實用的身份驗證 Practical authentication
談身份驗證是什麼及如何實作什麼是 Authentication
Authentication 是驗證或認證身份,最常見的就是帳號密碼登入,也可以透過憑證或是生物辨識來確認身份
與 Authorization 的差別
與 Authentication 不同,Authorization 是用來確認使用者是否擁有存取各個功能的權限
Authentication | Authorization |
你是誰? | 你可以做什麼? |
帳號密碼登入
不要幫使用者保存密碼
使用者嘗試註冊帳號,帳號密碼設定分別是jessica及123
這時候不應該在服務器上保存使用者的密碼,這是一件很危險的事情,一旦選擇幫使用者保存密碼後續就要增加很多工作來避免資料外洩或其他資安的問題,密碼保存在服務器上讓系統管理員能夠看見(不管有沒有加密)不是一件好事情,最理想的方案是讓使用者自己記住密碼(私鑰),服務器永遠不替使用者保存密碼
編碼及加密
- MTIz這是 123
- 30c20a0410bccb6c846c23ce4e26bf13ad3a7dd0b4fdc49f6f81d11b26885ac5這也是 123
如果只是將密碼用特定的編碼方式保存起來對提升安全性沒有任何幫助的,前面的MTIz可以透過 base64 解碼得到答案為 123,後面的30c20a......多了非對稱密碼學的處理必須要有 salt (public key) 及 password (private key) 才能知道答案
在密碼上灑點鹽 (Salt)
我們可以在使用者註冊帳號時產生一組 public key 並將它保存在服務器內,這組專門用來驗證密碼的 public key 我們稱它為salt,它是一組在使用者註冊時隨機產生的文字,這邊用 JavaScript 處理做舉例
// salt.js
const salt = () => crypto.randomBytes(8).toString("base64");
return console.log(salt());
> node salt.js
YsIxk2QDHfo=
再將 salt 與註冊帳號設定的密碼做計算得到一組雜湊值 (hash),與 salt 一樣要保存在服務器內
// hash.js
const salt = "YsIxk2QDHfo=";
const hash = crypto.createHmac("sha256", "123").update(salt).digest("hex");
return console.log(hash())
> node hash.js
30c20a0410bccb6c846c23ce4e26bf13ad3a7dd0b4fdc49f6f81d11b26885ac5
之後每次登入我們會拿輸入的密碼與該使用者擁有的 salt 做計算看結果跟註冊帳號時保存的 hash 有沒有吻合,如果不一樣就是密碼輸入錯誤,除了使用者本人以外沒有人知道密碼 (private key) 是什麼
public key (salt) | private key (password) | hash |
YsIxk2QDHfo= | 123 | 30c20a0410bccb6c846c23ce4e26bf13ad3a7dd0b4fdc49f6f81d11b26885ac5 |
YsIxk2QDHfo= | 1234 | 3b4f722ef0094771ca3a62db7253800ff3d057c812eb7529064e3214f08ad905 |
鹽巴記得換新
在使用者註冊帳號或是更換密碼成功時 (牽涉到 private key 的變更),我們應該幫使用者更換一組新的 salt
記住使用者的登入狀態
Session
使用者成功登入帳號後服務器可以基於使用者的資料產生 session 並將它暫存起來,其中的 session ID 會回傳給客戶端 (通常會透過 Cookie 存到瀏覽器內),之後客戶端要發送請求給服務器時,服務器先檢索 session ID 存不存在來判斷登入狀態,如果 session ID 不存在或已失效回傳 401 狀態將客戶端重導至登入頁面中