iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0

我們需要一個可靠的演算法對資料加密,就算駭客拿到資料也不知道內容,或者,就算駭客修改了資料內容傳到接收端後,也能夠被接受端發現資料已經遭到竄改。

或者,一般的應用中只要服務牽涉到會員登入的服務,可能就會遇到幾個問題:「如何處理使用者密碼?如何正確保存使用者的資料?」

最直覺的做法當然是直接把它存在資料庫。並且假設資料庫是安全的。

但很快會發現幾個問題:

  1. 管理者可以看到使用者的明文密碼,如果是有心人士,他們或許可以把你的密碼拿去其他網站試試看,這樣你的個資就全部洩露了
  2. 萬一不小心被駭客入侵,會員資料會全部都會被洩漏。

當然,對於使用者來說,他們並不會知道資料庫是否有將密碼加密,但是身為一個專業的工程師,如果對於資料的保存不夠謹慎,一旦曝光只會讓自己陷入苦境。

密碼學主要分類

根據用途不同,主要可以分為:

  • 編碼:編碼其實不算加密,只是將資料編碼方便計算、或是在網路上傳遞。實際使用時很常看到,再加上對不懂原理的人來說看起來就像亂碼,所以特別提出來
  • Hash (單向雜湊):將長度不固定的資料映射為固定長度的字串,如 MD5, SHA。
  • 對稱性密碼系統:加密與解密時使用相同的密鑰。常見的演算法有 AES
  • 非對稱密碼系統:除了自己擁有密鑰(私鑰)之外,還有一組公鑰。經過公鑰加密的資料只有私鑰能夠解密、而用私鑰加密過後的資料只能用公鑰解密。著名的非對稱密碼 RSA 演算法

編碼

為了讓資料可以在網路間傳送,需要一種方式能夠對資料、字元做編碼,封包可能經由多個路由器傳送,而每個路由器的編碼設定可能不同,因此需要透過編碼讓資料能夠在網路間傳遞。

編碼並不算加密,因為加密需要鑰匙,而且需要持有鑰匙的人才能解密;但編碼只要按照規範的演算法執行就可以知道原始訊息是什麼。

ASCII

早期的編碼是在美國發明使用,因此只需要將字元透過編碼轉為 2 進制的數字。通常用 1byte(8 bits) 來表示一個字元,因此 ASCII 除了 26 個大小寫英文外、數字,還包含常見的控制字元與標點符號,也就是常常在計概課出現的考題,像是 32 = 空白,65 = A 等等,總共定義了 128 個符號。

不過缺點顯而易見,因為只能傳送特定的字元,因此像是其它國家的語言,甚至像是漢字這種需要 2byte 表示的字元就沒辦法處理。所以目前通常使用 Unicode 來表示字元。其中最著名的實作為 UTF-8。

Base64

Base64 是一種透過可表示的字元來表示二進制資料的編碼方式。詳細的編碼方式可以參考維基百科。例如在網頁中最常見的,透過將小圖片編碼為 base64 的方式來減少請求數。

從實作中可以發現,base64 會比原始資料多 4/3 左右。這種編碼方式沒辦法加密資料,也沒辦法壓縮資料。

這可以當作判斷工程師的指標之一,如果他跟你說用 base64 可以用來加密與壓縮資料,那麼以後不要相信他說的話。

單向雜湊One way Hash —

什麼是雜湊? 將資料經過設計好的 hash function,放入一個固定長度的 table 當中。Hash 其實也不算加密,因為良好的雜湊函數並不可逆,也沒有跟某個 key 進行運算的動作。

一個簡單的例子是透過 mod 運算,例如下面的範例:

const mypassword = '1234';
const myHashFn = (password) => password % 100

這個簡單的 hash function 顯然有許多問題。

  1. 任何末二位數字是 34 的密碼,hash 值都一樣
  2. hash 值只有 0 ~ 99
  3. 可以從 hash function 推敲原始密碼。只要是 34 結尾都有可能是密碼

因此對於 Hash 來說,為了保持不可逆性,我們希望良好的 hash function 有幾個特性:

  • 不可逆:不能從雜湊值中推出原始的密碼是什麼
  • 不一樣的值雜湊後不應該相同
  • 設計一個不容易產生碰撞的 hash function,是實作單向雜湊的重點。

因此在現代的資料庫系統中,密碼通常是用 hash 過後的值保存。如果有任何教學直接將明碼存進資料庫,而且還沒有警告你這很不安全的話,不要再繼續往下看了。

一個完整的雜湊函式並不容易設計,目前著名的雜湊函式有 MD5, SHA1, SHA2,目前 MD5, SHA1 都已經被破解。

此外,還有一個問題要解決。雖然 hash 值不可逆,但駭客能夠預先生成常見明文與 hash 的對照表(又叫做彩虹表),如果找到 hash 能夠對應的明文就能夠破解密碼。

因此,比較好的做法是雜湊時加上一組亂數(通常被稱作 salt)一起加密。讓駭客沒辦法輕易透過預先生成的雜湊表來查詢明文。

小結

  • 良好的 hash function 在於它容不容易產生碰撞。(理論上所有 hash function 都會產生碰撞)
  • 目前 MD5, SHA1 都已經被淘汰,請使用比較安全的 SHA256, SHA512
  • 加入亂數 salt 來減少被明文完全洩漏的問題

更安全的雜湊:bcrypt

一般的 hash function 都被設計成在安全的情況下盡可能地加快計算時間,但如果你在實作密碼雜湊,更好的選擇可能是 bcrypt 或其他專門為雜湊密碼而設計的 hash function。 除了他的實作上讓密碼更安全之外(演算法本身已經幫你處理掉隨機 salt 的問題),且能夠透過 cost 函數提升複雜度。許多程式語言也已經實作相關的 library。

對稱式加密 — AES

對稱式加密需要雙方都持有同樣的 Key 才能夠加密、解密。目前最流行的演算法為 AES。主要是利用 XOR 的特性達成。

主要的運作原理是將明文拆成固定大小的區塊後分別進行加、解密,常見的工作模式有幾種

非對稱式加密 — RSA

RSA 是個數學味道濃厚且相當重要的加密演算法。他的破解困難度是建立在對一個合數分解為兩個大質數的困難性。因為因式分解兩個大質數的乘積相當困難(證明稍嫌複雜,需要有質因數分解、質數與同餘等概念)

所謂的非對稱式加密,是指加密與解密時可以使用不同的鑰匙(key)。這樣一來可以將公鑰給發送訊息端,而私鑰則持有在自己身上,並且透過私鑰來解密。這樣可以保證只有自己才能夠解密訊息。

2009 年 12 月 12 日,RSA-768(768 bits, 232 digits)也被成功分解了,目前比較安全的 key 長度為 RSA-1024 或 RSA-2048。

不過儘管非對稱式加密已經相當普遍,使用對稱式加密的好處在於效率。因為隨機找出兩個大質數需要耗費比較久的時間。

JWT(JSON Web Tokens)

JWT 透過輕巧的規範方便傳遞訊息,其實並不算密碼學的一部份,而是一種標準。最近因為 SPA 流行的原因,需要大量的前後端互動,許多驗證方式都開始使用 JWT,在這邊做介紹。

JWT 透過一個 header 與 payload(需要傳遞的資料)做 base64 編碼後再透過(HMAC 或 RSA)來加密產生簽名。

優點在於透過這樣的 token,能夠包含以下資訊

  • header
  • payload
  • sign

這樣 token 被知道不就洩漏訊息了嗎?沒錯,只要將 header 與 payload 透過 base64 解碼就知道原始資料是什麼,但 token 本來就不該到處公開給別人使用才對,也因此 JWT 中不應該放入敏感資訊,例如使用者密碼。

至於要如何避免資料被竄改的可能?例如攻擊者把 payload 修改後再送出。這時伺服器端會檢查訊息跟加密後的字串是否與簽名相同。如果不同代表已經被竄改,而不知道 secret key 的情況下也就沒有辦法知道如何製作正確的簽名。

更詳細的介紹可以到 jwt.io 官方網站尋找更多資訊與實作。

小結

  • web service 做 authentication 時可以透過 JWT 當作 token 使用
  • 不要把密碼或任何敏感資料放入 JWT 傳送

結論

  • 編碼、Hash 並不是加密
  • 不要用 JWT 傳送敏感資料
  • 使用穩定的 library,盡量不要自幹加密演算法。一個穩固、安全的演算法是數學家嘔心瀝血的結晶,並不是三天兩頭就能生出來的。不過這並不代表不能夠探究密碼學中的原理。

密碼學對開發來說,看起來可能微不足道,在多數的情況下我們也不需要自己實作加密演算法。但如果不了解這些演算法的原理,我們很有可能挑選一個有破綻的加密演算法、將密碼暴露在極度危險的環境中。

另外就算是前端,在日常工作中,或許也有機會接觸到加密相關的需求。例如在前端加密後再送出(當然還是要在伺服器端再加密),或者私人訊息加密後再傳到 Server 端。

資安並不是一個碰到再說的 buzzword,而是一位具有專業素養的工程師都應該具備的基本常識。因此整理了密碼學的相關知識與資料。


上一篇
[Day27] Raspberry Pi pico 初探
下一篇
[Day29] CoreNFC 讀取 SUICA 資訊(FeliCa)
系列文
從電子元件到傅立葉轉換 - 那些我有興趣的主題30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言