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