【Spring篇】 项目加盐加密处理

目录

1.  MD5 加密算法

2.  加盐加密流程

3. Spring Security 实现加盐加密

1. 添加 Spring Security 框架

2. 关闭 Spring Security 认证 

3.实现加盐加密


1.  MD5 加密算法

       MD5 是 Message Digest Algorithm 的缩写,译为信息摘要算法,它是 Java 语言中使用很广泛的一种加密算法。MD5 可以将任意字符串,通过不可逆的字符串变换算法,生成一个唯一的 MD5 信息摘要,这个信息摘要也就是我们通常所说的 MD5 字符串。那么问题来了,MD5 安全吗?

答案是 MD5 并不安全 。

原因是 md 5 的每一位 原始密码都对应者着一位固定的密码,也就是说一个字符串的 MD5 永远是不变的,虽然说MD5并不可逆,但是可以被穷举出来,这里就 不得不介绍一下彩虹表了,当我们把每一位数的原始值对应的加密值在同一个列表中列举出来,就构成了一个彩虹表,

当我们知晓了 1 的 MD5 的值为  :c4ca4238a0b923820dcc509a6f75849b

2 的 MD5 的值为 :c81e728d9d4c2f636f067f89cc14862c ,这样我们就可以得到一张彩虹表用来存储

彩虹表
   原始值                                       加密值
       1            c4ca4238a0b923820dcc509a6f75849b
       2            c81e728d9d4c2f636f067f89cc14862c2

彩虹表通常用于恢复由有限集字符组成的固定长度的纯文本密码,也就是说,我们可以使用彩虹表来逐一穷举出原密码的每一位,所以在实际使用过程中数据库如果只是用 md5 进行加密,一把插了钥匙的锁一样不安全。

那么如何解决这种现象来实现加密呢? 

只需要使同一个字符串每一次生成的密码都不一样,实现的关键是使用随机数,也就是 加盐

2.  加盐加密流程

之前使用 MD5 不安全的原因是,每一个原始密码所对应的MD5 的值是固定的,那我们只需要让密码每次加盐之后,生成的最终的密码都不相同,这样就能解决加密不安全的问题了。

  • 使用  MD5 进行加密的流程是: 明文密码  -->     md5(明文密码)   --->  密码
  •  使用加盐加密的流程是 :

1. 构建期 :明文密码 + 随机盐值 

2 . md5(明文密码+随机盐值)

3.将盐值和加密之后的密码存储到数据库(存储到一个字段里边,自己约定一个规则来分离盐值和加密之后的密码)

在实际项目的开发过程中,因为需要将输入的密码和数据库中加盐加密的密码进行验证,所以我们需要在数据库中存入两样东西,一个是加盐加密之后的密码,另一个就是随机盐值

每一个随机盐值就对应了一个彩虹数据库,如果有n个随机盐值,就需要N个不同的彩虹数据库。

那使用这样的约定规则是否有泄漏密码的风险呢?

答案是肯定的,从理论上来讲,目前所有的安全手段都不是绝对安全的,破解上述的加盐密码数据库的破解成本远远高于收益,所以加盐加密的密码相对来说是比较安全的。

  • 模拟实现加盐加密:

实现规则:使用分隔符 $ 来分隔盐值和加密之后的密码

实现思路:将数据库中的 dbpassword 进行解密得到盐值,让用户输入的密码与该盐值进行加盐加密,最后和数据库中存的加盐加密之后的密码进行对比,如果两者相同说明密码匹配,如果两者不同,则说明密码不匹配。

加盐的具体实现步骤:

  1. 使用 UUID 产生一个随机盐值;
  2. 将随机盐值 + 原始密码一起 MD5,产生一个新密码(相同的原始密码,每次都会生成一个不同的新密码);
  3. 将随机盐值 + "$"+上一步生成的新密码加在一起,就是最终生成的密码。

验证加盐加密的具体实现:

  1.  获取数据库中 dbpassword 中的盐值
  2. 用相同的加密方式和步骤,生成一个最终密码和和数据库中保存的加密密码进行对比。
  3. 对比的结果相同,则密码输入正确

/**
 *
 * 密码工具类
 * 实现加盐加密 / 加盐解密
 */
public class PasswordTools {
    /**
     * 加密(加盐处理)
     * @param password 待加密密码(需要加密的密码)
     * @return 加密后的密码
     */
    public static String encrypt(String password) {
        // 随机盐值 UUID
        String salt = UUID.randomUUID().toString().replaceAll("-", "");
        // 密码=md5(随机盐值+密码)
        String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
//        return salt + "$" + finalPassword;
        String dbPassword = salt + "$" + finalPassword;
        return dbPassword;
    }

    /**
     * 解密
     * @param password       要验证的密码(未加密)
     * @param  dbPassword 数据库中的加了盐值的密码
     * @return 对比结果 true OR false
     */
    public static boolean decrypt(String password, String dbPassword) {
        boolean result = false;
        if (StringUtils.hasLength(password) && StringUtils.hasLength(dbPassword)) {
            if (dbPassword.length() == 65 && dbPassword.contains("$")) {
                String[] dbPasswordArr = dbPassword.split("\\$");
                // 盐值
                String salt = dbPasswordArr[0];
                String finalPassword = dbPasswordArr[1];
                // 使用同样的加密算法和随机盐值生成最终加密的密码
                password = DigestUtils.md5DigestAsHex((salt + password).getBytes());
                if (finalPassword.equals(password)) {
                    result = true;
                }
            }
        }
        return result;
    }
}

下面使用一组用例来测试上述代码是否实现了加盐加密和解密验证的过程,此处假定用户的明文密码为 :1234567 

public class Main{
    public static void main(String[] args){
        String password = "1234567";
        String dbPassword = encrypt(password);
        System.out.println(dbPassword);
        Scanner s = new Scanner(System.in);
        while(s.hasNext()){
            String str = s.nextLine();
            boolean flg = decrypt(str,dbPassword);
            System.out.println(flg);
        }
    }
}

 以上程序模拟实现了密码加盐加密的过程和进行解密验证的过程,Spring 中内置了 Spring Security 框架,可以很方便的使用相应的方法。

3. Spring Security 实现加盐加密

1. 添加 Spring Security 框架

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

2. 关闭 Spring Security 认证 

如果不关闭 Spring Security 认证的话,就会访问  Spring Security 提供的内置的登录页面,用户名和默认的密码会在控制台打印。

但是此处我们不需要Spring Security 的登录页面,所以需要在启动类中修改,来关闭 Spring Security 的 授权(自动类加载) 

3.实现加盐加密

使用 BCryptPasswordEncoder 类中的 encode() 方法来实现项目的加盐加密,使用 matches ()方法来实现项目的解密验证。

public class Main{ 
public static void main(String[] args) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = "12345";
        String dbPassword = passwordEncoder.encode(password);
        System.out.println(dbPassword);
        Scanner s = new Scanner(System.in);
        while(s.hasNext()){
            String str = s.nextLine();
            System.out.println(passwordEncoder.matches(str,dbPassword));
        }
    }
}

项目登录注册功能实现加盐加密和验证:


@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    private PasswordEncoder passwordEncoder;  // 注入密码加密器

    /**
     * 实现项目注册功能
     * @param userInfo
     * @return
     */
    @RequestMapping("/reg")
    public AjaxResult reg(UserInfo userInfo) {
        // 进行非空判断
        if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername()) ||
                !StringUtils.hasLength(userInfo.getPassword()))
            return AjaxResult.fail(-1, "参数有误");

        // 对密码进行加盐加密
        String salt = generateSalt();  // 生成盐值
        String encryptedPassword = passwordEncoder.encode(userInfo.getPassword() + salt);  // 加盐加密密码
        userInfo.setPassword(encryptedPassword);  // 更新用户对象的密码为加密后的密码
        userInfo.setSalt(salt);  // 设置盐值

        // 调用 UserService 执行添加方法,并将返回的结果添加 AjaxResult.data 进行返回
        int result = userService.reg(userInfo);
        return AjaxResult.success(result);
    }

    /**
     * 实现项目登录功能
     * @param username
     * @param password
     * @param request
     * @return
     */
    @RequestMapping("/login")
    public AjaxResult login(String username, String password,
                            HttpServletRequest request) {
        if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password))
            return AjaxResult.fail(-1, "参数有误");

        UserInfo userInfo = userService.login(username);
        if (userInfo == null || userInfo.getId() <= 0)
            return AjaxResult.fail(-2, "用户名或密码输入错误!");

        // 使用密码加密器验证密码是否匹配(包括盐值和加密密码的比较)
        boolean passwordMatch = passwordEncoder.matches(password + userInfo.getSalt(), userInfo.getPassword());
        if (!passwordMatch)
            return AjaxResult.fail(-2, "用户名或密码输入错误!");

        // 将当前成功登录的用户信息,存储到 session 中去
        HttpSession session = request.getSession();
        session.setAttribute(ApplicationVariable.SESSION_KEY_USERINFO, userInfo);
        return AjaxResult.success(1);
    }

    // 生成随机盐值的方法
    private String generateSalt() {
        // 根据需要选择适合您的盐值生成方法,这里使用UUID作为示例
        return UUID.randomUUID().toString().replace("-", "");
    }
}

当我们注册新用户时,用户的明文密码就会以加盐加密的密码来进行存储,同时也会存储密码加盐时使用的盐值,登录界面时使用存储的盐值来进行用户的登录验证。

 当用户登陆时输入的密码,与存储的盐值进行加盐加密之后的密码 和数据库中存储的用户注册时存储的加盐加密的密码相匹配时,用户登录验证成功。


 总结: 

进行项目的密存储时,不能只是简单的使用 md5 进行加密处理,需要使用随机盐值结合原始密码一起进行 md5 得到加盐加密之后的密码,然后将加盐加密之后的密码和盐值分别存储到数据库当中,这样才真正实现了项目的加盐加密。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/390764.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QGIS004:【08图层工具箱】-导出到电子表格、提取图层范围

摘要&#xff1a;QGIS图层工具箱常用工具有导出到电子表格、提取图层范围等选项&#xff0c;本文介绍各选项的基本操作。 实验数据&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ZK4_ShrQ5BsbyWfJ6fVW4A?pwdpiap 提取码&#xff1a;piap 一、导出到电子表格 工具…

【Web】CTFSHOW java刷题记录(全)

目录 web279 web280 web281 web282 web283 web284 web285 web286 web287 web288 ​web289 web290 web291 web292 web293 web294 web295 web296 web297 web298 web299 web300 web279 题目提示 url里告诉我们是S2-001 直接进行一个exp的搜 S2-001漏洞分析…

文件夹删不掉,显示在另一个文件中打开怎么办

问题&#xff1a; 一、想要删掉这个文件夹&#xff0c;却因为文件夹中的文件打开了删不掉&#xff0c;这里我因为做的测试&#xff0c;所以是知道打开了什么 二、一般情况下文件比较多时&#xff0c;是不知道打开了什么的&#xff0c;长这个样子 解决&#xff1a; 一、打开任…

JAVA面试题并发篇

1. 线程状态 要求 掌握 Java 线程六种状态 掌握 Java 线程状态转换 能理解五种状态与六种状态两种说法的区别 六种状态及转换 分别是 新建 当一个线程对象被创建&#xff0c;但还未调用 start 方法时处于新建状态 此时未与操作系统底层线程关联 可运行 调用了 start 方法…

初识数据库:探索数据的世界

初识数据库&#xff1a;探索数据的世界 1. 什么是数据库&#xff1f;2. 数据库的类型2.1 关系型数据库&#xff08;RDBMS&#xff09;2.2 非关系型数据库&#xff08;NoSQL&#xff09; 3. 为什么使用数据库&#xff1f;4. 如何选择合适的数据库&#xff1f;5. 结语 在信息技术…

【TC3xx芯片】TC3xx芯片SMU模块详解

目录 前言 正文 1.SMU功能概述 1.1 SMU架构 1.2 SMU_core 1.3 SMU_stdby 2. SMU功能详述 2.1 SMU_core 2.1.1 Reset类型 2.1.2 接口&#xff08;Interfaces&#xff09;概述 2.1.2.1 SMU_core到SCU的接口 2.1.2.2 SMU_core到IR的接口 2.1.2.3 SMU_core到Ports(Err…

Python绘制折线图、散点图...Pyplot库功能使用示例大全

matplotlib.pyplot库功能使用示例&#xff0c;Python绘制折线图、散点图... 1、简单折线图示例2、设置中文字符&#xff0c;解决乱码问题3、添加标记格式4、添加y值标记5、添加图例6、设置字体大小7、设置坐标轴起点数值8、绘制多条折线9、散点图基础示例 matplotlib.pyplot库是…

解析工信部印发的《工业控制系统网络安全防护指南》

文章目录 前言工业控制系统网络安全防护指南一、安全管理&#xff08;一&#xff09;资产管理&#xff08;二&#xff09;配置管理&#xff08;三&#xff09;供应链安全&#xff08;四&#xff09;宣传教育 二、技术防护&#xff08;一&#xff09;主机与终端安全&#xff08;…

tf.linspace时出现Could not find valid device for node.

背景&#xff1a; 在使用tensorflow2.x的时候,当使用tf.linspace的时候会出现如下的报错&#xff1a; import os os.environ[TF_CPP_MIN_LOG_LEVEL] 2import tensorflow as tf from tensorflow import keras import numpy as npdef out():# x tf.constant(np.arange(12).re…

Python爬虫之Splash详解

爬虫专栏&#xff1a;http://t.csdnimg.cn/WfCSx Splash 的使用 Splash 是一个 JavaScript 渲染服务&#xff0c;是一个带有 HTTP API 的轻量级浏览器&#xff0c;同时它对接了 Python 中的 Twisted 和 QT 库。利用它&#xff0c;我们同样可以实现动态渲染页面的抓取。 1. 功…

【51单片机】AD模数转换DA数模转换(江科大)

1.AD/DA介绍 AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号 DA(Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号 AD/DA转换打开了计算机与模拟信号的大门,极大的提高了计算机系统的应用范围,也为模拟信号数字化处理…

常用的正则表达式,收藏必备!!!

正则表达式是一种强大的文本模式匹配工具&#xff0c;用于在字符串中查找、替换和验证特定模式的文本。下面是一些常用的正则表达式示例&#xff1a; 匹配Email地址&#xff1a; ^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$匹配URL&#xff1a; ^(https?|ftp)://[^\s/$.?#…

【python】python入门(变量名)

Hi~ o(*&#xffe3;▽&#xffe3;*)ブ今天一起来看看python入门之变量名吧~~ 变量名的规定&#xff1a; 举个例子&#xff1a; “违法”的变量名们 my love/my &#xff01;love错误&#xff1a;中间不能是空格或者其他符号1my_love错误&#xff1a;不能数字开头"my_l…

BUGKU-WEB bp

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 提示说&#xff1a;弱密码top1000&#xff1f;z???(爆破?)先看看源码有没有提示 相关工具 Burp Suit 爆破top1000字典&#xff0c;点击下载 解题步骤 随便测试账号密码admin、admin 得到提…

java8-重构、测试、调试

8.1.1 改善代码的可读性 改善代码的可读性到底意味着什么?我们很难定义什么是好的可读性&#xff0c;因为这可能非常主观。通常的理解是&#xff0c;“别人理解这段代码的难易程度”。改善可读性意味着你要确保你的代码能非常容易地被包括自己在内的所有人理解和维护。为了确保…

巨抽象的前端vue3

根据实践证明&#xff0c;越是简单的问题&#xff0c;越容易造成大bug 一个自定义组件的路径就废了我老半天了 各种查询&#xff0c;各种百度&#xff0c;各种问&#xff0c;结果规规矩矩去导入组件路径&#xff0c;成了&#xff01; 错误代码&#xff1a; <script setu…

第七篇【传奇开心果系列】Python微项目技术点案例示例:数据可视化界面图形化经典案例

传奇开心果微博系列 系列微博目录Python微项目技术点案例示例系列 微博目录一、微项目开发背景和项目目标&#xff1a;二、雏形示例代码三、扩展思路介绍四、数据输入示例代码五、数据分析示例代码六、排名统计示例代码七、数据导入导出示例代码八、主题定制示例代码九、数据过…

linux系统下vscode portable版本的c++/Cmake环境搭建002:使用 VSIX 安装VSCODE插件(暂记)

使用 VSIX 安装VSCODE插件 在 Visual Studio Code (VSCode) 中&#xff0c;你可以通过以下步骤离线安装插件&#xff1a; 获取插件的 VSIX 文件&#xff1a; 在一个联网环境中&#xff0c;访问 Visual Studio Code Marketplace&#xff0c;搜索并找到你想要的插件。 比如&am…

谷歌内部开发AI大语言模型“鹅”;OpenAI CEO 寻求大规模AI芯片全球生产投资

&#x1f989; AI新闻 &#x1f680; 谷歌内部开发AI大语言模型“鹅” 摘要&#xff1a;谷歌正在积极将AI技术融入其产品中&#xff0c;并为提升员工效率而开发了一个名为“鹅”的AI大语言模型。这一模型仅供公司内部团队使用&#xff0c;旨在辅助新产品的开发。据悉&#xf…

Leetcode1423.可获得的最大点数

文章目录 题目原题链接思路&#xff08;逆向思维&#xff09; 题目 原题链接 Leetcode1423.可获得的最大点数 思路&#xff08;逆向思维&#xff09; 由题目可知&#xff0c;从两侧选k张&#xff0c;总数为n张&#xff0c;即从中间选n - k张 nums总和固定&#xff0c;要选k张最…