您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Java怎么利用MD5實現(xiàn)對密碼進行加密處理”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“Java怎么利用MD5實現(xiàn)對密碼進行加密處理”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
現(xiàn)在市場是加密的方式已經(jīng)有很多了,像Base64加密算法(編碼方式),MD5加密(消息摘要算法,驗證信息完整性),對稱加密算法,非對稱加密算法,數(shù)字簽名算法,數(shù)字證書,CA認證等等。。
Base64應用場景:圖片轉(zhuǎn)碼(應用于郵件,img標簽,http加密)
MD5應用場景:密碼加密、imei加密、文件校驗
非對稱加密:電商訂單付款、銀行相關業(yè)務
如果直接使用MD5進行加密,其實是不安全的,這是是可以驗證的,比如下面這個例子:
我直接使用MD5對123456的密碼進行加密??粗芘J前桑淮S機數(shù),但是其實一碰就碎
接下來就使用大家常用的一個網(wǎng)站進行破解:MD5破解網(wǎng)站
把剛才生成的MD5加密后的密碼進行解密。
輕松破解,別說黑客了,這個網(wǎng)站都能破解出來,那風險有多大就不用說了
所以我們需要采取一些措施,用于二次不強MD5加密后的密碼,針對這種方式,現(xiàn)在大多數(shù)采取的方式就是加鹽
鹽(salt)一般是一個隨機生成的字符串或者常量。我們將鹽與原始密碼連接在一起(放在前面或后面都可以),然后將拼接后的字符串加密。salt這個值是由系統(tǒng)隨機生成的,并且只有系統(tǒng)知道。即便兩個用戶使用了同一個密碼,由于系統(tǒng)為它們生成的salt值不同,散列值也是不同的。
加salt可以一定程度上解決這一問題。所謂加salt方法,就是加點“佐料”。其基本想法是這樣的:當用戶首次提供密碼時(通常是注冊時),由系統(tǒng)自動往這個密碼里撒一些“佐料”,然后再散列。而當用戶登錄時,系統(tǒng)為用戶提供的代碼撒上同樣的“佐料”,然后散列,再比較散列值,已確定密碼是否正確。
這樣也就變成了將密碼+自定義的鹽值來取MD5。但是如果黑客拿到了你的固定的鹽值,那這樣也不安全了。所以比較好的做法是用隨機鹽值。用戶登陸時再根據(jù)用戶名取到這個隨機的鹽值來計算MD5。
個人建議把鹽設置成隨機數(shù)而不是常量,這樣更加安全。
坐標如下:
<!--MD5加密 對銘文信息進行加密操作--> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency>
這種對銘文加密的操作,我們可以封裝成一個工具類,在這里我們主要進行對明文密碼進行MD5加密,并且進行二次加鹽加密,以及對比加鹽后的密碼和初始密碼是否相同。
直接把全部代碼附上:
package com.wyh.util; import org.apache.commons.codec.binary.Hex; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; /** * @Author 魏一鶴 * @Description 將明文密碼進行MD5加鹽加密 * @Date 23:18 2023/2/7 **/ public class SaltMD5Util { /** * @Author 魏一鶴 * @Description 生成普通的MD5密碼 * @Date 23:17 2023/2/7 **/ public static String MD5(String input) { MessageDigest md5 = null; try { // 生成普通的MD5密碼 md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { return "check jdk"; } catch (Exception e) { e.printStackTrace(); return ""; } char[] charArray = input.toCharArray(); byte[] byteArray = new byte[charArray.length]; for (int i = 0; i < charArray.length; i++) byteArray[i] = (byte) charArray[i]; byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); for (int i = 0; i < md5Bytes.length; i++) { int val = ((int) md5Bytes[i]) & 0xff; if (val < 16) hexValue.append("0"); hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } /** * @Author 魏一鶴 * @Description 生成鹽和加鹽后的MD5碼,并將鹽混入到MD5碼中,對MD5密碼進行加強 * @Date 23:17 2023/2/7 **/ public static String generateSaltPassword(String password) { Random random = new Random(); //生成一個16位的隨機數(shù),也就是所謂的鹽 /** * 此處的鹽也可以定義成一個系統(tǒng)復雜點的常量,而不是非要靠靠隨機數(shù)隨機出來 兩種方式任選其一 例如下面這行代碼: * 鹽加密 :SALT的字符串是隨意打的,目的是把MD5加密后的再次加密變得復雜 * public static final String SALT = "fskdhfiuhjfshfjhsad4354%@!@#%3"; **/ StringBuilder stringBuilder = new StringBuilder(16); stringBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999)); int len = stringBuilder.length(); if (len < 16) { for (int i = 0; i < 16 - len; i++) { stringBuilder.append("0"); } } // 生成鹽 String salt = stringBuilder.toString(); //將鹽加到明文中,并生成新的MD5碼 password = md5Hex(password + salt); //將鹽混到新生成的MD5碼中,之所以這樣做是為了后期更方便的校驗明文和秘文,也可以不用這么做,不過要將鹽單獨存下來,不推薦這種方式 char[] cs = new char[48]; for (int i = 0; i < 48; i += 3) { cs[i] = password.charAt(i / 3 * 2); char c = salt.charAt(i / 3); cs[i + 1] = c; cs[i + 2] = password.charAt(i / 3 * 2 + 1); } return new String(cs); } /** * @Author 魏一鶴 * @Description 驗證明文和加鹽后的MD5碼是否匹配 * @Date 23:16 2023/2/7 **/ public static boolean verifySaltPassword(String password, String md5) { //先從MD5碼中取出之前加的鹽和加鹽后生成的MD5碼 char[] cs1 = new char[32]; char[] cs2 = new char[16]; for (int i = 0; i < 48; i += 3) { cs1[i / 3 * 2] = md5.charAt(i); cs1[i / 3 * 2 + 1] = md5.charAt(i + 2); cs2[i / 3] = md5.charAt(i + 1); } String salt = new String(cs2); //比較二者是否相同 return md5Hex(password + salt).equals(new String(cs1)); } /** * @Author 魏一鶴 * @Description 生成MD5密碼 * @Date 23:16 2023/2/7 **/ private static String md5Hex(String src) { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] bs = md5.digest(src.getBytes()); return new String(new Hex().encode(bs)); } catch (Exception e) { return null; } } public static void main(String args[]) { // 原密碼 String password = "123456"; System.out.println("明文(原生)密碼:" + password); // MD5加密后的密碼 String MD5Password = MD5(password); System.out.println("普通MD5加密密碼:" + MD5Password); // 獲取加鹽后的MD5值 String SaltPassword = generateSaltPassword(password); System.out.println("加鹽后的MD密碼:" + SaltPassword); System.out.println("加鹽后的密碼和原生密碼是否是同一字符串:" + verifySaltPassword(password, SaltPassword)); } }
這樣我們就可以簡單的測試下,這傳說中的鹽是否真的這么厲害,還是剛才的套路,我們定義一個明文為123456的密碼。然后再對生成的MD5密碼進行加鹽處理,分別進行破解,以及對比加鹽后的密碼和初始密碼是否相同。
拿著MD5的密碼進行破解,不用想,基本就是一碰就碎
然后試試加了鹽之后的把,你會發(fā)現(xiàn)它破解不了。
有了這些的基礎后,我們就可以對用戶注冊和登錄分別進行加鹽加密,以及破解密碼對比是否一致了
其實很簡單,再原有的密碼上進行加密即可:
@PostMapping(value = "/save") public Result save(@RequestBody User user) { return userService.saveUser(user); } @Override public Result saveUser(User user) { // 密碼 進行MD5加鹽再入庫 user.setPassword(SaltMD5Util.generateSaltPassword(user.getPassword())); // 默認頭像 user.setImage("http://localhost:9090/upload/defaultUserImage.jpg"); if (this.save(user)) { return Result.ok(user); } return Result.fail("保存用戶信息失敗"); }
接口簡單測試下把,可以看到是以加密的方式入庫的:
加密后入庫了可不夠,還要進行對比呢,隨意登錄也要處理下:
@GetMapping(value = "/login") public Result login(User user) { return userService.login(user); } public Result login(User user) { // 賬號 String account = user.getAccount(); // 密碼 String password = user.getPassword(); // 如果賬號或者密碼為空,返回錯誤信息 if (StringUtils.isEmpty(account) || StringUtils.isEmpty(password)) { return Result.fail("賬號和密碼都不能為空!"); } // 根據(jù)賬號和密碼查詢對應的用戶信息 User loginUser = this.query() .eq("account", account) .one(); if (!StringUtils.isEmpty(loginUser)) { // 獲取該用戶在數(shù)據(jù)庫里面的加密過的密碼 String saltPassword = loginUser.getPassword(); // 輸入的密碼和加密后的密碼進行比較 boolean passwordFlag = SaltMD5Util.verifySaltPassword(password, saltPassword); // 如果根據(jù)賬號查詢和校驗加密密碼失敗,則返回錯誤信息 if (StringUtils.isEmpty(loginUser) || !passwordFlag) { return Result.fail("登錄失敗,賬號或者密碼錯誤!"); } // 如果賬號狀態(tài)被禁用了 if (loginUser.getStatus().equals(ACCOUNT_DISABLE.getCode())) { return Result.fail("登錄失敗,該賬號已被引用,請聯(lián)系管理員!", loginUser); } // 存在的話返回查詢到的用戶信息 return Result.ok(loginUser); } return Result.fail("登錄失敗,賬號或者密碼錯誤!"); }
我們還以剛才注冊的用戶為例進行登錄,可以看到雖然庫里是加密后的密碼,我們輸入的是明文,但是一樣可以匹配上的:
讀到這里,這篇“Java怎么利用MD5實現(xiàn)對密碼進行加密處理”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內(nèi)容的文章,歡迎關注億速云行業(yè)資訊頻道。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。