需求
對於用戶密碼的保護,通常都會進行加密。我們通常對密碼進行加密,然後存放在數據庫中,在用戶進行登錄的時候,將其輸入的密碼與數據庫中存放的密文進行比較,以驗證用戶密碼是否正確。
BCrypt和MD5介紹
BCrypt加密: 一種加鹽的單向Hash,不可逆的加密算法,同一種明文(plaintext),每次加密後的密文都不一樣,而且不可反向破解生成明文,破解難度很大。
MD5加密: 是不加鹽的單向Hash,不可逆的加密算法,同一個密碼經過hash的時候生成的是同一個hash值,在大多數的情況下,有些經過md5加密的方法將會被破解。
Bcrypt生成的密文是60位的。而MD5的是32位的。
目前,MD5和BCrypt比較流行。相對來說,BCrypt比MD5更安全,但加密更慢。
雖然BCrpyt也是輸入的字符串+鹽,但是與MD5+鹽的主要區別是:每次加的鹽不同,導致每次生成的結果也不相同。無法比對!
BCrypt加密實現
第一種: 單獨用BCrypt進行密碼加密
1,添加依賴
1
2 3 4 5 |
<dependency>
<groupId>org.mindrot</groupId> <artifactId>jbcrypt</artifactId> <version>0.4</version> </dependency> |
2,代碼
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public static void main(String[] args) {
String password = "666666"; /** * 第一步:生成鹽值salt * 調用BCrypt類的構造函數 * 有三個構造函數: * BCrypt.gensalt() * log_rounds爲散列數因子,範圍4-31,默認爲10 * BCrypt.gensalt(int log_rounds) * random是隨機數產生器,要使用的new SecureRandom()實例 * BCrypt.gensalt(int log_rounds, SecureRandom random) * */ String salt = BCrypt.gensalt(); /** * 第二步:生成加密字符串 * 調用BCrypt類的hashpw(String password, String salt)函數進行加密 * 其中password是明文密碼,salt是第一步生成的鹽值 */ String hashpw = BCrypt.hashpw(password, salt); System.out.println("明文:"+password); System.out.println("密文1:"+hashpw); /** * 第三步:驗證密文是否正確 * 調用BCrypt類的checkpw(String plaintext, String hashed)函數 * plaintext 需要傳入的明文 * hashed 爲第二步加密後的密文 */ String plaintext = "666666"; boolean checkpw = BCrypt.checkpw(plaintext, hashpw); if (checkpw){ System.out.println("密碼正確"); }else { System.out.println("密碼錯誤"); } } |
第二種: 如果用到spring security安全框架,就直接用spring security 的依賴就可以
1,添加依賴
1
2 3 4 5 |
<!-- spring security 安全認證 -->
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> |
2,創建BCryptPasswordEncoder 類後調用其encode方法,BCryptPasswordEncoder類底層也是調用第一種方法。
1
2 3 4 5 6 7 8 9 10 11 12 |
public static void BCryptTest(){
String password = "666666"; BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); // encode() 密碼加密 String encode = passwordEncoder.encode(password); //matches 密碼驗證 if (passwordEncoder.matches("666666",encode1)){ System.out.println("密碼正確"); }else { System.out.println("密碼錯誤"); } } |
1
2 3 4 5 |
for (int i = 1; i <10 ; i++){
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String encode = passwordEncoder.encode(password); System.out.println(encode); } |
MD5加密實現
1,添加依賴
1
2 3 4 |
<dependency>
<groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> |
2, 代碼
1
2 3 4 5 6 7 8 9 10 11 |
public static void md5Test(){
String password = "x987654321d"; //鹽/祕鑰 隨機數 String salt = UUID.randomUUID().toString().toUpperCase(); //帶鹽加密 String md5pw = DigestUtils.md5Hex(password + salt); //不帶鹽加密 String md5pw1 = DigestUtils.md5Hex(password); System.out.println("帶鹽 "+md5pw); System.out.println("不帶鹽 "+md5pw1); } |
MD5驗證
第一步:把鹽值和加密後的密文都存入數據庫
第二步:驗證時用輸入的密碼和數據庫中存入的鹽值進行再次進行加密後得到的密文和已經存入數據庫中的密文進行比較。(這也是md5加密的缺點,如果密碼相同,加密後的密文就相同。)