数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!

简介: 本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。

需求分析

在MySQL数据库中,我们常常需要对密码,⾝份证号,⼿机号等敏感信息进⾏加密,以保证数据的安全性.

如果使⽤明⽂存储,当⿊客⼊侵了数据库时,就可以轻松获取到⽤⼾的相关信息,从⽽对⽤⼾或者企业造 成信息泄漏或者财产损失.

⽬前我们⽤⼾的密码还是明⽂设置的,为了保护⽤⼾的密码信息,我们需要对密码进⾏加密

常用案例举例

比如常见的注册,当用户把账号密码发过来后,我们就可以对密码进行加盐加密,以下面这种形式存储在数据库中,这样大大增强了我们密码的安全性

经过MD5加密后的密⽂⽆法解密,但相同的密码经过MD5哈希之后的密⽂是相同的

理论上这个密文是无法破解的,只可以通过彩虹表(简单理解为字典)来查询,只不过彩虹表目前只能查到非常简单的密文的原密码,比如 1,2,3 哈哈

加盐加密逻辑+如何对比原数据(必看)

首先需要知道加盐是什么,加盐就相当于我们除了原密码的基础上给予了一个手动的盐值,来进行二次加密

官方回答:采⽤为⼀个密码拼接⼀个随机字符来进⾏加密,这个随机字符我们称之为"盐"

经过MD5加密后的密⽂⽆法解密,但相同的密码经过MD5哈希之后的密⽂是相同的

理论上这个密文是无法破解的,但因为相同的密码经过MD5哈希之后的密⽂是相同的,所以可以通过彩虹表(简单理解为字典)来查询,只不过彩虹表目前只能查到非常简单的密文的原密码,比如 1,2,3 哈哈

此片博客我们采用的加密算法是MD5算法

加密逻辑:

解密逻辑:

还是那句话,MD5本身是没法解密的

但同样的数据通过加密后密文是一样的,我们就可以通过这个逻辑来进行密文的对比验证

手写加密算法 —— 用md5 +盐值

首先,需要注意的是,我们这个虽然是手写,但其实还是用了md5的算法,毕竟加密这种数学逻辑,要想做到安全,肯定要用经过无数验证和推敲的算法。自己写的还是不太敢用的哈哈

导入依赖

我这里用的这个只要是个Spring项目,都可以直接用

代码如下:

绝对能用哦

注释写的特别全面,若有问题及时联系博主,博主看到会立即回复的

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


import java.util.UUID;

// md5 本身是不可逆的,只不过可以用彩虹表查询,因为同一个字符串用md5加密后生成的密码是固定的
// 密码工具类
// 加盐加密 / 加盐解密
public class PasswordTools {
    /**
     *   加盐加密
     * @param password   明文密码
     * @return           加盐加密的密码
     */
    public static String encrypt(String password) {
        // 1、产生盐值  此处产生去掉-后 32 位的盐值
        String salt = UUID.randomUUID().toString().replace("-","");
        System.out.println("盐值:" + salt);
        // 2、使用(盐值+明文密码)得到加密的密码
        // getBytes() 括号里设置编码 因为盐值没有中文,所以这里无需设置utf8
        // 此处加密后的密码是 32位
        String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
        // 3、将盐值和加密的密码共同返回(合并盐值和加密密码)
        // 总共 65 位
        String dbPassword = salt + "$" + finalPassword;
        return dbPassword;
    }

    /**
     *  接收传入的盐值进行加密
     * @param password  明文密码
     * @param salt      盐值
     * @return          加盐加密的密码
     */
    public static String encrypt(String password,String salt) {
        // 1、使用(盐值+明文密码)得到加密的密码
        // getBytes() 括号里设置编码 因为盐值没有中文,所以这里无需设置utf8
        // 此处加密后的密码是 32位
        String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
        // 2、将盐值和加密的密码共同返回(合并盐值和加密密码)
        // 总共 65 位
        String dbPassword = salt + "$" + finalPassword;
        return dbPassword;
    }

    /**
     * 解密(对比密码是否正确)
     * @param password    明文密码(不一定对,需要验证明文密码)
     * @param dbPassword  数据库存储的密码(包含:salt+$+加盐加密密码)
     * @return       true=密码正确
     */
    public static boolean decrypt(String password, String dbPassword){
        boolean result = false;
        if(StringUtils.hasLength(password) && StringUtils.hasLength(dbPassword) &&
                dbPassword.length() == 65 && dbPassword.contains("$")) {  // 参数正确
            // 1、得到盐值
            String[] passwordArr = dbPassword.split("\\$");
            // 1.1、盐值
            String salt = passwordArr[0];
//            // 1.2、得到正确密码的加盐加密密码
//            String finalPassword = passwordArr[1];
            // 2、生成验证密码的加盐加密密码
            String checkPassword = encrypt(password, salt);
            if (dbPassword.equals(checkPassword)) {
                result = true;
            }
        }
        return result;
    }
    //    // 测试
    public static void main(String[] args) {
        String password = "123456";

        String dbpwd1 = PasswordTools.encrypt(password);
        String dbpwd2 = PasswordTools.encrypt(password);
        String dbpwd3 = PasswordTools.encrypt(password);

        System.out.println(dbpwd1);
        System.out.println(dbpwd2);
        System.out.println(dbpwd3);

        String cPwd = "12345";
        boolean result = PasswordTools.decrypt(cPwd, dbpwd1);
        System.out.println("错误对比结果 ->" + result);

        boolean result2 = PasswordTools.decrypt(password, dbpwd2);
        System.out.println("正确对比结果 ->" + result2);
    }
}

调用封装好的

用这个必须阅读下面的注意事项!!!

导入依赖

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

代码如下:

我们用到了 BCryptPasswordEncoder 这个类,它提供了封装好的加盐加密、对比密码等操作

需要注意的是,BCryptPasswordEncode不支持指定的盐值,盐值是它内部自己的算法生成的,确保即使是相同的数据加盐加密后也能得到不同的密文

虽然得到的是不同的密文。但使用它内置的matches函数仍然可以对比验证密码,得到我们想要的结果

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;


// md5 本身是不可逆的,只不过可以用彩虹表查询,因为同一个字符串用md5加密后生成的密码是固定的
// 密码工具类
// 加盐加密 / 加盐解密
public class PasswordTools {
    public static void main(String[] args) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String password = "123456";
        // encode 就是 加盐加密的意思
        String dbpwd1 = passwordEncoder.encode(password);
        String dbpwd2 = passwordEncoder.encode(password);
        String dbpwd3 = passwordEncoder.encode(password);

        System.out.println(dbpwd1);
        System.out.println(dbpwd2);
        System.out.println(dbpwd3);

        // 对比(验证密码是否正确)
        String cPwd = "12345";
        boolean result = passwordEncoder.matches(cPwd, dbpwd1);
        System.out.println("错误对比结果 ->" + result);

        boolean result2 = passwordEncoder.matches(password, dbpwd2);
        System.out.println("正确对比结果 ->" + result2);
    }
}

必须阅读!—— 注意事项

当使用封装好的BCryptPasswordEncoder这个类时,需要引入security这个框架/依赖,随之而来的有一个非常重要的问题,或者说现象

你会发现启动SpringBoot项目后,很多接口都会返回401,这是因为security这个安全框架发挥了作用,但很明显我们并不想让所有接口返回401,因此我们启动类要加上这个注解

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)

当然,SpringBoot项目启动类本身就有@SpringBootApplication这个注解,但没有括号里的值,你可以直接复制这个替换你的@SpringBootApplication注解,也可以单独加上括号中的值

🧸前路漫漫,愿星光与您相伴!

目录
相关文章
|
17天前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
1月前
|
SQL 数据库 数据安全/隐私保护
数据库数据恢复——sql server数据库被加密的数据恢复案例
SQL server数据库数据故障: SQL server数据库被加密,无法使用。 数据库MDF、LDF、log日志文件名字被篡改。 数据库备份被加密,文件名字被篡改。
|
27天前
|
存储 JavaScript 前端开发
在NodeJS中使用npm包进行JS代码的混淆加密
总的来说,使用“javascript-obfuscator”包可以帮助我们在Node.js中轻松地混淆JavaScript代码。通过合理的配置,我们可以使混淆后的代码更难以理解,从而提高代码的保密性。
100 9
|
5月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
806 65
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
3月前
|
人工智能 JavaScript 关系型数据库
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
146 14
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
|
2月前
|
SQL druid Oracle
【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常
客户Java日志中出现异常,影响Druid的merge SQL功能(将SQL字面量替换为绑定变量以统计性能),但不影响正常业务流程。原因是Druid在merge SQL时传入null作为dbType,导致无法解析递归查询中的`start`关键字。
|
3月前
|
人工智能 JavaScript 安全
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
159 13
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
|
3月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
286 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
4月前
|
存储 缓存 Java
Java中的分布式缓存与Memcached集成实战
通过在Java项目中集成Memcached,可以显著提升系统的性能和响应速度。合理的缓存策略、分布式架构设计和异常处理机制是实现高效缓存的关键。希望本文提供的实战示例和优化建议能够帮助开发者更好地应用Memcached,实现高性能的分布式缓存解决方案。
90 9
|
4月前
|
Java API Apache
java集成stable diffusion
通过REST API和JNI两种方法,我们可以在Java应用程序中集成Stable Diffusion模型。REST API方法更加简单和易于维护,而JNI方法则提供更高的性能。根据具体应用场景和需求,选择合适的集成方法,可以充分利用Stable Diffusion的强大功能,实现高效的图像生成和处理。
113 15
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等