最安全的加密算法Bcrypt防止數據泄露詳解_第1頁
最安全的加密算法Bcrypt防止數據泄露詳解_第2頁
最安全的加密算法Bcrypt防止數據泄露詳解_第3頁
最安全的加密算法Bcrypt防止數據泄露詳解_第4頁
最安全的加密算法Bcrypt防止數據泄露詳解_第5頁
已閱讀5頁,還剩2頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第最安全的加密算法Bcrypt防止數據泄露詳解目錄引言哈希(Hash)與加密(Encrypt)不可逆的MD5為什么是不安全的?如何防御彩虹表的破解?一個更難破解的加密算法BcryptPasswordEncoder接口

引言

這是《SpringSecurity進階》專欄的第三篇文章,給大家介紹一下SpringSecurity中內置的加密算法BCrypt,號稱最安全的加密算法,究竟有著什么魔力能讓黑客聞風喪膽

哈希(Hash)與加密(Encrypt)

哈希(Hash)是將目標文本轉換成具有相同長度的、不可逆的雜湊字符串(或叫做消息摘要),而加密(Encrypt)是將目標文本轉換成具有不同長度的、可逆的密文。

哈希算法往往被設計成生成具有相同長度的文本,而加密算法生成的文本長度與明文本身的長度有關。哈希算法是不可逆的,而加密算法是可逆的。

HASH算法是一種消息摘要算法,不是一種加密算法,但由于其單向運算,具有一定的不可逆性,成為加密算法中的一個構成部分。

JDK的String的Hash算法。代碼如下:

publicinthashCode(){

inth=hash;

if(h==0value.length0){

charval[]=value;

for(inti=0;ivalue.length;i++){

h=31*h+val[i];

hash=h;

returnh;

從JDK的API可以看出,它的算法等式就是

s[0]*31^(n-1)+s[1]*31^(n-2)+...+s[n-1]

其中s[i]就是索引為i的字符,n為字符串的長度。

HashMap的hash計算時先計算hashCode(),然后進行二次hash。代碼如下:

//計算二次Hash

inthash=hash(key.hashCode());

staticinthash(inth){

h^=(h20)^(h12);

returnh^(h7)^(h

可以發現,雖然算法不同,但經過這些移位操作后,對于同一個值使用同一個算法,計算出來的hash值一定是相同的。

那么,hash為什么是不可逆的呢?

假如有兩個密碼3和4,我的加密算法很簡單就是3+4,結果是7,但是通過7我不可能確定那兩個密碼是3和4,有很多種組合,這就是最簡單的不可逆,所以只能通過暴力破解一個一個的試。

在計算過程中原文的部分信息是丟失了。一個MD5理論上是可以對應多個原文的,因為MD5是有限多個而原文是無限多個的。

不可逆的MD5為什么是不安全的?

因為hash算法是固定的,所以同一個字符串計算出來的hash串是固定的,所以,可以采用如下的方式進行破解。

暴力枚舉法:簡單粗暴地枚舉出所有原文,并計算出它們的哈希值,看看哪個哈希值和給定的信息摘要一致。字典法:黑客利用一個巨大的字典,存儲盡可能多的原文和對應的哈希值。每次用給定的信息摘要查找字典,即可快速找到碰撞的結果。彩虹表(rainbow)法:在字典法的基礎上改進,以時間換空間。是現在破解哈希常用的辦法。

對于單機來說,暴力枚舉法的時間成本很高(以14位字母和數字的組合密碼為例,共有1.2410^25種可能,即使電腦每秒鐘能進行10億次運算,也需要4億年才能破解),字典法的空間成本很高(仍以14位字母和數字的組合密碼為例,生成的密碼32位哈希串的對照表將占用5.710^14TB的存儲空間)。但是利用分布式計算和分布式存儲,仍然可以有效破解MD5算法。因此這兩種方法同樣被黑客們廣泛使用。

如何防御彩虹表的破解?

雖然彩虹表有著如此驚人的破解效率,但網站的安全人員仍然有辦法防御彩虹表。最有效的方法就是加鹽,即在密碼的特定位置插入特定的字符串,這個特定字符串就是鹽(Salt),加鹽后的密碼經過哈希加密得到的哈希串與加鹽前的哈希串完全不同,黑客用彩虹表得到的密碼根本就不是真正的密碼。即使黑客知道了鹽的內容、加鹽的位置,還需要對H函數和R函數進行修改,彩虹表也需要重新生成,因此加鹽能大大增加利用彩虹表攻擊的難度。

一個網站,如果加密算法和鹽都泄露了,那針對性攻擊依然是非常不安全的。因為同一個加密算法同一個鹽加密后的字符串仍然還是一毛一樣滴!

一個更難破解的加密算法Bcrypt

BCrypt是由NielsProvos和DavidMazires設計的密碼哈希函數,他是基于Blowfish密碼而來的,并于1999年在USENIX上提出。

除了加鹽來抵御rainbowtable攻擊之外,bcrypt的一個非常重要的特征就是自適應性,可以保證加密的速度在一個特定的范圍內,即使計算機的運算能力非常高,可以通過增加迭代次數的方式,使得加密速度變慢,從而可以抵御暴力搜索攻擊。

Bcrypt可以簡單理解為它內部自己實現了隨機加鹽處理。使用Bcrypt,每次加密后的密文是不一樣的。

對一個密碼,Bcrypt每次生成的hash都不一樣,那么它是如何進行校驗的?

雖然對同一個密碼,每次生成的hash不一樣,但是hash中包含了salt(hash產生過程:先隨機生成salt,salt跟password進行hash);在下次校驗時,從hash中取出salt,salt跟password進行hash;得到的結果跟保存在DB中的hash進行比對。

在SpringSecurity中內置了Bcrypt加密算法,構建也很簡單,代碼如下:

@Bean

publicPasswordEncoderpasswordEncoder(){

returnnewBCryptPasswordEncoder();

生成的加密字符串格式如下:

$2b$[cost]$[22charactersalt][31characterhash]

比如:

$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

\__/\/\____________________/\_____________________________/

AlgCostSaltHash

上面例子中,$2a$表示的hash算法的唯一標志。這里表示的是Bcrypt算法。

10表示的是代價因子,這里是2的10次方,也就是1024輪。

N9qo8uLOickgx2ZMRZoMye是16個字節(128bits)的salt經過base64編碼得到的22長度的字符。

最后的IjZAgcfl7p92ldGxad68LJZdL17lhWy是24個字節(192bits)的hash,經過bash64的編碼得到的31長度的字符。

PasswordEncoder接口

這個接口是SpringSecurity內置的,如下:

publicinterfacePasswordEncoder{

Stringencode(CharSequencerawPassword);

booleanmatches(CharSequencerawPassword,StringencodedPassword);

defaultbooleanupgradeEncoding(StringencodedPassword){

returnfalse;

這個接口有三個方法:

encode方法接受的參數是原始密碼字符串,返回值是經過加密之后的hash值,hash值是不能被逆向解密的。這個方法通常在為系統添加用戶,或者用戶注冊的時候使用。matches方法是用來校驗用戶輸入密碼rawPassword,和加密后的hash值encodedPassword是否匹配。如果能夠匹配返回true,表示用戶輸入的密碼rawPassword是正確的,反之返回fasle。也就是說雖然這個hash值不能被逆向解密,但是可以判斷是否和原始密碼匹配。這個方法通常在用戶登錄的時候進行用戶輸入密碼的正確性校驗。upgradeEncoding設計的用意是,判斷當前的密碼是否需要升級。也就是是否需要重新加密?需要的話返回true,不需要的話返回fasle。默認實現是返回false。

例如,我們可以通過如下示例代碼在進行用戶注冊的時候加密存儲用戶密碼

//將User保存到數據庫表,該表包含password列

user.setPassword(passwordEncoder.encode(user.getPassword()));

BCryptPasswordEncoder是SpringSecurity推薦使用的PasswordEncoder接口實現類

publicclassPasswordEncoderTest{

@Test

voidbCryptPasswordTest(){

PasswordEncoderpasswordEncoder=newBCryptPasswordEncoder();

StringrawPassword="123456";//原始密碼

StringencodedPassword=passwordEncoder.encode(rawPassword);//加密后的密碼

System.out.println("原始密碼"+rawPassword);

System.out.println("加密之后的hash密碼:"+encodedPassword);

System.out.println(rawPassword+"是否匹配"+encodedPassword+":"http://密碼校驗:true

+passwordEncoder.matches(rawPassword,encodedPassword));

System.out.println("654321是否匹配"+encodedPassword+":"http://定義一個錯誤的密碼進行校驗:false

+passwordEncoder.matches("654321",encodedPassword));

上面的測試用例執行的結果是下面這樣的。(注意:對于同一個原始密碼,每次加密之后的hash密碼都是不一樣的,這正是BCryptPasswordEncoder的強大之處,它不僅不能被破解,想通過常用密碼對照表進行大海撈針你都無從下手),輸出如下:

原始密碼123456

加密之后的hash密碼:$2a$10$zt6dUMTjNSyzINTGyiAgluna3mPm7qdgl26vj4tFpsFO6WlK5lXNm

123456是否匹配$2a$10$zt6dUMTjNSyzINTGyiAgluna

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論