加入收藏 | 设为首页 | 会员中心 | 我要投稿 银川站长网 (https://www.0951zz.com/)- 云通信、基础存储、云上网络、机器学习、视觉智能!
当前位置: 首页 > 服务器 > 安全 > 正文

Md5加密是否足够安全

发布时间:2023-10-16 10:52:14 所属栏目:安全 来源:
导读:Message digest algorithm 的缩写为 MD5,译为信息摘要算法,它是 Java 语言中使用很广泛的一种加密算法。MD5 可以将任意字符串,通过不可逆的字符串变换算法,生成一个唯一的 MD5 信息摘要,这个信息摘要也就是我们

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

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

1.彩虹表

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

简单来说,彩虹表就是一个很大的,用于存放穷举对应值的数据表。以 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 加密是不安全的,因为每个字符串都会生成固定的密文,那么我们就可以使用彩虹表将密文还原出来,所以它不是安全的。想要解决这个问题,我们需要通过加盐的手段,每次生成一个不同的密码,就把这个问题解决了。在这个过程中,我们可以看到,密码的长度是固定的,只要我们不断重复加盐,就可以一直保持密码的长度不变。

(编辑:银川站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章