Java面试题之MD5加密的安全性详解

目录
  • 1.彩虹表
    • 什么是彩虹表
  • 2.解决方案
  • 3.实现代码
  • 总结

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

这道题看似简单,其实是一道送命题,很多人尤其是一些新入门的同学会觉得,安全啊,MD5 首先是加密的字符串,其次是不可逆的,所以它一定是安全的。如果你这样回答,那么就彻底掉进面试官给你挖好的坑了。

为什么呢?因为答案是“不安全”,而不是“安全”

1.彩虹表

MD5 之所以说它是不安全的,是因为每一个原始密码都会生成一个对应的固定密码,也就是说一个字符串生成的 MD5 值是永远不变的。这样的话,虽然它是不可逆的,但可以被穷举,而穷举的“产品”就叫做彩虹表。

什么是彩虹表

彩虹表是一个用于加密散列函数逆运算的预先计算好的表, 为破解密码的散列值(或称哈希值、微缩图、摘要、指纹、哈希密文)而准备。 一般主流的彩虹表都在 100G 以上。这样的表常常用于恢复由有限集字符组成的固定长度的纯文本密码。这是空间/时间替换的典型实践,比每一次尝试都计算哈希的破解处理时间少而储存空间多,但却比简单的对每条输入散列翻查表的破解方式储存空间少而处理时间多。

简单来说,彩虹表就是一个很大的,用于存放穷举对应值的数据表。 以 MD5 为例,“1”的 MD5 值是“C4CA4238A0B923820DCC509A6F75849B”,而“2”的 MD5 值是“C81E728D9D4C2F636F067F89CC14862C”,那么就会有一个 MD5 的彩虹表是这样的:

原始值 加密值
1 C4CA4238A0B923820DCC509A6F75849B
2 C81E728D9D4C2F636F067F89CC14862C
... ...

大家想想,如果有了这张表之后,那么我就可以通过 MD5 的密文直接查到原始密码了,所以说数据库如果只使用 MD5 加密,这就好比用了一把插了钥匙的锁一样不安全。

2.解决方案

想要解决以上问题,我们需要引入“加盐”机制。

盐(Salt):在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。

说的通俗一点“加盐”就像炒菜一样,放不同的盐,炒出菜的味道就是不同的,咱们之前使用 MD5 不安全的原因是,每个原始密码所对应的 MD5 值都是固定的,那我们只需要让密码每次通过加盐之后,生成的最终密码都不同,这样就能解决加密不安全的问题了

3.实现代码

加盐是一种手段、是一种解决密码安全问题的思路,而它的实现手段有很多种,我们可以使用框架如 Spring Security 提供的 BCrypt 进行加盐和验证,当然,我们也可以自己实现加盐的功能。

本文为了让大家更好的理解加盐的机制,所以我们自己来动手来实现一下加盐的功能。实现加盐机制的关键是在加密的过程中,生成一个随机的盐值,而且随机盐值尽量不要重复,这时,我们就可以使用 Java 语言提供的 UUID(Universally Unique Identifier,通用唯一识别码)来作为盐值,这样每次都会生成一个不同的随机盐值,且永不重复。加盐的实现代码如下:

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

public class PasswordUtil {
    /**
     * 加密(加盐处理)
     * @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;
    }
}

从上述代码我们可以看出,加盐的实现具体步骤是:

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

那么,问题来了,既然每次生成的密码都不同,那么怎么验证密码是否正确呢?要验证密码是否正确的关键是需要先获取盐值,然后再使用相同的加密方式和步骤,生成一个最终密码和和数据库中保存的加密密码进行对比,具体实现代码如下:

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

public class PasswordUtil {
    /**
     * 加密(加盐处理)
     * @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;
    }

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

总结

只是简单的使用 MD5 加密是不安全的,因为每个字符串都会生成固定的密文,那么我们就可以使用彩虹表将密文还原出来,所以它不是安全的。想要解决这个问题,我们需要通过加盐的手段,每次生成一个不同的密码,就把这个问题解决了。

到此这篇关于Java面试题之MD5加密的安全性详解的文章就介绍到这了,更多相关Java MD5加密内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java经典面试题最全汇总208道(一)

    目录 前言 1.JDK 和 JRE 有什么区别? 2.== 和 equals 的区别是什么? 3.final 在 java 中有什么作用? 4.java 中的 Math.round(-1.5) 等于多少? 5.String 属于基础的数据类型吗? 6.String str="i"与 String str=new String(“i”)一样吗? 7.如何将字符串反转? 8.String 类的常用方法都有那些? 9.new String("a") + new Strin

  • Java单链表的增删改查与面试题详解

    目录 一.单链表的增删改查 1.创建结点 2.单链表的添加操作 3.单链表的删除操作 4.单链表的有效结点的个数 二.大厂面试题 一.单链表的增删改查 1.创建结点 单链表是由结点连接而成,所以我们首先要创建结点类,用于对结点进行操作.定义data属性 表示序号,定义name属性表示结点存放的数据信息,定义next属性表示指向下一个结点.构造器只需要放入data属性和name属性,重写toString方法方便打印结点信息. public class Node { public int data;

  • Java经典面试题最全汇总208道(六)

    目录 前言 181.什么是类加载器,类加载器有哪些? 182.说一下类加载的执行过程? 183.JVM的类加载机制是什么? 184.什么是双亲委派模型? 185.怎么判断对象是否可以被回收? 186.说一下 jvm 有哪些垃圾回收算法? 187.说一下 jvm 有哪些垃圾回收器? 188.JVM栈堆概念,何时销毁对象 189.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别? 190.详细介绍一下 CMS 垃圾回收器? 191.简述分代垃圾回收器是怎么工作的? 192.Redis是什么?

  • Java经典面试题最全汇总208道(二)

    目录 前言 53.concurrentHashMap和HashTable有什么区别 54.HasmMap和HashSet的区别 55.请谈谈 ReadWriteLock 和 StampedLock 56.线程的run()和start()有什么区别? 57.为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法? 58.Synchronized 用过吗,其原理是什么? 59.JVM 对 Java 的原生锁做了哪些优化? 60.为什么 wait(),

  • java面试题解LeetCode27二叉树的镜像实例

    目录 正文 解题思路 方法一:递归法 方法二:辅助栈(或队列) 正文 LeetCode27. 二叉树的镜像 请完成一个函数,输入一个二叉树,该函数输出它的镜像. 例如输入: 4 /2 7 / \ /1 3 6 9 镜像输出: 4 /7 2 / \ /9 6 3 1 示例 1: 输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1] 限制: 0 <= 节点个数 <= 1000 解题思路 方法一:递归法 根据二叉树镜像的定义,考虑递归遍历(dfs)二叉树,交换每个

  • Java经典面试题最全汇总208道(三)

    目录 前言 websocket应用的是哪个协议 106.说一下 tcp 粘包是怎么产生的? 107.请列举出在 JDK 中几个常用的设计模式? 108.什么是设计模式?你是否在你的代码里面使用过任何设计模式? 110.在 Java 中,什么叫观察者设计模式(observer design pattern)? 111.使用工厂模式最主要的好处是什么?在哪里使用? 112.请解释自动装配模式的区别? 113.举一个用 Java 实现的装饰模式(decorator design pattern)?它是

  • Java经典面试题最全汇总208道(四)

    目录 前言 126.Spring 框架中的单例 Beans 是线程安全的么? 127.请解释 Spring Bean 的自动装配? 129.什么是 Spring Batch? 130.spring mvc 和 struts 的区别是什么? 131.请举例解释@Required 注解? 132.Spring常用注解 133.项目中是如何实现权限验证的,权限验证需要几张表 134.谈谈controller,接口调用的路径问题 135.如何防止表单重复提交 136.Spring中都应用了哪些设计模式

  • Java数据结构之单链表的实现与面试题汇总

    目录 1 单链表 1.1 单链表介绍 1.2 单链表的实现思路分析 1.3 实现代码 2 单链表的面试题 2.1 统计单链表中有效节点数量 2.2 新浪–倒数第k个节点 2.3 腾讯–单链表的反转 2.4 百度–逆序打印单链表 1 单链表 1.1 单链表介绍 由于顺序表的插入删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储——单链表.单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它 不要求在逻辑上相邻的两个元素在物理位置上也相邻.

  • Java经典面试题最全汇总208道(五)

    目录 前言 152.什么是 YAML? 153.如何使用 Spring Boot 实现分页和排序? 154.如何使用 Spring Boot 实现异常处理? 155.单点登录 156.Spring Boot比Spring多哪些注解 157.打包和部署 158.Spring Boot如何访问不同的数据库 159.查询网站在线人数 160.easyExcel如何实现 161.什么是 Swagger?你用 Spring Boot 实现了它吗? 162.数据库的三范式是什么? 163.一张自增表里面总共

  • Java面试题之MD5加密的安全性详解

    目录 1.彩虹表 什么是彩虹表 2.解决方案 3.实现代码 总结 MD5 是 Message Digest Algorithm 的缩写,译为信息摘要算法,它是 Java 语言中使用很广泛的一种加密算法.MD5 可以将任意字符串,通过不可逆的字符串变换算法,生成一个唯一的 MD5 信息摘要,这个信息摘要也就是我们通常所说的 MD5 字符串.那么问题来了,MD5 加密安全吗? 这道题看似简单,其实是一道送命题,很多人尤其是一些新入门的同学会觉得,安全啊,MD5 首先是加密的字符串,其次是不可逆的,所

  • Java使用Cipher类实现加密的过程详解

    一.先看一个简单加密,解密实现 1.1 加密 /** * content: 加密内容 * slatKey: 加密的盐,16位字符串 * vectorKey: 加密的向量,16位字符串 */ public String encrypt(String content, String slatKey, String vectorKey) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

  • 微信小程序 MD5加密登录密码详解及实例代码

    微信小程序 MD5加密 在小程序中,页面的脚本逻辑是在JsCore中运行,JsCore是一个没有窗口对象的环境,所以不能在脚本中使用window,也无法在脚本中操作组件.zepto/jquery 也无法使用,因为zepto/jquery 会使用到window对象和document对象.所以在微信小程序中不能使用jquery.md5.js对密码进行加密.下面我提供一种MD5.js加密实例,本实例先静态演示,后面再到小程序中演示. md5.js程序如下: /* * A JavaScript impl

  • Java Web开发之MD5加密用法分析

    本文实例讲述了Java Web开发之MD5加密用法.分享给大家供大家参考.具体如下: MD5是Message Digest 5的缩写,是一种加密算法,能够对字节数组进行加密,有如下特点: ① 不能根据加密后的信息找加密之前的信息: ② 加密后的结果是128位: ③ 对于给定的字节数组,不管什么时候采用这种加密算法,结果是相同的: ④ 对于不同的字节数组,加密的结果是不相同的. 在Web应用中通常需要对用户设置的密码进行加密之后再存储,否则数据库管理员能够看到明文的密码,并且密码也有被黑客获取的危

  • Java实现API sign签名校验的方法详解

    目录 1. 前言 2. 签名生成策略 3. API 签名算法 Java 实现 4. 测试一下 1. 前言 目的:为防止中间人攻击. 场景: 项目内部前后端调用,这种场景只需要做普通参数的签名校验和过期请求校验,目的是为了防止攻击者劫持请求 url 后非法请求接口. 开放平台向第三方应用提供能力,这种场景除了普通参数校验和请求过期校验外,还要考虑 3d 应用的授权机制,不被授权的应用就算传入了合法的参数也不能被允许请求成功. 2. 签名生成策略 接下来详述场景 2,其实场景 1 也包含在场景 2

  • Java之JSP教程九大内置对象详解(下篇)

    目录 前言 JSP pageContext对象 示例 JSP page对象 示例 JSP Cookie的使用 JSP 使用 cookie 主要分为以下几个步骤. 创建 cookie 对象 写入 cookie 设置 cookie 有效期 读取cookie 示例 读取cookie 删除cookie session和cookie的区别 前言 之前我们在这篇文章Java之JSP教程九大内置对象详解中,已经讲解完了六个个对象,接下来我们讲解最后的三个对象 JSP pageContext对象 pageCon

  • Python 加密的实例详解

     Python 加密的实例详解 hashlib支持md5,sha1,sha256,sha384,sha512,用法和md5一样 import hashlib #hashlib支持md5,sha1,sha256,sha384,sha512,用法和md5一样 m = hashlib.md5() #创建加密对象 m.update(b'password') #对输入内容进行加密, m.digest() #获取二进制加密密文 m.hexdigest() #获取十六进制加密密文 '''''python3默认

  • java通过ssh连接服务器执行shell命令详解及实例

    java通过ssh连接服务器执行shell命令详解 java通过ssh连接服务器执行shell命令:JSch 是SSH2的一个纯Java实现.它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文件传输等等.你可以将它的功能集成到你自己的 程序中.同时该项目也提供一个J2ME版本用来在手机上直连SSHD服务器. SSH是Secure Shell的缩写,一种建立在应用层和传输层基础上的安全协议.SSH在连接和传送过程中会加密所有数据,可以用来在不同系统或者服务器之间进行安全连接.SSH提

  • Java中成员方法与成员变量访问权限详解

    记得在一次面试的笔试题中,有的面试官会要求写出具体的像pullic这些访问限定符的作用域.其实,平常我都没去系统的考虑这些访问限定符的作用域,特别是包内包外的情况,OK,笔试不行了. 这是java基本的知识,也是公司看重的,那没办法啦,我的脑袋记不住东西,那我只能把这些东西写下来方便自己温故知新,不废话了,贴代码了. 代码如下: package com.jaovo; /** *_1_ 成员变量访问权限的求证 * public private protected default(默认的权限) *自

  • Java使用备忘录模式实现过关类游戏功能详解

    本文实例讲述了Java使用备忘录模式实现过关类游戏功能.分享给大家供大家参考,具体如下: 一.模式定义 备忘录模式,在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象外部保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 二.模式举例 1模式分析 我们借用过关类游戏来说明这一模式. 2备忘录模式静态类图 3代码示例(黑箱备忘录模式) 3.1创建备忘录窄接口一INarrowMemento package com.demo.memento; /** * 备忘录窄接口(不提供任何方法,外部

随机推荐