在 Java 中对密码进行哈希处理

1.概述

在本教程中,我们将讨论密码哈希的重要性。

我们将快速了解它是什么,为什么它很重要,以及在 Java 中执行它的一些安全和不安全的方法。

2.什么是哈希?

散列是使用称为加密散列函数的数学函数从给定消息生成字符串或散列的过程。

虽然有几个散列函数,但那些为散列密码量身定制的函数需要具有四个主要属性才能确保安全:

  1. 它应该是确定性的:由相同散列函数处理的相同消息应该 总是 产生相同的 散列
  2. 它是不 可逆的:从其哈希生成 消息是不切实际的
  3. 它具有高:对消息的微小更改会 产生截然不同的 哈希值
  4. 并且它可以抵抗冲突:两条不同 的消息不应该产生相同的 哈希

具有所有四个属性的哈希函数是密码哈希的有力候选者,因为它们一起极大地增加了从哈希中逆向工程密码的难度。

不过,密码散列函数也应该很慢。快速算法将有助于暴力 攻击,其中黑客将尝试通过散列和比较每秒数十亿(或数万亿)个潜在密码来猜测密码。

满足所有这些标准的一些出色的散列函数是PBKDF2、  BCrypt 和 SCrypt。 但首先,让我们看一下一些较旧的算法以及为什么不再推荐它们 

3. 不推荐:MD5

我们的第一个哈希函数是 MD5 消息摘要算法,开发于 1992 年。

Java 的 MessageDigest使计算变得容易,并且在其他情况下仍然有用。

然而,在过去几年中,发现 MD5在第四个密码散列属性 中失败,因为它在计算上变得容易产生冲突。最重要的是,MD5 是一种快速算法,因此对暴力攻击毫无用处。

因此,不推荐使用 MD5。

4. 不推荐:SHA-512

接下来,我们将看看 SHA-512,它是 Secure Hash Algorithm 系列的一部分,该系列始于 1993 年的 SHA-0。

4.1。为什么选择 SHA-512?

随着计算机功能的增加,以及我们发现新的漏洞,研究人员会推导出新版本的 SHA。较新版本的长度越来越长,或者有时研究人员会发布底层算法的新版本。

SHA-512 代表第三代算法中最长的密钥。

虽然现在有更安全的 SHA 版本,但SHA-512 是用 Java 实现的最强版本。

4.2. 用Java实现

现在,让我们看看在 Java 中实现 SHA-512 哈希算法。

首先,我们要了解 的概念。简单地说,这是为每个新哈希生成的随机序列

通过引入这种随机性,我们增加了散列的,并且我们保护我们的数据库免受称为彩虹表的预编译散列列表的影响。

然后我们的新哈希函数大致变为:

salt <- generate-salt;
hash <- salt + ':' + sha512(salt + password)

4.3. 生成盐

为了引入盐,我们将使用 java.security中的SecureRandom 类:

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);

然后,我们将使用 MessageDigest 类使用我们的 salt 配置 SHA-512 哈希函数:

MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(salt);

添加后,我们现在可以使用摘要方法生成我们的哈希密码:

byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));

4.4. 为什么不推荐?

当与 salt 一起使用时,SHA-512 仍然是一个不错的选择但还有更强大和更慢的选择

此外,我们将介绍的其余选项具有一个重要特性:可配置强度。

5. PBKDF2、BCrypt 和 SCrypt

PBKDF2、BCrypt 和 SCrypt 是三种推荐的算法。

5.1。为什么推荐这些?

这些中的每一个都很慢,并且每个都具有可配置强度的出色功能。

这意味着随着计算机强度的增加, 我们可以通过改变输入来减慢算法的速度。

5.2. 在 Java 中实现 PBKDF2

现在, 盐是密码散列的基本原理,因此我们也需要一个用于 PBKDF2 的:

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);

接下来,我们将创建一个 PBEKeySpec 和一个SecretKeyFactory  ,我们将使用 PBKDF2WithHmacSHA1 算法对其进行实例化:

KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

第三个参数(65536)实际上是强度参数。它指示该算法运行了多少次迭代,从而增加了生成哈希所需的时间。

最后,我们可以使用我们的 SecretKeyFactory 来生成哈希:

byte[] hash = factory.generateSecret(spec).getEncoded();

5.3. 在 Java 中实现 BCrypt 和 SCrypt

因此,事实证明BCrypt 和 SCrypt 支持尚未随 Java 一起提供,尽管一些 Java 库支持它们。

其中一个库是 Spring Security。

6. 使用 Spring Security 进行密码散列

尽管 Java 本身支持 PBKDF2 和 SHA 哈希算法,但它不支持 BCrypt 和 SCrypt 算法。

幸运的是,Spring Security 通过PasswordEncoder接口支持所有这些推荐算法 :

  • Pbkdf2PasswordEncoder给我们 PBKDF2
  • BCryptPasswordEncoder 为我们提供 BCrypt,并且
  • SCryptPasswordEncoder 给我们 SCrypt

PBKDF2、BCrypt 和 SCrypt 的密码编码器都支持配置所需的密码哈希强度。

我们可以直接使用这些编码器,即使没有基于 Spring Security 的应用程序。或者,如果我们使用 Spring Security 保护我们的站点,那么我们可以通过其 DSL 或依赖注入来配置我们想要的密码编码器。

而且,与我们上面的示例不同,这些加密算法将在内部为我们生成盐。该算法将盐存储在输出哈希中,以供以后用于验证密码。

7. 结论

因此,我们深入研究了密码散列;探索这个概念及其用途。

在用 Java 编码之前,我们已经查看了一些历史哈希函数以及一些当前实现的哈希函数。

最后,我们看到 Spring Security 附带了它的密码加密类,实现了一系列不同的哈希函数。

与往常一样,代码可在 GitHub 上找到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值