面试突击91:MD5 加密安全吗?
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面试真题解析
面试突击91:MD5 加密安全吗?的更多相关文章
- 4、C#进阶:MD5加密、进程、线程、GDI+、XML、委托
MD5加密 将字符串进行加密,无法解密.网上的解密方式也都是在库里找,找不到也没有. 1 protected void Page_Load(object sender, EventArgs e) 2 ...
- MD5加密相关
demo效果
- 常见https,SSH协议和MD5加密方式分析
前言 https,SSH协议和MD5加密是前端可能会接触到的加密,所以我就将他们进行了一个归纳. 1.https 1.1原理 A.就是在http加入SSL层,是http安全的基础;B.htts协议是在 ...
- 关于CryptoJS中md5加密以及aes加密的随笔
最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...
- Android数据加密之MD5加密
前言: 项目中无论是密码的存储或者说判断文件是否是同一文件,都会用到MD5算法,今天来总结一下MD5加密算法. 什么是MD5加密? MD5英文全称“Message-Digest Algorithm 5 ...
- android MD5加密
public class MD5Uutils { //MD5加密,32位 public static String MD5(String str) { MessageDige ...
- IOS 杂笔-9 (MD5 加密)
首先是一段对MD5的简介 *出自一位大牛之手* Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护 ...
- JS中使用MD5加密
下载 MD5 使用MD5加密的方法:下载md5.js文件,在网页中引用该文件: < script type="text/javascript" src="md5.j ...
- MD5工具类,提供字符串MD5加密、文件MD5值获取(校验)功能
MD5工具类,提供字符串MD5加密(校验).文件MD5值获取(校验)功能 : package com.yzu.utils; import java.io.File; import java.io.Fi ...
随机推荐
- 【PMP学习笔记】第4章 项目整合管理
[PMP学习笔记]第4章 项目整合管理 一.项目整合管理 什么是项目整合管理? 项目整合管理由项目经理负责.虽然其他知识领域可以由相关专家(如成本分析专家.进度规划专家.风险管理专家)管理,但是项目整 ...
- 面向开发的内存调试神器,如何使用ASAN检测内存泄漏、堆栈溢出等问题
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 目录 介绍 如何使用 ASAN 检测内存泄漏 检测悬空指针访问 检测堆溢出 C++ 中的new/delete不匹配 检测栈 ...
- 关于KeyFile的破解,含注册机源代码
程序来自于<加密与解密3>的第五章的PacMe.exe.书中并没有给出C语言实现的加密与解密代码,自己花了一些时间,把代码还原了,并且写了一个C语言的注册机. 加密原理:正如书中所说,此程 ...
- 我和Apache DolphinScheduler的这一年
Apache DolphinScheduler,为Apache开源项目, 简称"DS", 中文名 "小海豚调度"(海豚聪明.人性化,又左右脑可互相换班,终生不用 ...
- 彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-项目入口与路由EP01
书接上回,我们已经安装好Iris框架,并且构建好了Iris项目,同时配置了fresh自动监控项目的实时编译,万事俱备,只欠东风,彩虹女神蓄势待发.现在我们来看看Iris的基础功能,如何编写项目入口文件 ...
- 虚拟DOM解析及其在框架里的应用
虚拟DOM解析及其在框架里的应用 浏览器是怎样解析HTML并且绘出整个页面的 上图为webkit引擎浏览器的处理流程,如上图大致分为4大步: 第一步,HTML解析器分析html,构建一颗DOM树: 第 ...
- CSS 布局(一):Flex 布局
主轴和纵轴 对某一盒子模型添加display: flex;属性后,称之为 Flexible Box 模型(或称之为 flexbox),即弹性盒子模型,简称弹性盒子. 弹性盒子为子元素提供了强大的空间分 ...
- iOS影视应用+全网视频下载
又一个新的iOS影视伪装 打开软件连续点击3次列表,然后关闭重新打开即可变身,无广告全免费高画质,还有电视直播 下载地址:https://apps.apple.com/cn/app/贴画壁纸/id16 ...
- 一文了解.Net的CLR、GC内存管理
一文了解.Net的CLR.GC内存管理 微软官方文档对内存管理和CLR的概述 什么是托管代码? 托管代码就是执行过程交由运行时管理的代码. 在这种情况下,相关的运行时称为公共语言运行时 (CLR),不 ...
- 【java】基础1-字符串、堆、栈、静态与引用类型
/*结论:1,一般变量(int,float,boolean..)使用==比较,引用类型(String,int[],对象)使用equals比较.2,一般的变量存放在栈中,new出来的对象都存放在堆中,字 ...