一文搞懂Web中暗藏的密碼學(xué)
前言
開發(fā)網(wǎng)站登錄功能時,如何保證密碼在傳輸過程/儲存的安全?
相信不少前后端的朋友,在面試時都會被問到類似的問題。
在我對密碼學(xué)一無所知時,也僅會回答:“MD5加密啊。”
諸不知,密碼學(xué)在網(wǎng)絡(luò)七層模型,甚至web開發(fā)中的應(yīng)用比我想象得多得多。
1. 什么是密碼學(xué)?
密碼學(xué)是各種安全應(yīng)用程序所必需的,現(xiàn)代密碼學(xué)旨在創(chuàng)建通過應(yīng)用數(shù)學(xué)原理和計算機科學(xué)來保護信息的機制。但相比之下,密碼分析旨在解密此類機制,以便獲得對信息的非法訪問。
密碼學(xué)具有三個關(guān)鍵屬性:
- 機密性,為了防止未經(jīng)授權(quán)的各方訪問信息(換句話說,是要確保只有經(jīng)過授權(quán)的人才能訪問受限制的數(shù)據(jù))。
- 完整性,是指保護信息不被隨意篡改
- 真實性,與識別信息的所有者有關(guān)。
例如個人醫(yī)療數(shù)據(jù):
- 機密性,個人醫(yī)療數(shù)據(jù)需要保密,這意味著只有醫(yī)生或醫(yī)護人員才能訪問它。
- 完整性,還必須保護其完整性,因為篡改此類數(shù)據(jù)可能導(dǎo)致錯誤的診斷或治療,并給患者帶來健康風(fēng)險。
- 真實性,患者數(shù)據(jù)應(yīng)與已識別的個人聯(lián)系起來,且患者需要知道操作者(醫(yī)生)是誰。
在本文中,我們將從加密,哈希,編碼和混淆四種密碼學(xué)基礎(chǔ)技術(shù)來入門。
2. 什么是加密?
加密定義:以保證機密性的方式轉(zhuǎn)換數(shù)據(jù)的過程。
為此,加密需要使用一個保密工具,就密碼學(xué)而言,我們稱其為“密鑰”。
加密密鑰和任何其他加密密鑰應(yīng)具有一些屬性:
- 為了保護機密性,密鑰的值應(yīng)難以猜測。
- 應(yīng)該在單個上下文中使用它,避免在不同上下文中重復(fù)使用(類比 JS 作用域)。密鑰重用會帶來安全風(fēng)險,如果規(guī)避了其機密性,則影響更大,因為它“解鎖”了更敏感的數(shù)據(jù)。
2.1 加密的分類:對稱和非對稱
加密分為兩類:對稱和非對稱
對稱加密:
用途:文件系統(tǒng)加密,Wi-Fi 保護訪問(WPA),數(shù)據(jù)庫加密(例如信用卡詳細(xì)信息)
非對稱加密:
用途:TLS,VPN,SSH。
其主要區(qū)別是:所需的密鑰數(shù)量:
- 在對稱加密算法中,單個密用于加密和解密數(shù)據(jù)。只有那些有權(quán)訪問數(shù)據(jù)的人才能擁有單個共享密鑰。
- 在非對稱加密算法中,使用了兩個密鑰:一個是公用密鑰,一個是私有密鑰。顧名思義,私鑰必須保密,而每個人都可以知道公鑰。
- 應(yīng)用加密時,將使用公鑰,而解密則需要私鑰。
- 任何人都應(yīng)該能夠向我們發(fā)送加密數(shù)據(jù),但是只有我們才能夠解密和讀取它。
- 通常使用非對稱加密來在不安全的通道上進行通信時,兩方之間會安全地建立公共密鑰。
- 通過此共享密鑰,雙方切換到對稱加密。
- 這種加密速度更快,更適合處理大量數(shù)據(jù)。
能被密碼界承認(rèn)的加密算法都是公開的:
- 某些公司使用專有或“軍事級”加密技術(shù)進行加密,這些技術(shù)是“私有的”。且基于“復(fù)雜“算法,但這不是加密的工作方式。
- 密碼界廣泛使用和認(rèn)可的所有加密算法都是公開的,因為它們基于數(shù)學(xué)算法,只有擁有密鑰或先進的計算能力才能解決。
- 公開算法是得到廣泛采用,證明了其價值的。
3. 什么是哈希?
哈希算法定義:·一種只能加密,不能解密的密碼學(xué)算法,可以將任意長度的信息轉(zhuǎn)換成一段固定長度的字符串。
加密算法是可逆的(使用密鑰),并且可以提供機密性(某些較新的加密算法也可以提供真實性),而哈希算法是不可逆的,并且可以提供完整性,以證明未修改特定數(shù)據(jù)。
哈希算法的前提很簡單:給定任意長度的輸入,輸出特定長度的字節(jié)。在大多數(shù)情況下,此字節(jié)序列對于該輸入將是唯一的,并且不會給出輸入是什么的指示。換一種說法:
- 僅憑哈希算法的輸出,是無法確定原始數(shù)據(jù)的。
- 取一些任意數(shù)據(jù)以及使用哈希算法輸出,就可以驗證此數(shù)據(jù)是否與原始輸入數(shù)據(jù)匹配,從而無需查看原始數(shù)據(jù)。
為了說明這一點,請想象一個強大的哈希算法通過將每個唯一輸入放在其自己的存儲桶中而起作用。當(dāng)我們要檢查兩個輸入是否相同時,我們可以簡單地檢查它們是否在同一存儲桶中。
散列文件的存儲單位稱為桶(Bucket)
3.1 例子一:資源下載
提供文件下載的網(wǎng)站通常會返回每個文件的哈希值,以便用戶可以驗證其下載副本的完整性。
例如,在Debian的圖像下載服務(wù)中,您會找到其他文件,例如SHA256SUMS,其中包含可供下載的每個文件的哈希輸出(在本例中為SHA-256算法)。
- 下載文件后,可以將其傳遞給選定的哈希算法,輸出一段哈希值
- 用該哈希值來與校驗和文件中列出的哈希值作匹配,以校驗是否一致。
在終端中,可以用openssl來對文件進行哈希處理:
- $ openssl sha256 /Users/hiro/Downloads/非對稱.png
- SHA256(/Users/hiro/Downloads/非對稱.png)= 7c264efc9ea7d0431e7281286949ec4c558205f690c0df601ff98d59fc3f4f64
同一個文件采用相同的hash算法時,就可以用來校驗是否同源。
在強大的哈希算法中,如果有兩個不同的輸入,則幾乎不可能獲得相同的輸出。
而相反的,如果計算后的結(jié)果范圍有限,就會存在不同的數(shù)據(jù)經(jīng)過計算后得到的值相同,這就是哈希沖突。(兩個不同的數(shù)據(jù)計算后的結(jié)果一樣)
這種稱為:哈希碰撞(哈希沖突)。
如果兩個不同的輸入最終出現(xiàn)在同一個存儲桶中,則會發(fā)生沖突。如MD5和SHA-1,就會出現(xiàn)這種情況。這是有問題的,因為我們無法區(qū)分哪個碰撞的值匹配輸入。
強大的哈希算法幾乎會為每個唯一輸入創(chuàng)建一個新存儲桶。
3.2 例子二:網(wǎng)站登陸
在web開發(fā)中,哈希算法使用最頻繁的是在網(wǎng)站登陸應(yīng)用上:
絕大多數(shù)的網(wǎng)站,在將登陸數(shù)據(jù)存入時,都會將密碼哈希后存儲。
- 這是為了避免他人盜取數(shù)據(jù)庫信息后,還原出你的初始輸入。
- 且下次登錄時,Web 應(yīng)用程序?qū)⒃俅螌δ愕拿艽a進行哈希處理,并將此哈希與之前存儲的哈希進行比較。
- 如果哈希匹配,即使 Web 應(yīng)用程序中沒有實際的密碼存儲,Web 應(yīng)用程序也確信你知道密碼。
注冊:
登陸:
哈希算法的一個有趣的方面是:無論輸入數(shù)據(jù)的長度如何,散列的輸出始終是相同的長度。
從理論上講,碰撞沖突將始終在可能性的范圍之內(nèi),盡管可能性很小。
與之相反的是編碼。
4. 什么是編碼?
編碼定義:將數(shù)據(jù)從一種形式轉(zhuǎn)換為另一種形式的過程,與加密無關(guān)。
它不保證機密性,完整性和真實性這三種加密屬性,因為:
- 不涉及任何秘密且是完全可逆的。
- 通常會輸出與輸入值成比例的數(shù)據(jù)量,并且始終是該輸入的唯一值。
- 編碼方法被認(rèn)為是公共的,普遍用于數(shù)據(jù)處理。
- 編碼永遠不適用于操作安全性相關(guān)。
4.1 URL編碼
又叫百分號編碼,是統(tǒng)一資源定位(URL)編碼方式。URL地址(常說網(wǎng)址)規(guī)定了:
- 常用的數(shù)字,字母可以直接使用,另外一批作為特殊用戶字符也可以直接用(/,:@等)
- 剩下的其它所有字符必須通過%xx編碼處理。
現(xiàn)在已經(jīng)成為一種規(guī)范了,基本所有程序語言都有這種編碼,如:
- js:encodeURI、encodeURIComponent
- PHP:urlencode、urldecode 等。
編碼方法很簡單,在該字節(jié)ascii碼的 16 進制字符前面加%. 如 空格字符,ascii碼是 32,對應(yīng) 16 進制是'20',那么urlencode編碼結(jié)果是:%20。
- # 源文本:
- The quick brown fox jumps over the lazy dog
- # 編碼后:
- #!shell
- %54%68%65%20%71%75%69%63%6b%20%62%72%6f%77%6e%20%66%6f%78%20%6a%75%6d%70%73%20%6f%76%65%72%20%74%68%65%20%6c%61%7a%79%20%64%6f%67
4.2 HTML實體編碼
在HTML中,需要對數(shù)據(jù)進行HTML編碼以遵守所需的HTML字符格式。轉(zhuǎn)義避免 XSS 攻擊也是如此。
4.3 Base64/32/16編碼
base64、base32、base16可以分別編碼轉(zhuǎn)化 8 位字節(jié)為 6 位、5 位、4 位。
16,32,64 分別表示用多少個字符來編碼,
Base64常用于在通常處理文本數(shù)據(jù)的場合,表示、傳輸、存儲一些二進制數(shù)據(jù)。包括MIME的email,email via MIME,在XML中存儲復(fù)雜數(shù)據(jù)。
編碼原理:
Base64編碼要求把 3 個 8 位字節(jié)轉(zhuǎn)化為 4 個 6 位的字節(jié)
之后在 6 位的前面補兩個 0,形成 8 位一個字節(jié)的形式
6 位 2 進制能表示的最大數(shù)是 2 的 6 次方是 64,這也是為什么是 64 個字符的原因
A-Z,a-z,0-9,+,/這 64 個編碼字符,=號不屬于編碼字符,而是填充字符
Base64映射表,如下:
舉個栗子:
- 第一步:“M”、“a”、"n"對應(yīng)的ASCII碼值分別為 77,97,110,對應(yīng)的二進制值是01001101、01100001、01101110。如圖第二三行所示,由此組成一個 24 位的二進制字符串。
- 第二步:如圖紅色框,將 24 位每 6 位二進制位一組分成四組。
- 第三步:在上面每一組前面補兩個 0,擴展成 32 個二進制位,此時變?yōu)樗膫€字節(jié):00010011、00010110、00000101、00101110。分別對應(yīng)的值(Base64編碼索引)為:19、22、5、46。
- 第四步:用上面的值在 Base64 編碼表中進行查找,分別對應(yīng):T、W、F、u。因此“Man”Base64編碼之后就變?yōu)椋篢WFu。
上面的示例旨在指出,編碼的用例僅是數(shù)據(jù)處理,而不為編碼的數(shù)據(jù)提供保護。
4. 什么是混淆?
混淆定義:將人類可讀的字符串轉(zhuǎn)換為難以理解的字符串。
- 與加密相反,混淆處理不包含加密密鑰。
- 與編碼類似,混淆不能保證任何安全性,盡管有時會誤將其用作加密方法
盡管不能保證機密性,但混淆仍有其它應(yīng)用:
- 用于防止篡改和保護知識產(chǎn)權(quán)。
- APP 源代碼通常在打包之前就被混淆了
- 因為源代碼位于用戶的設(shè)備中,可以從中提取代碼。由于混淆后代碼不友好,因此會阻止逆向工程,從而有助于保護知識產(chǎn)權(quán)。
- 反過來,這可以防止篡改代碼并將其重新分發(fā)以供惡意使用。
但是,如此存在許多有助于消除應(yīng)用程序代碼混淆的工具。那就是其它話題了。。。
4.1 例子一:JavaScript混淆
JavaScript源代碼:
- function hello(name) {
- console.log('Hello, ' + name);
- }
- hello('New user');
混淆后:
- var _0xa1cc=["\x48\x65\x6C\x6C\x6F\x2C\x20","\x6C\x6F\x67","\x4E\x65\x77\x20\x75\x73\x65\x72"];
- function hello(_0x2cc8x2){console[_0xa1cc[1]](_0xa1cc[0]+ _0x2cc8x2 "_0xa1cc[1]")}hello(_0xa1cc[2])
總結(jié)
從機密性,完整性,真實性分析四種密碼技術(shù):
- 加密,雖然是為了保證數(shù)據(jù)的機密性,但某些現(xiàn)代加密算法還采用了其他策略來保證數(shù)據(jù)的完整性(有時通過嵌入式哈希算法)和真實性。
- 哈希,只能保證完整性,但可以通過完整性對比來做權(quán)限控制,如:基于哈希的消息認(rèn)證碼(HMAC)和某些傳輸層安全性(TLS)方法。
- 編碼,過去曾被用來表示加密,并在技術(shù)領(lǐng)域之外仍具有這種含義,但在編程世界中,它僅是一種數(shù)據(jù)處理機制,從未提供任何安全措施。
- 混淆,可以用來提高抵御攻擊的能力;但是,它永遠不能保證數(shù)據(jù)的機密性。狡猾的對手最終將繞過混淆策略。與編碼一樣,永遠不要將混淆視為可靠的安全控制。
附錄:哈希函數(shù)常用的哈希函數(shù):
- MD5,一種被廣泛使用的密碼雜湊函數(shù),可以產(chǎn)生出一個 128 位元(16 位元組)的哈希值,用于確保信息傳輸完整一致。*雖廣泛,但過時。
- SHA-256/SHA512 , "加鹽"。在比特幣中,區(qū)塊鏈?zhǔn)褂肧HA-256算法作為基礎(chǔ)的加密哈希函數(shù)。
- 安全散列算法secure hash algorithm,是一個密碼哈希函數(shù)家族。
- SHA家族有五個算法,分別是SHA-1,SHA-224,SHA-256,SHA-384,SHA-512
- 它們是美國的政府標(biāo)準(zhǔn),后面的四個稱之為SHA-2
- bcrypt:bcrypt算法相對來說是運算比較慢的算法。
在密碼學(xué)界有句常話:越慢的算法越安全。算法越算,黑客破解成本越高:
通過salt和const這兩個值來減緩加密過程,ta 的加密時間(百 ms 級)遠遠超過md5(大概1ms左右)。
對于計算機來說,Bcrypt 的計算速度很慢,但是對于用戶來說,這個過程不算慢。
bcrypt是單向的,而且經(jīng)過salt和cost的處理,使其受rainbow攻擊破解的概率大大降低,同時破解的難度也提升不少。
相對于MD5等加密方式更加安全,而且使用也比較簡單.
- 設(shè)計良好的密鑰擴展算法,如PBKDF2,bcrypt,scrypt。
后記 & 引用
- How Secure Are Encryption, Hashing, Encoding and Obfuscation?[3]
- CTF 中那些腦洞大開的編碼和加密[4]
- 散列文件的存儲——‘桶’[5]
那么,如何保證密碼在傳輸過程/儲存的安全呢?
參考資料
How Secure Are Encryption, Hashing, Encoding and Obfuscation?: https://auth0.com/blog/how-secure-are-encryption-hashing-encoding-and-obfuscation/#What-is-Encoding-
引自:一篇文章徹底弄懂Base64編碼原理: https://blog.csdn.net/wo541075754/article/details/81734770
How Secure Are Encryption, Hashing, Encoding and Obfuscation?: https://auth0.com/blog/how-secure-are-encryption-hashing-encoding-and-obfuscation/#What-is-Encoding-
CTF中那些腦洞大開的編碼和加密: https://www.cnblogs.com/godoforange/articles/10850493.html
散列文件的存儲——‘桶’: https://blog.csdn.net/Dearye_1/article/details/78492021