哈希密码的加盐强化

news2024/12/28 2:11:35

🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

欢迎志同道合的朋友一起加油喔🤺🤺🤺


目录

一、什么是哈希加密?

二、哈希加密的问题

三、加盐哈希加密

四、Java中的加盐哈希加密实践

1. 加盐加密代码实例

2. 验证加盐加密的密码代码实例

五、MD5加密流程对比加盐加密流程

MD5加密流程:

加盐加密流程:

六、spring框架实现加盐加密



在当今的信息时代,数据安全的重要性不言而喻。我们的系统中包含了许多敏感数据,其中就包括用户的密码。尽管密码是敏感的,但直接存储明文密码会导致严重的安全问题。因此,对密码进行哈希加密以提供更好的安全性是常见的做法。在这篇文章中,我将带你深入理解加盐哈希加密算法,并演示如何在Java中实现它。

一、什么是哈希加密?

哈希加密是一种通过哈希函数对输入数据进行转换,输出一个固定长度的字符串的过程。这个输出称为哈希值或者哈希码。哈希函数具有以下特性:

  • 同样的输入将产生同样的输出。
  • 不同的输入尽可能产生不同的输出。
  • 无法从哈希值反推回输入值。

对于密码存储来说,哈希加密非常有用。我们将用户的明文密码通过哈希函数转换为哈希值,然后将这个哈希值存储在数据库中,而非明文密码。在验证用户身份时,我们只需要将用户输入的密码经过同样的哈希函数,然后比较哈希值是否一致即可。

二、哈希加密的问题

然而,纯粹的哈希加密也有其弱点。如果两个用户使用相同的密码,那么他们的哈希值也将相同。这就意味着,如果一个用户的哈希密码被泄露,那么使用相同密码的其他用户也会受到威胁。此外,由于哈希函数是公开的,黑客可以通过“彩虹表”攻击预先计算并存储哈希值与原始密码的对应关系,从而反推出明文密码。

彩虹表是一种用于破解哈希函数的预计算表。它包含了许多预计算的哈希值和对应的原始数据(密码)。攻击者可以通过比对彩虹表,找出与泄露的哈希值相匹配的原始数据,从而破解出原始密码。这种攻击方式对于那些使用简单密码的用户尤其有效,因为这些简单密码很可能已经被包含在彩虹表中。

三、加盐哈希加密

  • 为了防止彩虹表攻击,就出现了"加盐"的概念。"加盐"指的是在用户密码哈希之前,先将一个额外的随机数据(称为“盐”)添加到用户密码中。然后,将这个新的字符串(即原始密码+盐)进行哈希,得到的结果再存储到数据库中。同时,这个“盐”也需要被存储,以便在验证密码时使用
  • 加盐的目的是,即使两个用户使用相同的密码,由于"盐"的随机性,他们的哈希值也会是不同的这使得攻击者不能使用彩虹表进行攻击,因为他们需要为每个可能的盐值构建一个新的彩虹表,这在实践中是非常困难的
  • 在实际应用中,为了增加破解的难度,"盐"的值通常会足够长,并且每次用户更改密码时,都会生成新的"盐
  • 所以,简单来说,"加盐"加密就是给你的密码加点"调料",让每个人的密码都有独特的味道,这样就算有人偷偷尝试了你的密码,他们也尝不出原始的味道。

为什么说一个盐值对应一个彩虹表呢?

  1. 哈希算法中,"key"是你要加密的原始数据(例如密码),而"value"是生成的哈希值。盐值的加入会改变原始数据(也就是"key"),从而导致生成的哈希值(也就是"value")发生变化。
  2. 如果攻击者只知道哈希值,而不知道盐值,那么他就无法通过查找彩虹表(即通过哈希值查找原始密码)来获取原始密码,因为彩虹表是基于未加盐的密码生成的。
  3. 换句话说,即使攻击者拥有一份完整的彩虹表(这已经非常难以实现了),如果他不知道盐值,他仍然无法通过哈希值找到原始的密码,因为彩虹表中的所有哈希值都是对未加盐的密码进行哈希运算得到的。
  4. 总的来说,每个盐值对应一张彩虹表的原因在于盐值的加入改变了密码的哈希值,使得攻击者不能再用一张彩虹表来破解所有用户的密码,而需要为每个盐值分别创建一张彩虹表。

四、Java中的加盐哈希加密实践

接下来,我将以Java为例,介绍如何实现加盐加密验证加盐加密密码

1. 加盐加密代码实例

/**
   * 加盐加密
   * @param password 明文密码
   * @return 加盐加密的密码
   */
public static String encrypt(String password) {
    // 这是一个静态方法,输入的参数是你想要加密的原始密码。
    
    //1.产生盐值
    String salt = UUID.randomUUID().toString().replace("-","");
    // UUID.randomUUID().toString() 用于生成一个随机的唯一识别码,这个码的格式是一个32位的数字,包含四个"-"。
    // replace("-","") 是为了将这些"-"去除,得到一个完全由数字和字母组成的32位字符串,这就是所谓的"盐值"。

    //2.使用(盐值+明文密码) 得到加密的密码
    String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
    // salt + password 是将盐值和密码拼接在一起,getBytes() 方法是将拼接后的字符串转化为字节数组,以便后面进行哈希运算。
    // DigestUtils.md5DigestAsHex 是Spring框架提供的一个工具类,用于进行MD5哈希运算,并将结果转化为16进制的字符串。
    // 这样我们就得到了加盐后的密码。

    //3.将盐值和加密的密码共同返回(合并盐值和加密码)
    String dbPassword = salt + "$" + finalPassword;
    // 最后,我们将盐值、一个"$"和加密后的密码拼接在一起,这样在验证密码时,我们可以知道盐值是什么。
    // "$"在这里是作为盐值和密码之间的分隔符,也可以选择其他不会在盐值和密码中出现的字符。

    return dbPassword;
    // 将最终的字符串返回,这就是存入数据库的密码。
}

通过这种方法,即使两个用户的原始密码相同,他们在数据库中存储的密码也会不同,因为盐值是随机生成的。同时,由于盐值是与密码一同存储的,所以在验证密码时也能知道盐值是什么,从而正确地验证密码。

2. 验证加盐加密的密码代码实例

/**
 * 验证加盐加密密码
 * @param password  明文密码(不一定对, 需要验证明文密码)
 * @param dbPassword 数据库存储的密码(包含: salt+$+加盐加密密码)
 * @return
 */
public static boolean decrypt(String password, String dbPassword) {
    // 这个方法是静态方法,输入参数是用户输入的待验证密码和数据库中存储的密码。方法将返回一个布尔值,表示密码是否正确。
    
    boolean result = false;
    // 默认的结果是 false,也就是默认密码是错误的。

    if(StringUtils.hasLength(password) && StringUtils.hasLength(dbPassword)
            && dbPassword.length() == 65 && dbPassword.contains("$")) {  //参数正确
        // 这个if语句是进行一些基本的参数检查,检查输入的密码和数据库中存储的密码是否都不为空,
        // 数据库中存储的密码长度是否是65(因为盐值长度是32,加密后的密码长度也是32,再加上一个"$",总长度就是65),
        // 以及数据库中存储的密码是否包含"$"。

        //1. 得到盐值
        String[] passwordArr = dbPassword.split("\\$");
        // 使用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;
        }
        // 如果待验证的加盐后的密码和数据库中存储的加盐后的密码相等,那么说明密码正确,将结果设为true。
    }

    return  result;
    // 返回验证结果。
}

这种方法的优点是即使攻击者拿到了数据库中存储的密码和盐值,也无法直接知道原始的密码是什么,因为加盐后的密码和原始的密码是通过不可逆的哈希函数得到的。只有知道了原始的密码,才能通过同样的加盐和哈希操作得到同样的结果,从而验证密码是否正确。

五、MD5加密流程对比加盐加密流程

  1. MD5加密流程:

    • 用户在输入密码后,系统首先将用户的密码作为输入参数传给MD5函数。

    • MD5函数会对输入进行一系列复杂的数学运算,生成一个128位的哈希值,也就是我们所说的MD5值。

    • 这个MD5值通常以32位的十六进制数表示,我们将这个值存储在数据库中。

    • 当用户下次登录时,系统会再次将输入的密码进行MD5运算,并将得到的MD5值与存储在数据库中的值进行比较。如果两者相同,则验证成功,用户登录成功。

  2. 加盐加密流程:

    • 首先,系统会生成一个随机的字符串,我们称之为"盐"。

    • 然后,系统会将用户输入的密码和这个盐值拼接在一起,形成一个新的字符串。

    • 这个新的字符串会作为输入参数传给哈希函数,通常我们仍然可以使用MD5函数或者其他更安全的哈希函数如SHA-256。

    • 哈希函数会对这个新的字符串进行哈希运算,得到一个哈希值。我们将这个哈希值和盐值一起存储在数据库中。

    • 当用户下次登录时,系统会将用户输入的密码和存储在数据库中的盐值进行拼接,并进行哈希运算。然后将得到的哈希值与存储在数据库中的哈希值进行比较。如果两者相同,则验证成功,用户登录成功。

加盐加密在MD5的基础上增加了一个随机的盐值,这样就使得即使两个用户的密码相同,他们的哈希值也会因为盐值的不同而不同。这大大增加了破解的难度,因为攻击者现在需要针对每一个盐值都进行一次攻击,而不能像攻击MD5那样只需要一次攻击就可以破解所有密码。

六、spring框架实现加盐加密

Spring Security是Spring框架下的一个子框架,它主要负责应用程序的安全性,包括身份验证和授权。在Spring Security中,有一个类BCryptPasswordEncoder,可以用于使用加盐的BCrypt算法对密码进行哈希。

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

public class PasswordEncoderUtil {
    
    private static BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    //加密密码
    public static String encodePassword(String rawPassword) {
        return passwordEncoder.encode(rawPassword);
    }

    // 验证密码
    public static boolean matches(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

}

在上述代码中,BCryptPasswordEncoder类用于创建基于BCrypt的加盐哈希密码。在创建对象时,BCryptPasswordEncoder会自动在每次加密时生成一个随机盐,并将其合并到哈希值中。对于相同的明文,每次生成的加密文本都会不同。

在密码验证时,matches()方法会自动从存储的哈希值中提取盐,与提供的明文密码一起进行哈希运算,并将结果与存储的哈希值进行比较。

在使用上述工具类对密码进行加密后,你可以将加密后的密码存储在数据库中。当需要验证密码时,只需调用matches()方法进行验证即可。

 下面是如何使用Spring Security进行加盐哈希密码的步骤解析:

1. 在你的项目中,需要先在POM.xml文件或build.gradle中加入Spring Security的依赖。对于Maven项目,你可以在POM.xml中添加以下代码:

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

2. 创建一个BCryptPasswordEncoder对象:

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

3. 你可以使用BCryptPasswordEncoder对象的encode方法对密码进行哈希:

String hashedPassword = passwordEncoder.encode(plainPassword);

其中plainPassword是原始的未加密的密码。encode方法会对原始密码进行BCrypt哈希,并添加一个随机的盐值。然后,你可以将hashedPassword保存到数据库中。

4. 当需要验证密码时,你可以使用BCryptPasswordEncoder对象的matches方法:

boolean isPasswordMatch = passwordEncoder.matches(rawPassword, hashedPassword);

其中rawPassword是用户输入的密码,hashedPassword是存储在数据库中的哈希密码。matches方法会先将存储在哈希密码中的盐值添加到用户输入的密码上,然后进行哈希,最后将哈希后的结果和存储在数据库中的哈希密码进行比较。如果两者相同,那么matches方法将返回true,否则返回false

注意,Spring Security使用的BCrypt算法已经内置了添加和使用盐值的机制,你不需要自己生成和存储盐值。这大大简化了使用加盐哈希密码的流程。

如果你觉得这篇文章有价值,或者你喜欢它,那么请点赞并分享给你的朋友。你的支持是我创作更多有用内容的动力,感谢你的阅读和支持。祝你有个美好的一天!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

讯飞星火大模型详细内测体验:看它能否应对这些挑战?

名人说&#xff1a;一花独放不是春&#xff0c;百花齐放花满园。——《增广贤文》 作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、简要介绍二、分类问题测试0️⃣自我介绍1️⃣语言理解2️⃣知识问答3️⃣逻辑推…

“房地一体”专用系列:DG3M、D2M产品发布

基于“房地一体”项目的作业特点&#xff0c;睿铂听取客户作业过程中的需求反馈&#xff0c;在D2PSDK、D3PSDK基础之上推出全新中端产品&#xff1a;D2M和DG3M。 D2M适用于地势平坦区域的房地一体项目&#xff0c;DG3M适用于落差较大场景的房地一体项目和智慧城市三维建模项目…

【面试】标准库相关题型(二)

文章目录 1. deque底层实现原理1.1 概述1.2 原理图1.3 类结构1.4 操作函数 2. 什么时候使用vector、list、deque2.1 vector2.2 list2.3 deque 3. priority_queue的底层实现原理3.1 一句话概括&#xff1a;用堆来实现优先级队列3.2 堆结构3.3 底层容器3.4 STL对堆结构提供的接口…

计算机网络-物理层

目录 一、物理层的基本概念 二、物理层下的传输媒体 &#xff08;一&#xff09;引导型传输媒体 &#xff08;二&#xff09;非引导型传输媒体 三、传输方式 &#xff08;一&#xff09;串行传输和并行传输 &#xff08;二&#xff09;同步传输和异步传输 &#xff08;…

STL之位图(bitset)

目录 位图bitset介绍bitset使用 模拟实现位图的应用——题目总结 位图 bitset介绍 参考文档:bitset 在 C STL 中&#xff0c;std::bitset 是一个固定大小的容器类&#xff0c;用于表示二进制位序列。它可以被看作是一个长度固定为 N 的布尔数组&#xff0c;其中每个元素只有两…

[Selenium] 通过Java+Selenium查询文章质量分

文章目录 前言一、环境准备二、查询文章质量分2.1、修改pom.xml配置2.2、配置Chrome驱动2.3、引入浏览器配置2.4、设置无头模式2.5、启动浏览器实例&#xff0c;添加配置信息2.6、访问质量分地址2.7、窗口设置2.8、定位到输入框并输入博文地址2.9、定位到查询按钮并点击2.10、强…

三、Docker的基本组成和常用命令(二)

文章目录 容器命令创建并启动容器列举运行的容器退出容器命令启动容器重启容器停止容器强制停止容器删除容器 常用其他命令后台启动容器查看运行日志查看容器中的进程信息查看容器或镜像的元数据进入当前正在运行的容器从容器内拷贝文件到主机上 容器命令 说明&#xff1a;有镜…

【Linux】常用指令(二)

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 man指令 echo指令 补充: echo和cat的区别&#xff1f; CP指令 mv命令 ctrlc 指令 which指令 学习中遇到得问题: 1.如何看待指令&#xff1f; 2.在执行指令之前&#xf…

【MySQL】不就是MySQL——子查询

前言 今天我们来学习多表查询的下一个模块——子查询&#xff0c;子查询包括了标量子查询、列子查询、行子查询、表子查询&#xff0c;话不多说我们开始学习。 目录 前言 目录 一、子查询 1. 子查询的概念 2. 子查询语法格式 2.1 根据子查询结果不同可以分为&#xff1a;…

全志V3S嵌入式驱动开发(基于usb otg的spi-nor镜像烧入)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 说到了用usb otg来实现spi nand flash的烧入&#xff0c;这中间主要用到了PhoenixSuit软件。那么怎么用usb otg来实现spi nor flash的烧入呢&#…

从零开始 Spring Boot 47:缓存

从零开始 Spring Boot 47&#xff1a;缓存 图源&#xff1a;简书 (jianshu.com) Spring 提供一个简单但使用的缓存&#xff08;Cache&#xff09;机制&#xff0c;我们可以利用它来优化代码执行效率。 简单示例 老规矩&#xff0c;我们从一个简单示例开始&#xff1a; Serv…

RedHat红帽认证---RHCSA

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; RHCSA node1 1.配置网络设置 将 node1 配置为具有以下网络配置&#xff1a;主机名&#xff1a;node1.domain250.example.comIP 地址&#xff1a;172.25.250.100子网…

基于Java+Swing实现聊天室

基于JavaSwing实现聊天室 一、系统介绍二、功能展示三、其它1.其他系统实现 四、获取源码 一、系统介绍 Java聊天室系统主要用于实现在线聊天&#xff0c;基本功能包括&#xff1a;服务端和客户端。本系统结构如下&#xff1a; &#xff08;1&#xff09;服务端&#xff1a; 1…

SpringBoot中使用Tomcat、Undertow、jetty等容器

文章目录 SpringBoot中使用Tomcat、Undertow、jetty等容器&#xff1b;1. 默认使用Tomcat容器&#xff0c;直接运行项目即可&#xff1a;Java -jar xxx.jar2. 使用undertow容器2-1 引入Maven依赖&#xff0c;同时屏蔽内置Tomcat2-2 Undertow容器的常用配置参考2-3 一个特别的报…

人工智能---D分离

D分离&#xff08;D-Separation&#xff09;是一种用来判断变量是否条件独立的图形化方法。相比于非图形化方法&#xff0c;D-Separation更加直观&#xff0c;且计算简单。对于一个DAG&#xff08;有向无环图&#xff09;E&#xff0c;D-Separation方法可以快速的判断出两个节点…

c++11 标准模板(STL)(std::basic_streambuf)(三)

定义于头文件 <streambuf> template< class CharT, class Traits std::char_traits<CharT> > class basic_streambuf; 类 basic_streambuf 控制字符序列的输入与输出。它包含下列内容并提供到它们的访问&#xff1a; 1) 受控制字符序列&#xff…

在Android手机上安装kali Linux 的 QA

本文仅提供在安装时遇到问题的解决方案&#xff0c;查看安装链接请进入教程页面。 教程 https://www.hestudio.net/posts/install-kali-on-android-renew.html 一些命令 这里只说明我的教程涉及到的命令&#xff0c;查看其他博主教程的命令请转到对应博主的文档里查看&…

Linux 学习记录38(C高级篇)

Linux 学习记录38(C高级篇) 本文目录 Linux 学习记录38(C高级篇)一、shell中的分支语句1. case...in语句2. shell中的通配符 二、shell中的循环结构1. while循环2. shell中的printf3. for循环(1. 类似C中的格式(2. shell中的格式(3. 连续列表 4. select ...in 语句5. 辅助控制关…

PyQt学习(二)-----图形的建立(柱状图,折线图,堆叠柱状图,饼图)

数据库列表如图所示&#xff0c;如何对其进行绘图&#xff1a; &#xff08;一&#xff09;柱状图的建立 (1)柱状图初始化 self.__iniBarChart() pyqtSlot()def __iniBarChart(self):chart QChart()chart.setTitle("Barchart 演示")chart.setAnimationOptions(QChar…

md5的特点以及加密原理

MD5的特点及加密原理 简介特点1.长度固定2.结果不可逆3.高度离散性4.抗碰撞性 适用场景1.用户密码保护2.文件传输完整性校验3.数字签名4.云盘秒传 加密原理一.1.对输入的内容进行补位使其长度变成 N * 512 448 &#xff08;即长度对512取余之后 余数为448&#xff09;2.再往后补…