欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實現(xiàn)加鹽算法的兩種方法

 更新時間:2024年02月12日 10:41:05   作者:fiance111  
數(shù)據(jù)安全是一個重要的問題,本文主要介紹了Java實現(xiàn)加鹽算法的兩種方法,具有一定的參考價值,感興趣的可以了解一下

密碼安全是一件很重要的事情,所以一定要謹(jǐn)慎對待

常見的主要是3種方式

  • 明文
  • MD5加密
  • 加鹽算法

首先明文肯定是不可取的,在數(shù)據(jù)庫中明文存儲密碼風(fēng)險實在是太大了

簡單來說,使用MD5就是將一串字符串通過某特定的算法來將其變成另一種形式,這樣子就在外觀上起到了加密的效果,但是由于背后的算法是固定的,所以每一個字符串都有固定的MD5格式

密碼破解程序可以是暴力破解:將得到的密碼使用MD5轉(zhuǎn)換成哈希,之后將得到的哈希與最初的哈希進行比較,要是匹配就說明已經(jīng)破解了密碼,但是這種方法的時間復(fù)雜度很高,會耗時很久

彩虹表:彩虹表記錄了幾乎所有字符串的MD5對照表

有了彩虹表MD5就相當(dāng)于是不存在了,因為一種字符串就只有一種特定的MD5格式

手寫一個加鹽算法

首先要理解“鹽”的概念,他就是一個隨機值,沒有任何規(guī)律

這里約定密碼的最終格式都是 鹽值(32位)$加密后的密碼(32位)

加密的實現(xiàn)思路:

每次調(diào)用的時候都會隨機生成一個鹽值(隨機、唯一) + 用戶輸入的密碼(使用MD5) = 加密的密碼,鹽值(32位) + $ + 加密密碼(32位) = 最終的密碼格式

解密(驗證密碼)的實現(xiàn)思路:

解密的時候需要兩個密碼 : 用戶輸入的明文待驗證密碼 、 存儲在數(shù)據(jù)庫中的最終密碼(自定義格式: 鹽值(32位)$加密后的密碼(32位))

解密(驗證密碼)的核心在于得到 鹽值

解密的時候,首先從最終數(shù)據(jù)庫中的密碼中來得到鹽值,之后將用戶輸入的明文待驗證密碼加上這個鹽值,生成加密后的密碼,然后使用鹽值 + 分隔符 + 加密后的密碼 生成 最終密碼格式,再與數(shù)據(jù)庫中最終的密碼格式進行比對

要是一樣的,那就說明這個用戶輸入的密碼是沒有問題的,要是不對就說明密碼輸入錯誤

最重要的是先理解加鹽 解密的實現(xiàn)思路,這是最核心的!??!

就算使用加鹽算法來對密碼加密,也不能保證就一定是安全的,可以針對一個鹽值來生成一個彩虹表,暴力破解也是可以的,但是這只是破解了一個賬號密碼,所以破解的成本是極大的,當(dāng)破解的成本遠大于收益的時候,可以看做是安全的

解密(驗證密碼)具體的實現(xiàn)步驟:

  • 從數(shù)據(jù)庫中真正的最終密碼中得到鹽值
  • 將用戶輸入的明文密碼+鹽值 = 加密后的密碼(使用MD5)
  • 使用鹽值 + 分隔符 + 加密后的密碼 生成 最終密碼(最終密碼的格式)
  • 對比生成的最終密碼和數(shù)據(jù)庫中的最終密碼是否相等

要是相等就說明用戶名和密碼都是對的,要是不對,就說明密碼輸入錯誤

為什么就是能驗證成功呢?

最終比對的就是三個部分: 鹽值 我就是從數(shù)據(jù)庫中的最終密碼中拿的前32位,肯定是一樣的,$都是一樣的,加密的部分都是MD5加密的,所以 也一定是一樣的,所以能登錄成功

具體的代碼:

在common包下面建一個PasswordUtils類

package com.example.demo.common;

import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.UUID;

public class PasswordUtils{

    /**
     * 1.加鹽并生成最終的密碼
     * @param password 明文的密碼
     * @return 最終生成的密碼
     */
    public static String encrypt(String password){
        //a.產(chǎn)生鹽值
        //UUID.randomUUID()會生成32位數(shù)字+4位-,是隨機的唯一的,將4位-去掉就得到32位數(shù)字的鹽值
        String salt = UUID.randomUUID().toString().replace("-","");
        //生成加鹽后的密碼(需要使用MD5)
        String saltPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
        //生成最終的密碼格式
        String finalPassword = salt + "$" + saltPassword;
        return finalPassword;
    }

    /**
     * 2.加鹽并生成最終密碼格式(方法一的重載),區(qū)別于上面的方法:這個方法是用來解密的,給定了鹽值,生成一個最終密碼,
     后面要和正確的最終密碼進行比對
     * @param password 需要驗證的明文密碼
     * @param salt
     * @return
     */
    public static  String encrypt(String password, String salt){
        //1.生成一個加密后的密碼
        String saltPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
        //2.生成最終的密碼(待驗證)
        String finalPassword = salt + "$" + saltPassword;
        return finalPassword;
    }

    /**
     * 3.驗證密碼
     * @param inputPassword  登錄用戶輸入的明文密碼
     * @param finalPassword  數(shù)據(jù)庫中實際的最終密碼格式
     * @return
     */
    public static boolean check(String inputPassword, String finalPassword){
        //首先判斷這兩個參數(shù)到底有沒有值,數(shù)據(jù)庫中的最終密碼是不是65位
        if(StringUtils.hasLength(inputPassword) && StringUtils.hasLength(finalPassword)
        && finalPassword.length() == 65){
            //a.首先從最終的密碼中得到鹽值
            //使用$將finalPassword劃分成兩個部分,前面的32位的部分就是鹽值
            //注意:這里的$是被認為是一個通配符,所以要轉(zhuǎn)義一下
            String salt = finalPassword.split("\\$")[0];
            //b.使用之前加密的方法,生成最終的密碼格式(待驗證)
            String checkPassword = encrypt(inputPassword,salt);
            if(checkPassword.equals(finalPassword)){
                return true;
            }
        }
        return false;
    }
}

在寫完了加鹽算法之后,就要修改一下博客的具體調(diào)用了

在userinfoController中的注冊接口:

@RequestMapping("/reg")
public AjaxResult reg(UserInfo userinfo) {
    //非空判斷
    //雖然前端已經(jīng)進行了非空檢查,但是用戶可能會通過別的方式直接訪問url繞過前端的非空校驗,所以作為后端,應(yīng)該要考慮到這一點
    //所以在后端也是要寫非空校驗的
    if (userinfo == null || !StringUtils.hasLength(userinfo.getUsername()) ||
        !StringUtils.hasLength(userinfo.getPassword())){
            return AjaxResult.fail(-1,"非法參數(shù)");
    }
    //不是空的話,就直接返回成功的響應(yīng)就行了
    //這里響應(yīng)的是1,所以前端在進行成功判斷的時候才有result.data == 1這一條

    //注冊成功之后要將密碼加鹽,寫進數(shù)據(jù)庫中
    userinfo.setPassword(PasswordUtils.encrypt(userinfo.getPassword()));
    return AjaxResult.success(userService.reg(userinfo));
}

在userinfoController中的登錄接口:

@RequestMapping("/login")
public AjaxResult login(HttpServletRequest request, String username, String password) {
    //1.進行非空判斷
    if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)){
        //說明沒有傳入任何參數(shù)
        return AjaxResult.fail(-1,"非法請求");
    }
    //2.查詢數(shù)據(jù)庫
    UserInfo userinfo = userService.getUserByName(username);
    if (userinfo != null && userinfo.getId() > 0) {
        //能獲得id就說明用戶名一定是在數(shù)據(jù)庫中,說明是有效用戶

        //使用自己寫的加鹽算法來判斷登錄
        //password是輸入的待驗證的明文密碼,userinfo.getPassword()得到的是數(shù)據(jù)庫中正確的最終密碼格式
        if (PasswordUtils.check(password,userinfo.getPassword())){
            //將用戶的session存儲下來
            //參數(shù)為true:要是沒有session就創(chuàng)建一個會話
            HttpSession session = request.getSession(true);
            //設(shè)置session的key和value
            session.setAttribute(ApplicationVariable.USER_SESSION_KEY,userinfo);
            //要是密碼正確,在將數(shù)據(jù)返回之前,考慮到隱私,隱藏密碼
            userinfo.setPassword("");
            return AjaxResult.success(userinfo);
        }
    }
    return AjaxResult.fail(0,null);
}

以上就是自己手寫的一個加鹽算法

實際上,springboot官方也提供了一種更加齊全的安全框架: spring security

spring security

要想使用spring security首先要先引入依賴(可以通過插件Edit Starters來引入依賴)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

在spring security框架中在項目啟動的時候,會自動注入登錄的頁面,在一般的項目中都是有自己的登錄頁面的,所以不需要自動注入登錄,所以要將其去掉

在項目的啟動類前面的@SpringBootApplication注解加上排除SecurityAutoConfiguration.class這個類對象就行了

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;

//關(guān)閉spring security的驗證
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class Demo3Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo3Application.class, args);
    }
}

在單元測試中使用spring security中的密碼加鹽算法

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@SpringBootTest
class Demo3ApplicationTests {

    @Test
    void contextLoads() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String str = "111";
        //進行加密
        String finalPassword = bCryptPasswordEncoder.encode(str);
        System.out.println(finalPassword);
        //驗證密碼
        String inputPassword1 = "123";
        String inputPassword2 = "111";
        //inputPassword是用戶輸入的密碼(待驗證),finalPassword是存儲在數(shù)據(jù)庫中的最終密碼格式
        System.out.println(bCryptPasswordEncoder.matches(inputPassword1,finalPassword));
        System.out.println(bCryptPasswordEncoder.matches(inputPassword2,finalPassword));
    }

}

image-20230412171450323

加密之后的最終密碼格式: $2a 10 10 10BXpuKmotUdqoS3rFE59anOTrSfk7gCYX5wfsg9ZblBHvc79EyVFOi

spring security中的最終密碼的格式:

image-20230412170137167

其實spring security的加鹽算法就是bCryptPasswordEncoder對象的encode方法和matches方法

加密的時候encode方法傳的參數(shù)是用戶輸入的密碼

解密(驗證)的時候,使用的matches方法的參數(shù)分別是用戶輸入的明文密碼 和 數(shù)據(jù)庫中最終密碼格式

所以自己手寫一個加鹽算法之后再去看spring security調(diào)用就會很簡單,因為思想都是一樣的,所以先理解實現(xiàn)思路很重要!

到此這篇關(guān)于Java實現(xiàn)加鹽算法的兩種方法的文章就介紹到這了,更多相關(guān)Java 加鹽算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java枚舉類的屬性、方法和構(gòu)造方法應(yīng)用實戰(zhàn)

    java枚舉類的屬性、方法和構(gòu)造方法應(yīng)用實戰(zhàn)

    這篇文章主要介紹了java枚舉類的屬性、方法和構(gòu)造方法應(yīng)用,結(jié)合實例形式分析了java枚舉類的定義、構(gòu)造及相關(guān)應(yīng)用操作技巧,需要的朋友可以參考下
    2019-08-08
  • 詳解Spring中Bean的生命周期和作用域及實現(xiàn)方式

    詳解Spring中Bean的生命周期和作用域及實現(xiàn)方式

    這篇文章主要給大家介紹了Spring中Bean的生命周期和作用域及實現(xiàn)方式的相關(guān)資料,文中介紹的非常詳細,對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-03-03
  • Java文件操作實例詳解

    Java文件操作實例詳解

    這篇文章主要為大家詳細介紹了Java文件操作實例,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Java 中文字符按Unicode排序的實現(xiàn)方法

    Java 中文字符按Unicode排序的實現(xiàn)方法

    這篇文章主要介紹了Java 中文字符按Unicode排序的實現(xiàn)方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-10-10
  • hashset去除重復(fù)值原理實例解析

    hashset去除重復(fù)值原理實例解析

    這篇文章主要介紹了hashset去除重復(fù)值原理實例解析,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • mybatis 運行時加載自定義mapper文件方式

    mybatis 運行時加載自定義mapper文件方式

    這篇文章主要介紹了mybatis 運行時加載自定義mapper文件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java制作專屬智能陪聊機器人詳解

    java制作專屬智能陪聊機器人詳解

    人工智能一直是最近的熱點話題,,這篇文章主要為大家詳細介紹了java實現(xiàn)智能陪聊機器人,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 淺談Java之Map 按值排序 (Map sort by value)

    淺談Java之Map 按值排序 (Map sort by value)

    下面小編就為大家?guī)硪黄獪\談Java之Map 按值排序 (Map sort by value)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • JavaWeb連接數(shù)據(jù)庫MySQL的操作技巧

    JavaWeb連接數(shù)據(jù)庫MySQL的操作技巧

    數(shù)據(jù)庫是編程中重要的一部分,它囊括了數(shù)據(jù)操作,數(shù)據(jù)持久化等各方面。在每一門編程語言中都占有相當(dāng)大的比例。本次,小編以MySQL為例,使用mvc編程思想,給大家講解下javaweb對數(shù)據(jù)庫的操作
    2017-02-02
  • IDEA如何加載resources文件夾下文件相對路徑

    IDEA如何加載resources文件夾下文件相對路徑

    這篇文章主要介紹了IDEA如何加載resources文件夾下文件相對路徑問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12

最新評論