1. 程式人生 > >安防之淺談Hash

安防之淺談Hash

Hash,一般翻譯做“雜湊”,也有直接音譯為“雜湊”的,就是把任意長度的輸入通過雜湊演算法變換成固定長度的輸出,該輸出就是雜湊值。這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出,所以不可能從雜湊值來確定唯一的輸入值。簡單的說就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式。(來源百度百科解釋)

Hash的特點

  • 演算法是公開的
  • 對相同資料運算,得到的結果是一樣的
  • 對不用資料運算,如MD5得到的結果都是32個字元長度的字串
  • 這玩意沒法逆運算

Hash的運用場景

通過它的這幾個特點.我們可以談談Hash它的運用場景了

登陸密碼加密

我們在開發的過程中首次登陸需要向伺服器傳送使用者密碼進行賬戶驗證.但是使用者的密碼是非常隱私的資訊.所以一定要使用加密保護.

直接使用Hash

那麼目前最優的解決方案就是使用密碼的Hash值進行驗證
客戶端
直接將使用者輸入的密碼進行Hash運算,得到結果傳送給伺服器驗證.因為Hash演算法無法逆運算,所以就算Hash值洩露,使用者真實密碼也不會洩露.
服務端
需要伺服器配合,在使用者註冊的時候,服務端的資料庫中儲存的就是使用者密碼的Hash值,而不是密碼本身(根據Hash的特點,對相同的資料加密結果是一樣的).這樣就算伺服器被攻克,使用者的隱私資訊也能起到一定的保護.

也就是現在為什麼各類產品只提供重置密碼的功能,而不再有找回密碼的功能了.因為服務端本身也不知道使用者的真實密碼.

**特別說明:**使用者的密碼屬於非常隱私的資訊.因為大多數使用者有一個特點.密碼喜歡使用重複的.如果你的APP洩露了使用者的密碼.那麼很有可能,黑客利用使用者的手機號碼加上密碼,可以套出使用者的支付資訊.這種後果是非常嚴重的!

再加一點東西

上面所說的案例理論上已經非常的"安全"了.因為就算黑客知道了你的Hash值,也沒法逆運算出使用者的密碼.但情況並不樂觀.我們眼見為實!
以MD5為例:在終端上演示一下(比如我的密碼是123456)

$md5 -s "123456"

MD5的結果是: e10adc3949ba59abbe56e057f20f883e
接下來隆重介紹一個網站http://www.cmd5.com/
我們只需要將Hash值進行反向的查詢.

查詢結果圖

可能你會問,Hash既然不能反算為何這個網站能夠查詢出來?仔細看下網站的介紹不難發現:其實它是一個巨大的資料庫.利用明文和Hash的資料記錄,進行反向查詢.

網站介紹

當然,提供雜湊反向查詢服務的不僅僅只有這個網站,還有很多盈利性的公司提供有償服務.
所以如果我們單純的直接使用Hash演算法,使用者的密碼安全性會非常低.
早期的解決方案加鹽

//使用者密碼
NSString * pwd = @"123456";
//足夠複雜 足夠長!!
static NSString * salt = @")@#(*URJ(@FJ_(@JF_([email protected](IJWD{OIJW_(DIJ!W";
//先將明文拼接一個鹽
pwd = [pwd stringByAppendingString:salt];
//再進行Hash演算法
const char *str = pwd.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), buffer);
NSMutableString *md5Str = [NSMutableString string];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [md5Str appendFormat:@"%02x", buffer[i]];
 }

這種方式,對於反向查詢來說就比較困難了.安全係數也相對較高.

HMAC(Hash-based Message Authentication Code)

對於簡單的使用鹽的方式還是會有安全隱患,因為如果鹽被洩露了.那麼整個專案將陷入被動.因為這種方式將鹽寫死在程式裡面了,要想今後換掉是非常難的.
那麼接下來介紹一種加密方案HMAC.它使用一個金鑰,並且做了兩次雜湊!

注意:在開發過程中,這個金鑰KEY是從伺服器獲取的.並且一個使用者對應一個KEY

廢話不多說,直接上程式碼

//使用者密碼
NSStirng * pwd = @"123456";
//加密用的KEY,注意是從伺服器獲取的
NSString * key = @"hmackey";
//轉成C串
const char *keyData = key.UTF8String;
const char *strData = pwd.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
//hmac加密
CCHmac(kCCHmacAlgSHA1, keyData, strlen(keyData), strData, strlen(strData), buffer);
NSMutableString *hmacStr = [NSMutableString string];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [hmacStr appendFormat:@"%02x", buffer[i]];
 }

對於這種加密方案.就可以很好的保護使用者的隱私資訊.因為就算洩露了KEY.這個KEY也只是一個使用者的.不會汙染整個專案.
如果拿到這個KEY,然後想反查詢出使用者的明文密碼.這個成本,除非這是馬雲的賬戶.

所謂安全,無法做到絕對安全.他們灰產有句話:只要錢到位,沒有什麼不可能!我們要做到的就是相對安全.讓破解的成本大於破解的利潤.

登入加密補充

今天寫得開心.所以再分享一點乾貨.
剛才我們一直停留子在黑客想要拿到使用者的真實密碼.那麼如果黑客換了一個思路.大哥就是想要拿到使用者的登入許可權呢?
那麼我們這種加密.無論你怎麼玩.妥妥的都是給伺服器一個Hash串進行驗證啊,也就是我只需要拿到你的Hash值.那麼我只要模擬你客戶端進行登入是再簡單不過了.
當然,這樣的防護手段有很多.我介紹一種有效的防護方式.有更好的建議可以留言寫在下面,一起交流,向您學習.
註冊的過程
註冊的過程還是一樣.伺服器儲存的還是一串HMAC加密之後的HASH值.進行校驗.但是登入時的驗證做點修改.
客戶端

  • 通過伺服器的KEY進行HMAC加密,得到HMAC的Hash串
  • 將得到的Hash串拼接一個時間字串**@‘201807102248’**注意只到分(當然根據你的情況可以到秒)
  • 然後將這個拼接完成的串,再次Hash.將這個結果發給伺服器驗證

服務端
伺服器儲存了hmac的Hash串,以同樣的演算法,拼接伺服器的時間,進行運算,然後校驗.比如時間是59秒99傳送的請求.伺服器正好跳過一個分鐘.過程如下:

  • (伺服器的Hash串[email protected]“201807102249”)Hash.這次不通過再來一次
  • (伺服器的Hash串[email protected]“201807102248”)Hash.和上一分鐘對比,一次通過算成功

這樣的好處,可以做到每登入傳送給伺服器的Hash值是不一樣的.黑客不能通過儲存Hash值模擬登入.

版權&檔案識別

當然Hash的作用除了用於登入密碼加密以外.還有版權的運用.
比如如何識別一段視訊或者一段音訊,這種數字檔案是正版的.這個時候,我們使用肉眼是沒法判斷的.因為翻錄的視訊和音訊檔案幾乎看不出來.但是,檔案的二進位制不一樣,它的Hash值是不會欺騙群眾的.所以類似YouTube這樣的網站,在你上傳視訊的時候,它會將檔案的Hash值儲存.當其他的網站上傳這個視訊,那麼看是否是正版,就是對比檔案的Hash值.
既然可以識別檔案.那麼還有一個非常廣泛運用的就是像百度雲這樣的雲端服務.舉個例子:
很多小夥伴保留的視訊,經常被"和諧".有的人將視訊的名稱全部改為葫蘆兄弟,黑貓警長但是還是被和諧了.
百度識別你的視訊檔案,和你的檔名稱,以及檔案字尾(有人改成.txt)沒有半毛錢關係.它只會看這個檔案的Hash值.那麼如果想要逃脫.你唯一的出路就是改變檔案原有的二進位制.(翻錄\視訊格式轉換).

以上就是這篇文章的全部內容了,希望本文的內容對大傢俱有一定的參考學習價值,同時歡迎大家進入小編交流群:624212887,一起交流學習,謝謝大家的支援