溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

數(shù)字指紋作用有哪些

發(fā)布時間:2021-10-20 10:24:47 來源:億速云 閱讀:184 作者:iii 欄目:web開發(fā)

本篇內(nèi)容介紹了“數(shù)字指紋作用有哪些”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

在大文件上傳的場景中,為了提高大文件上傳的用戶體驗,我們會支持斷點續(xù)傳。在上傳過程中,我們會對大文件進行分片處理,然后使用 md5  算法計算分片的哈希值,再把該分片的內(nèi)容和其對應(yīng)的哈希值一起提交到服務(wù)器。

當(dāng)服務(wù)器接收到分片對應(yīng)的哈希值時,會先查詢該哈希值是否已經(jīng)存在。如果存在,則表示該分片已經(jīng)上傳過。這時可以返回大文件已上傳的字節(jié)數(shù),從而讓客戶端可以繼續(xù)上傳剩余的內(nèi)容。

其實分片對應(yīng)的哈希值也可以被稱為分片的 “數(shù)字指紋”,那么什么是 “數(shù)字指紋” 呢?要理解 “數(shù)字指紋”,我們需要先來了解一下什么是消息摘要算法。

一、什么是消息摘要算法

消息摘要算法是密碼學(xué)算法中非常重要的一個分支,它通過對所有數(shù)據(jù)提取指紋信息以實現(xiàn)數(shù)據(jù)簽名、數(shù)據(jù)完整性校驗等功能,由于其不可逆性,有時候會被用做敏感信息的加密。消息摘要算法也被稱為哈希(Hash)算法或散列算法。

任何消息經(jīng)過散列函數(shù)處理后,都會獲得唯一的散列值,這一過程稱為 “消息摘要”,其散列值稱為 “數(shù)字指紋”,其算法自然就是 “消息摘要算法”  了。換句話說,如果其數(shù)字指紋一致,就說明其消息是一致的。

數(shù)字指紋作用有哪些

(圖片來源 —— https://zh.wikipedia.org/wiki/散列函數(shù))

消息摘要算法不存在密鑰的管理與分發(fā)問題,適合于分布式網(wǎng)絡(luò)上使用。消息摘要算法主要應(yīng)用在 “數(shù)字簽名” 領(lǐng)域,作為對明文的摘要算法。著名的摘要算法有 RSA  公司的 MD5 算法和 SHA-1 算法及其大量的變體。

1.1 消息摘要算法的特點

  • 無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的。例如應(yīng)用 MD5 算法摘要的消息有 128 個比特位,用 SHA-1 算法摘要的消息最終有  160 個比特位的輸出,SHA-1的變體可以產(chǎn)生 192 個比特位和 256 個比特位的消息摘要。一般認為,摘要的最終輸出越長,該摘要算法就越安全。

  • 消息摘要看起來是  “隨機的”。這些比特看上去是胡亂的雜湊在一起的,可以用大量的輸入來檢驗其輸出是否相同,一般,不同的輸入會有不同的輸出,而且輸出的摘要消息可以通過隨機性檢驗。一般地,只要輸入的消息不同,對其進行摘要以后產(chǎn)生的摘要消息也必不相同;但相同的輸入必會產(chǎn)生相同的輸出。

  • 消息摘要函數(shù)是單向函數(shù),即只能進行正向的信息摘要,而無法從摘要中恢復(fù)出任何的消息,甚至根本就找不到任何與原信息相關(guān)的信息。

  • 好的摘要算法,沒有人能從中找到 “碰撞” 或者說極度難找到,雖然 “碰撞” 是肯定存在的(碰撞即不同的內(nèi)容產(chǎn)生相同的摘要)。

1.2 消息摘要算法的家譜

消息摘要算法主要分為三大類:MD(Message Digest,消息摘要算法)、SHA-1(Secure Hash Algorithm,安全散列算法)和  MAC(Message Authentication Code,消息認證碼算法)。

MD 系列算法包括 MD2、MD4 和 MD5 共 3 種算法;SHA 算法主要包括其代表算法 SHA-1 和 SHA-1 算法的變種 SHA-2  系列算法(包含 SHA-224、SHA-256、SHA-384 和 SHA-512);MAC 算法綜合了上述兩種算法,主要包括  HmacMD5、HmacSHA1、HmacSHA256、HmacSHA384 和 HmacSHA512 算法。

盡管上述內(nèi)容列舉了各種消息摘要算法,但仍不能滿足應(yīng)用需要?;谶@些消息摘要算法,又衍生出了 RipeMD 系列(包含  RipeMD128、RipeMD160、RipeMD256、RipeMD320)、Tiger、GOST3411 和 Whirlpool 算法。

對于大多數(shù)前端開發(fā)者來說,接觸得比較多的應(yīng)該是 MD5 算法。所以,接下來阿寶哥將重點介紹 MD5 算法。

二、什么是 MD5 算法

MD5(Message Digest Algorithm 5,消息摘要算法版本5),它由 MD2、MD3、MD4 發(fā)展而來,由 Ron  Rivest(RSA 公司)在 1992 年提出,目前被廣泛應(yīng)用于數(shù)據(jù)完整性校驗、數(shù)據(jù)(消息)摘要、數(shù)據(jù)簽名等。MD2、MD4、MD5 都產(chǎn)生 16  字節(jié)(128 位)的校驗值,一般用 32 位十六進制數(shù)表示。MD2 的算法較慢但相對安全,MD4 速度很快,但安全性下降,MD5 比 MD4  更安全、速度更快。

隨著計算機技術(shù)的發(fā)展和計算水平的不斷提高,MD5 算法暴露出來的漏洞也越來越多。1996  年后被證實存在弱點,可以被加以破解,對于需要高度安全性的數(shù)據(jù),專家一般建議改用其他算法,如 SHA-2。2004 年,證實 MD5  算法無法防止碰撞(collision),因此不適用于安全性認證,如 SSL 公開密鑰認證或是數(shù)字簽名等用途。

2.1 MD5 特點

  • 穩(wěn)定、運算速度快。

  • 壓縮性:輸入任意長度的數(shù)據(jù),輸出長度固定(128 比特位)。

  • 運算不可逆:已知運算結(jié)果的情況下,無法通過通過逆運算得到原始字符串。

  • 高度離散:輸入的微小變化,可導(dǎo)致運算結(jié)果差異巨大。

2.2 MD5 散列

128 位的 MD5 散列在大多數(shù)情況下會被表示為 32 位十六進制數(shù)字。以下是一個 43 位長的僅 ASCII 字母列的 MD5 散列:

MD5("The quick brown fox jumps over the lazy dog") = 9e107d9d372bb6826bd81d3542a419d6

即使在原文中作一個小變化(比如把 dog 改為 cog,只改變一個字符)其散列也會發(fā)生巨大的變化:

MD5("The quick brown fox jumps over the lazy cog") = 1055d3e698d289f2af8663725127bd4b

接著我們再來舉幾個 MD5 散列的例子:

MD5("") -> d41d8cd98f00b204e9800998ecf8427e  MD5("semlinker") -> 688881f1c8aa6ffd3fcec471e0391e4d MD5("kakuqo") -> e18c3c4dd05aef020946e6afbf9e04ef

三、MD5 算法的用途

3.1 防止被篡改

3.1.1 文件分發(fā)防篡改

在互聯(lián)網(wǎng)上分發(fā)軟件安裝包時,出于安全性考慮,為了防止軟件被篡改,比如在軟件安裝程序中添加木馬程序。軟件開發(fā)者通常會使用消息摘要算法,比如 MD5  算法產(chǎn)生一個與文件匹配的數(shù)字指紋,這樣接收者在接收到文件后,就可以利用一些現(xiàn)成的工具來檢查文件完整性。

數(shù)字指紋作用有哪些

(圖片來源 —— https://en.wikipedia.org/wiki/MD5)

這里我們來舉一個實際的例子,下圖是 MySQL Community Server 8.0.19 版本的下載頁,該下載頁通過 MD5  算法分別計算出不同軟件包的數(shù)字指紋,具體如下圖所示:

數(shù)字指紋作用有哪些

(圖片來源 —— https://dev.mysql.com/downloads/mysql/)

當(dāng)用戶從官網(wǎng)上下載到對應(yīng)的安裝包之后,可以利用一些 MD5 校驗工具對已下載的文件進行校驗,然后比對最終的 MD5  數(shù)字指紋。若結(jié)果與官網(wǎng)公布的數(shù)字指紋一致,則表示該安裝包未經(jīng)過任何修改是安全的,基本可以放心安裝。

3.1.2 消息傳輸防篡改

假設(shè)在網(wǎng)絡(luò)上你需要發(fā)送電子文檔給你的朋友,在文件發(fā)送前,先對文檔的內(nèi)容進行 MD5 運算,得出該電子文檔的 “數(shù)字指紋”,并把該 “數(shù)字指紋”  隨電子文檔一同發(fā)送給對方。當(dāng)對方接收到電子文檔之后,也使用 MD5 算法對文檔的內(nèi)容進行哈希運算,在運算完成后也會得到一個對應(yīng)  “數(shù)字指紋”,當(dāng)該指紋與你所發(fā)送文檔的 “數(shù)字指紋” 一致時,表示文檔在傳輸過程中未被篡改。

3.2 信息保密

在互聯(lián)網(wǎng)初期很多網(wǎng)站在數(shù)據(jù)庫中以明文的形式存儲用戶的密碼,這存在很大的安全隱患,比如數(shù)據(jù)庫被黑客入侵,從而導(dǎo)致網(wǎng)站用戶信息的泄露。針對這個問題,一種解決方案是在保存用戶密碼時,不再使用明文,而是使用消息摘要算法,比如  MD5  算法對明文密碼進行哈希運算,然后把運算的結(jié)果保存到數(shù)據(jù)庫中。使用上述方案,避免了在數(shù)據(jù)庫中以明文方式保存密碼,提高了系統(tǒng)的安全性,不過這種方案并不安全,后面我們會詳細分析。

數(shù)字指紋作用有哪些

當(dāng)用戶登錄時,登錄系統(tǒng)對用戶輸入的密碼執(zhí)行 MD5 哈希運算,然后再使用用戶 ID 和密碼對應(yīng)的 MD5 “數(shù)字指紋”  進行用戶認證。若認證通過,則當(dāng)前的用戶可以正常登錄系統(tǒng)。用戶密碼經(jīng)過 MD5 哈希運算后存儲的方案至少有兩個好處:

防內(nèi)部攻擊:因為在數(shù)據(jù)庫中不會以明文的方式保存密碼,因此可以避免系統(tǒng)中用戶的密碼被具有系統(tǒng)管理員權(quán)限的人員知道。

防外部攻擊:網(wǎng)站數(shù)據(jù)庫被黑客入侵,黑客只能獲取經(jīng)過 MD5 運算后的密碼,而不是用戶的明文密碼。

四、MD5 算法使用示例

在 Node.js 環(huán)境中,我們可以使用 crypto 原生模塊提供的 md5 實現(xiàn),當(dāng)然也可以使用主流的 MD5 第三方庫,比如 md5  這個可以同時運行在服務(wù)端和客戶端的第三方庫。在介紹具體使用前,我們需要提前安裝 md5 這個第三方庫,具體安裝方式如下:

$ npm install md5 --save

4.1 crypto 模塊使用示例

const crypto = require("crypto");  const msg = "阿寶哥"; function md5(data) {   const hash = crypto.createHash("md5");   return hash.update(data).digest("hex"); }  console.log("Node.js Crypto MD5: " + msg + " -> " + md5(msg));

4.2 MD5 庫使用示例

const md5 = require('md5'); const msg = "阿寶哥";  console.log("MD5 Lib MD5: " + msg + " -> " + md5(msg));

以上示例代碼正常運行后,在控制臺中會輸出以下結(jié)果:

Node.js Crypto MD5: 阿寶哥 -> 8eec7fcf817f7340b791b32ecdbed570 MD5 Lib MD5: 阿寶哥 -> 8eec7fcf817f7340b791b32ecdbed570

五、MD5 算法的缺陷

哈希碰撞是指不同的輸入?yún)s產(chǎn)生了相同的輸出,好的哈希算法,應(yīng)該沒有人能從中找到 “碰撞” 或者說極度難找到,雖然 “碰撞” 是肯定存在的。

2005 年山東大學(xué)的王小云教授發(fā)布算法可以輕易構(gòu)造 MD5 碰撞實例,此后 2007 年,有國外學(xué)者在王小云教授算法的基礎(chǔ)上,提出了更進一步的 MD5  前綴碰撞構(gòu)造算法 “chosen prefix collision”,此后還有專家陸續(xù)提供了MD5 碰撞構(gòu)造的開源的庫。

2009 年,中國科學(xué)院的謝濤和馮登國僅用了 220.96 的碰撞算法復(fù)雜度,破解了 MD5 的碰撞抵抗,該攻擊在普通計算機上運行只需要數(shù)秒鐘。

MD5 碰撞很容易構(gòu)造,基于 MD5 來驗證數(shù)據(jù)完整性已不可靠,考慮到近期谷歌已成功構(gòu)造了 SHA-1(英語:Secure Hash Algorithm  1,中文名:安全散列算法1)的碰撞實例,對于數(shù)據(jù)完整性,應(yīng)使用 SHA256 或更強的算法代替。

5.1 MD5 碰撞樣本

下面我們先來看一下 MD5 碰撞的樣本:

5.1.1 HEX(十六進制)樣本 A1

4dc968ff0ee35c209572d4777b721587 d36fa7b21bdc56b74a3dc0783e7b9518 afbfa200a8284bf36e8e4b55b35f4275 93d849676da0d1555d8360fb5f07fea2

5.1.2 HEX(十六進制)樣本 A2

4dc968ff0ee35c209572d4777b721587 d36fa7b21bdc56b74a3dc0783e7b9518 afbfa202a8284bf36e8e4b55b35f4275 93d849676da0d1d55d8360fb5f07fea2

兩個樣本之間的差異如下圖所示:

數(shù)字指紋作用有哪些

5.2 驗證 MD5 碰撞

下面我們來使用 Node.js 實際驗證一下樣本 A1 和樣本 A2 經(jīng)過 MD5 運算后輸出的結(jié)果是否一致:

5.2.1 設(shè)置樣本數(shù)據(jù)

let sample1 = ` 4dc968ff0ee35c209572d4777b721587 d36fa7b21bdc56b74a3dc0783e7b9518 afbfa200a8284bf36e8e4b55b35f4275 93d849676da0d1555d8360fb5f07fea2`;  let sample2 = ` 4dc968ff0ee35c209572d4777b721587 d36fa7b21bdc56b74a3dc0783e7b9518 afbfa202a8284bf36e8e4b55b35f4275 93d849676da0d1d55d8360fb5f07fea2 `;

5.2.2 定義 getHashResult 方法

function getHashResult(hexString) {   const hash = crypto.createHash("md5");   const buffer = Buffer.from(hexString.replace(/\s/g, ""), "hex");   return hash.update(buffer).digest("hex"); }

5.2.3 執(zhí)行碰撞檢測

let sample1Md5 = getHashResult(sample1); let sample2Md5 = getHashResult(sample2);  if (sample1Md5 === sample2Md5) {   console.log(`出現(xiàn) MD5 碰撞: ${sample1Md5}`); } else {   console.log(`未出現(xiàn) MD5 碰撞`); }

以上代碼成功運行后,在控制臺中會輸出以下結(jié)果:

出現(xiàn) MD5 碰撞: 008ee33a9d58b51cfeb425b0959121c9

如果你對其它 MD5 碰撞的樣本感興趣,可以查看 MD5碰撞的一些例子 這篇文章。由于基于 MD5 來驗證數(shù)據(jù)完整性不太可靠,所以 Node.js 使用了  SHA256 算法來確保數(shù)據(jù)的完整性。

數(shù)字指紋作用有哪些

(圖片來源 —— https://nodejs.org/download/release/v15.6.0/SHASUMS256.txt.asc)

六、MD5 密碼安全性

6.1 MD5 密文反向查詢

前面我們已經(jīng)提到通過對用戶密碼進行 MD5  運算可以提高系統(tǒng)的安全性。但實際上,這樣的安全性還是不高。為什么呢?因為只要輸入相同就會產(chǎn)生相同的輸出。接下來我們來舉一個示例,字符串 123456789  是一個很常用的密碼,它經(jīng)過 MD5 運算后會生成一個對應(yīng)的哈希值:

MD5("123456789") -> 25f9e794323b453885f5181f1b624d0b

由于輸入相同就會產(chǎn)生相同的結(jié)果,因此攻擊者就可以根據(jù)哈希結(jié)果反推輸入。其中一種常見的破解方式就是使用彩虹表。彩虹表是一個用于加密散列函數(shù)逆運算的預(yù)先計算好的表,常用于破解加密過的密碼散列。  查找表常常用于包含有限字符固定長度純文本密碼的加密。這是以空間換時間的典型實踐,在每一次嘗試都計算的暴力破解中使用更少的計算能力和更多的儲存空間,但卻比簡單的每個輸入一條散列的翻查表使用更少的儲存空間和更多的計算性能。

目前網(wǎng)上某些站點,比如 cmd5.com 已經(jīng)為我們提供了 MD5 密文的反向查詢服務(wù),我們以 MD5("123456789")  生成的結(jié)果,做個簡單的驗證,具體如下圖所示:

數(shù)字指紋作用有哪些

因為 123456789 是很常見的密碼,因此該網(wǎng)站能夠反向得出正確結(jié)果那就不足為奇了。以下是 cmd5  網(wǎng)站的站點說明,大家可以參考一下,感興趣的小伙伴可以親自驗證一下。

現(xiàn)在我們已經(jīng)知道如果用戶的密碼相同 MD5 的值就會一樣,通過一些 MD5  密文的反向查詢網(wǎng)站,密碼大概率會被解析出來,這樣使用相同密碼的用戶就會受到影響。那么該問題如何解決呢?答案是密碼加鹽。

6.2 密碼加鹽

鹽(Salt),在密碼學(xué)中,是指在散列之前將散列內(nèi)容(例如:密碼)的任意固定位置插入特定的字符串。這個在散列中加入字符串的方式稱為  “加鹽”。其作用是讓加鹽后的散列結(jié)果和沒有加鹽的結(jié)果不相同,在不同的應(yīng)用情景中,這個處理可以增加額外的安全性。

在大部分情況,鹽是不需要保密的。鹽可以是隨機產(chǎn)生的字符串,其插入的位置可以也是隨意而定。如果這個散列結(jié)果在將來需要進行驗證(例如:驗證用戶輸入的密碼),則需要將已使用的鹽記錄下來。為了便于理解,我們來舉個簡單的示例。

6.2.1 Node.js MD5 加鹽示例

const crypto = require("crypto");  function cryptPwd(password, salt) {   const saltPassword = password + ":" + salt;   console.log("原始密碼:%s", password);   console.log("加鹽后的密碼:%s", saltPassword);    const md5 = crypto.createHash("md5");   const result = md5.update(saltPassword).digest("hex");   console.log("加鹽密碼的md5值:%s", result); }  cryptPwd("123456789","exe"); cryptPwd("123456789","eft");

以上示例代碼正常運行后,在控制臺中會輸出以下結(jié)果:

原始密碼:123456789 加鹽后的密碼:123456789:exe 加鹽密碼的md5值:3328003d9f786897e0749f349af490ca 原始密碼:123456789 加鹽后的密碼:123456789:eft 加鹽密碼的md5值:3c45dd21ba03e8216d56dce8fe5ebabf

通過觀察以上結(jié)果,我們發(fā)現(xiàn)原始密碼一致,但使用的鹽值不一樣,最終生成的 MD5  哈希值差異也比較大。此外為了提高破解的難度,我們可以隨機生成鹽值并且提高鹽值的長度。

6.3 bcrypt

哈希加鹽的方式確實能夠增加攻擊者的成本,但是今天來看還遠遠不夠,我們需要一種更加安全的方式來存儲用戶的密碼,這也就是今天被廣泛使用的  bcrypt。

bcrypt 是一個由 Niels Provos 以及 David Mazières 根據(jù) Blowfish 加密算法所設(shè)計的密碼散列函數(shù),于 1999  年在 USENIX 中展示。bcrypt  這一算法就是為哈希密碼而專門設(shè)計的,所以它是一個執(zhí)行相對較慢的算法,這也就能夠減少攻擊者每秒能夠處理的密碼數(shù)量,從而避免攻擊者的字典攻擊。實現(xiàn)中 bcrypt  會使用一個加鹽的流程以防御彩虹表攻擊,同時 bcrypt 還是適應(yīng)性函數(shù),它可以借由增加迭代之次數(shù)來抵御日益增進的電腦運算能力透過暴力法破解。

由 bcrypt 加密的文件可在所有支持的操作系統(tǒng)和處理器上進行轉(zhuǎn)移。它的口令必須是 8 至 56 個字符,并將在內(nèi)部被轉(zhuǎn)化為 448  位的密鑰。然而,所提供的所有字符都具有十分重要的意義。密碼越強大,您的數(shù)據(jù)就越安全。

下面我們以 Node.js 平臺的 bcryptjs 為例,介紹一下如何使用 bcrypt 算法來處理用戶的密碼。首先我們需要先安裝  bcryptjs:

$ npm install bcryptjs --save

6.3.1 使用 bcryptjs 處理密碼

const bcrypt = require("bcryptjs");  const password = "123456789"; const saltRounds = 10;  async function bcryptHash(str, saltRounds) {   let hashedResult;   try {     const salt = await bcrypt.genSalt(saltRounds);     hashedResult = await bcrypt.hash(str, salt);   } catch (error) {     throw error;   }   return hashedResult; }  bcryptHash(password, saltRounds).then(console.log);

以上示例代碼正常運行后,在控制臺中會輸出以下結(jié)果:

$2a$10$O1SrEy3KsgN0NQdQjaSU6OxjxDo0jf.j/e2goSwSEu4esz9i58dRm

很明顯密碼 123456789 經(jīng)過 bcrypt 的哈希運算后,得到了一串讀不懂的  “亂碼”。這里我們已經(jīng)完成第一步,即用戶登錄密碼的加密。下一步我們要實現(xiàn)登錄密碼的比對,即要保證用戶輸入正確的密碼后,能正常登錄系統(tǒng)。

6.3.2 使用 bcryptjs 校驗密碼

async function bcryptCompare(str, hashed) {   let isMatch;   try {     isMatc = await bcrypt.compare(str, hashed);   } catch (error) {     throw error;   }   return isMatch; }  bcryptCompare(   "123456789",   "$2a$10$O1SrEy3KsgN0NQdQjaSU6OxjxDo0jf.j/e2goSwSEu4esz9i58dRm" ).then(console.log);  bcryptCompare(   "123456",   "$2a$10$O1SrEy3KsgN0NQdQjaSU6OxjxDo0jf.j/e2goSwSEu4esz9i58dRm" ).then(console.log);

以上示例代碼正常運行后,在控制臺中會輸出以下結(jié)果:

true false

因為我們的原始密碼是 123456789,很明顯與 123456 并不匹配,所以會輸出以上的匹配結(jié)果。

“數(shù)字指紋作用有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI