學習目標:了解什麼是加密(Encryption)、什麼是雜湊(Hash function)以及兩個的差別。
現有的網站在處理忘記密碼的功能時,通常會寄一封信到信箱,請使用者重新設定密碼,為什麼他們不直接把密碼寄給使用者就好了呢?
因為其實網站主也不知道使用者的密碼是什麼,密碼在資料庫中是不會以明文儲存,原因在於假設很不幸的資料庫被入侵,最重要的密碼也不會拿走或輕易的被猜出來。
不以明碼儲存的方式基本上有兩種:加密(Encryption)、雜湊(Hash function),以下說明兩者的基本原理
第一種方式:加密(Encryption)
- 將明文資訊改變為難以讀取的密文,可透過「解密」還原出內容。
- 加密跟解密都必須要透過金鑰(key)才能進行。
- 為一對一之對應關係。
- 缺點:只要知道金鑰(key),就可以還原出明文。
- 又可以分為:對稱式、非對稱式兩種。
對稱式
- 常見的加密演算法:DES, 3DES, AES
- 也稱為秘密金鑰加密、發送者與接收者持有「相同的」金鑰來加解密訊息。
- 只要傳遞金鑰的過程中(發送 request、response 中)被竊取資訊,再強的加密演算法都沒有用,因此產生出另一種安全性更高,應用範圍更廣的非對稱是加密。
非對稱式
- 常見演算法: RSA, DSA, ECC
- 每個使用者都擁有一對金鑰:一把公鑰用來加密訊息,一把私鑰用來解密。
- 訊息由其中一把金鑰加密後,必需由另一把金鑰予以解密
小明擁有兩把鑰匙跟箱子,這兩把鑰匙,一把只能上鎖(私鑰)而另一把只能開鎖(公鑰),小明將私鑰保留給自己,將公鑰打了好多把分給班上的同學,並告訴大家:「各位同學這個是一把只能上鎖的鑰匙,所以如果有人有話想跟我說,可以把信放在箱子中上鎖」
你可能會好奇小明幹嘛這麼做?沒有什麼原因單純好玩。
隔天小明用私鑰打開箱子,很驚喜的箱子裡面真的有信!
….
從舉例中可以發現,由於至始至終能開啟箱子的私鑰都在小明手上,所以只有小明可以打開箱子,也確保了裡面的內容只有小明可以看到
相對於「對稱式」,「非對稱式」安全性更高。
上述的情況是 …私鑰「解密」、公鑰「加密」
假設把情況反過來… 私鑰「加密」、公鑰「解密」
就變成另一種有趣的用法
班上的每一位同學都提供了自己的公鑰,但只有小明的公鑰,才能解鎖小明的箱子,因此你可以公鑰對應上私鑰,就可以證明這個箱子是來自於哪一個同學 — — — 實際運用:數位簽章
但加密回歸到最基本就是…
明文 ➡️ 加密(key)➡️ 變成密文
密文 ➡️ 解密(key)➡️ 變成明文
雜湊(Hash function)
- 把明文丟進一串公式後變成秘文
- 無論內容長短,透過雜湊演算法後都會輸出固定長度的值。
- 當不同的內容卻輸出一樣的值時,這個情況稱為「碰撞」,但好的雜湊演算法,產生碰撞的機率是很低的。
- 由於無法「逆向解出明文」,因此安全性相較於加密更高,也是跟加密最大的區別。
- 常見演算法:SHA 系列、BLAKE2
PHP 內建雜湊函式
(PHP 5 >= 5.5.0, PHP 7)
password_hash()
- 可以簡單實踐複雜的秘文
- 語法:
password_hash('password', PASSWORD_DEFAULT)
第一個參數:原始 password
第二個參數:演算法,建議可以直接使用 PASSWORD_DEFAULT,每次處理時,都會在背後產生隨機的SALT。 - 舉例:將經過處理的密碼存在變數中
$password = password_hash($_POST[‘password’], PASSWORD_DEFAULT);
password_verify()
- 將經過
password_hash()
處理的密碼,進行驗證,白話就是檢查輸入密碼對不對,用於登入功能 - 語法:
password_verify('使用者輸入的密碼','資料庫裡的密碼')
根據回傳 boolean 值,進行操作 - 舉例:檢查輸入的密碼是否是否存在相對應的資料中,如果有就登入導回首頁,否則導回登入頁
$password = '123456' // 原始密碼if(password_verify($password, $row['password'])) { $_SESSION['username'] = $username;} else { header('Location: login.php?error=2'); die();}header('Location: index.php');
以上有任何錯誤的地方歡迎指正,感謝。