读security-of-encrypt-or-hash-password-in-client-side

读security-of-encrypt-or-hash-password-in-client-side

原文

以下是摘录:

MFA 對於保護密碼沒什麼幫助。很簡單就可以假設出一種狀況是雖然攻擊者無法登入帳號,但密碼明文還是被偷走了。

如果https不安全:攻擊者若是可以繞過 HTTPS 拿到明文的 request,那在應用層將密碼加密,確實會比較安全,但要注意的是要達成這個前提非常困難,發生的機率極低。

如果https安全:有一個現實生活中會發生,而且也確實發生過的風險,那就是 logging。

在前端加裝一些 error tracking 的服務是很合理的事情,若是我們直接實作一個「只要伺服器回傳 5xx,就把 request 記錄起來」的機制,如果好巧不巧哪天登入的 API 出現這個狀況,你就可以在 log 裡面看到使用者的明文密碼。

後端也可能有類似的機制,碰到一些問題就把 request 整個寫到 log 檔去,方便以後查看以及 debug,一不小心密碼就可能被寫進去。

在這種狀況下,在 client 端先把密碼加密顯然是有好處的,那就是在這些錯誤處理的 log 中,被記錄下來的密碼會是密文,除非你有密鑰,否則你是不會知道使用者的密碼的。

如果是传hash值,那么服务器端也要再hash一下,这样服务器端hash泄露也不会有影响,可以保證:

  • HTTPS 因為各種原因失效時,攻擊者無法取得明文密碼
  • 在 Server 端,沒有任何人知道使用者的明文密碼
  • 明文密碼不會因為人為失誤被記錄到 log 中

確實有些大公司有做這個機制,但是非大多數,不過在銀行業似乎是主流

在前端先做 hash 或是加密,它確實是有優點的,不是多此一舉,也不是沒有意義,更不是讓系統變得更危險。

但這不代表每個系統都該實作這個機制,因為它帶來的效益或許沒有成本高,這個端看各個公司的考量。對大部分的公司來說,與其為了 HTTPS 失效這個極低的可能性去投入成本,不如把時間花在加強其他登入環節的安全性(例如說 2FA 啦,或是不同裝置登錄警告等等),帶來的效益會更高。


  • 無論如何,一定要先用 HTTPS
  • 可以的話,能用 Passkeys 當然是最好,少掉傳統密碼的一些問題
  • 如果你想要用很安全的方式驗證密碼,並且確保在 Server 端不會處理到明文密碼,請參考 SRP(Secure Remote Password)協定,或是留言裡面讀者 yoyo930021 提到的 OPAQUE
  • 若是上述都沒有資源做的話,那在前端先把密碼做加密或是 hash 後再傳送,確實能夠增加一點安全性,但同時還是會帶來額外成本
  • 如果你是銀行或需要較高的安全性,再來考慮要不要做這個,否則極大多數的狀況下,你不需要這個機制就夠安全了,資源投入在其他地方的效益會更大