[資安] 密碼的傳輸 & 儲存
[資安] 密碼的傳輸 & 儲存

[資安] 密碼的傳輸 & 儲存

關於密碼,很重要的觀念是「密碼不可以被明文傳輸,也不可以被明文儲存」。不可以明文傳輸是防止傳輸過程中被中間人擷取,不可以明文儲存則是避免當你的主機被駭時,或是有內部工程師心懷不軌時,密碼不會被直接看光光。


這篇文章會講到以下三個問題,是註冊&登入功能會遇到的問題,懶得看內文的人可以直接拉到最後結論:

  1. 密碼要怎麼安全的從前端傳送到後端 (註冊、登入)
  2. 密碼要怎麼儲存在資料庫 (註冊)
  3. 登入時如何驗證使用者的密碼正確 (登入)


密碼如何從前端傳送後端

HTTPS

這篇文章沒有要講 HTTPS 的原理,所以就簡單帶過。簡單來說 HTTPS 就是在原本不安全的、明文傳輸的、不驗證使用者身分的 HTTP上, 加上 SSL 這個加密協議 (實際上現在使用的技術是升級版的 TLS ,不過出於習慣大家還是會叫 SSL ),SSL 提供內容加密、身份認證、資料完整性校驗,因此在 HTTPS 上的資料傳輸其實已經是加密過的了。

有些人會說既然 HTTPS 已經把傳輸資料加密了,那密碼是否就可以直接明文傳輸? 這個沒有一定的答案,但我自己是覺得不手動做點加密心裡感覺怪怪的,而且 SSL 憑證在網路上有免費的也有付費的,我自己會直接用免費的,但就覺得是不是不夠安全,所以還是會再做下一步的不對稱加密。

順帶一提整個 HTTPS 的請求流程簡單來說就是在做不對稱加密,也是透過公鑰私鑰來做身分驗證,所以才會有人說幹嘛 HTTPS 做一次加密,你又自己做一次加密呢?對 HTTPS 流程有興趣的人可以去看看這篇文章的第一段。


對稱加密

好的,來到加密的步驟了,加密可以分為「對稱加密」和「非對稱加密」。

對稱加密就是指用同一把 key 做加密和解密的動作,那我們也知道所有前端的程式都是公開在網路上的,所以把 key 直接放在前端是不行的,如果是透過網路從後端傳送給前端,也一樣會有在傳輸過程中被中間人擷取的風險。常見的對稱加密演算法有 AES 和 DES。

image-20210829215220386


非對稱加密

相較於對稱加密是用同一把 key 在做加解密,非對稱加密則是有分公鑰和私鑰,透過公鑰加密的資料,只能透過對應的私鑰才可以解密。

在登入的流程中,大致上就是在登入前會先有一隻 API 是前端請求公鑰的,接著前端將密碼用公鑰加密,透過登入 API 將加密後的資料傳送到後端,後端接到資料後就可以透過私鑰解密了。常見的非對稱加密演算法有 RSA。

image-20210829215700136


請求 public key

image-20210829221107887

登入時帶的資料(例如帳號密碼)是加密後的資料

image-20210829221440134


把密碼儲存進資料庫中

編碼

首先是編碼,例如常見的 Base64,雖然經過編碼後對人類來說勉強算是亂碼,但其實看字尾的===就很容易猜到這是 Base64,接著丟到解碼網站就可以輕易得到密碼了喔。

就算改成用少見的編碼算法,對於駭客來說大概還是跟明文儲存沒什麼差別吧,所以不要用編碼來儲存密碼

image-20210829232044658


加密

跟前面講得一樣分為對稱加密和非對稱加密,對稱加密的話,你的 key 總是要存在某個地方,不是資料庫就是網站後端,對於能看到資料庫的駭客或內部工程師來說,其實拿到 key 也不會有什麼困難。

那非對稱加密呢?先想想你的每個經過公鑰加密的密碼,都有一個對應的私鑰,既然是對應的私鑰,那當然只能和加密後的密碼一起存在資料庫阿,那這樣又有什麼意義呢?所以加密也不行


Hash 雜湊

雜湊是不可逆的,因此若資料庫儲存的是密碼的雜湊值,那即使資料庫被駭了也沒辦法回推原本的密碼,而要驗證使用者輸入的密碼則只要把輸入的密碼再進行一次雜湊,看看得到的雜湊值是否和資料庫內儲存的相同,就可判斷密碼是否正確了。

但要注意的是,雜湊函數是有機率碰撞的,因此可能不同的密碼卻得到同樣的雜湊值,因此碰撞機率也是挑選雜湊函數的重要考慮因素。


雜湊函數的選擇

所以到底要怎麼挑選雜湊函數呢,有三個方向可以考慮

  • 安全性 ( md-5, sha-1 已被破解 )
  • 碰撞機率 (基本上你聽過的、大家常用的都不容易碰撞,但還是有小機率會發生,不過你自己寫的可能是大機率碰撞 )
  • 運算速度 ( 選運算慢的可避免被彩虹表反推 )


彩虹表

指把所有文字的排列組合丟進 hash function 並算出結果,並儲存而成的一張表,用於將 hash 值反推原始字串。例如網路上隨便找都能找到 md-5和 sha-1 的對照表網站,把 hash 值丟進去馬上查給你原始字串。

若 hash function 計算速度很快,彩虹表就越容易被產出,因此選擇計算較慢的 function 可避免被輕易用彩虹表反推。


加鹽雜湊

除了選一個好的 hash function 以外,我們還能加鹽。

加鹽是指將密碼加上一串複雜特殊符號例如h7.@-]%<#L,變成HiLisa.h7.@-]%<#L後再丟進去雜湊函數,因為原文夠長也夠亂,所以不容易被網路上的表暴力破解。


推薦雜湊函數

  • bcrypt ( 運算慢,也是目前流行的雜湊算法 )
  • Argon2 ( 熱心人士補充,好像比 bcrypt 更新也更好 )


總結

  • 傳輸密碼:用 HTTPS + 非對稱加密 (e.g. RSA)
  • 儲存密碼:儲存密碼的雜湊值 (e.g. bcrypt, Argon2)
  • 驗證密碼:把輸入密碼雜湊後,和資料庫中的值比對,相同即表示極大機率是正確密碼


參考資料

程式設計師必備基礎:如何安全傳輸儲存使用者密碼?

聽說不能用明文存密碼,那到底該怎麼存?

[資訊安全] 密碼存明碼,怎麼不直接去裸奔算了?淺談 Hash , 用雜湊保護密碼