野鸡: Java EE应用程序中随机加盐密码

4

WildFly(8.2)中处理随机盐值密码存储在数据库中的方法是什么?

org.jboss.crypto.digest.DigestCallback的实现(在密码验证过程中)是否可以访问数据库中的盐值部分?

还是说我应该在将密码交给HttpServletRequestlogin方法之前自行哈希和盐化密码?


1
我找到了一个好的开源解决方案,现在正在使用。请查看我的编辑后的答案。 - Stijn de Witt
1个回答

5
我认为,“野飞”处理密码的方式是像大多数容器一样提供一个非安全的解决方案。我不知道为什么,但迄今为止我见过的所有标准JDBC领域实现都只是对密码进行哈希处理,而没有加盐...这是完全不安全的。 开源解决方案 编辑:我找到了一个在WildFly上可用的开箱即用的解决方案。我最终自己使用了它,效果很好。我可以推荐它: m9aertner/PBKDF2 以下是我的配置方式:
首先,在modules/下创建一个文件夹,添加一个模块到WildFly中,如下所示:

C:\WildFly\v8.2.0\modules\de\rtner\PBKDF2\main

PBKDF2-1.1.0.jar文件和以下内容的module.xml文件放入其中:

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="de.rtner.PBKDF2">
  <resources>
    <resource-root path="PBKDF2-1.1.0.jar"/>
  </resources>
  <dependencies>
    <module name="org.picketbox"/>
    <module name="javax.api"/>
  </dependencies>
</module>`

然后,在 standalone.xml 中添加一个领域配置:

<subsystem xmlns="urn:jboss:domain:security:1.2">
  <security-domains>
    <!-- .... -->

    <security-domain name="MyRealm">
      <authentication>
        <login-module code="de.rtner.security.auth.spi.SaltedDatabaseServerLoginModule" flag="required" module="de.rtner.PBKDF2">
          <module-option name="dsJndiName" value="java:/jdbc/MyDS"/>
          <module-option name="principalsQuery" value="SELECT password FROM users WHERE username = ?"/>
          <module-option name="rolesQuery" value="SELECT roles.name AS groupid, 'Roles' FROM roles INNER JOIN user_roles ON roles.name = users.username WHERE users.username = ?"/>
          <module-option name="unauthenticatedIdentity" value="guest"/>
          <!-- DEFAULT HASHING OPTIONS:
          <module-option name="hmacAlgorithm" value="HMacSHA1" />
          <module-option name="hashCharset" value="UTF-8" />
          <module-option name="formatter" value="de.rtner.security.auth.spi.PBKDF2HexFormatter" />
          <module-option name="engine" value="de.rtner.security.auth.spi.PBKDF2Engine" />
          <module-option name="engine-parameters" value="de.rtner.security.auth.spi.PBKDF2Parameters" />
          -->
        </login-module>
      </authentication>
    </security-domain>

    <!-- .... -->
  </security-domains>
</subsystem>

SQL查询与标准的DatabaseLoginModule相同。默认哈希选项无需指定(因为它们是默认值),但在创建新用户时,您需要了解它们(并正确设置它们),以便使用相同的参数正确地哈希其密码。
示例用法
以下是我在代码中执行的操作,根据给定的明文创建新密码哈希(包括盐)。
public static String hash(String plainText, String storedPassword) {
    if (plainText == null) return null;
    SimplePBKDF2 crypto = new SimplePBKDF2();
    PBKDF2Parameters params = crypto.getParameters();
    params.setHashCharset("UTF-8");
    params.setHashAlgorithm("HmacSHA1");
    params.setIterationCount(1000);
    if (storedPassword != null) {
        new PBKDF2HexFormatter().fromString(params, storedPassword);
    }
    return crypto.deriveKeyFormatted(plainText);
}

创建新密码时,您需要调用此函数,并将null作为storedPassword传递:
String password = hash('MySecretPassword', null);

密码 最终可能会看起来像这样:

"192EAEB3B7AA40B1:1000:4C137AF7AD0F3999D18E2B9E6FB726D5C07DE7D5"

比较密码时,调用同一函数,传递原始密码,然后比较结果:

String enteredPassword = hash(userInput, password);
if (enteredPassword.equals(password)) {
    // Ok!
}

你需要传递原始密码的原因是哈希参数和盐被存储在密码哈希中,所以算法需要存储的密码来获取这些参数并将它们用于新的哈希。然而,通常情况下你不需要自己比较密码,因为这已经在登录模块中完成了。
或者,自己动手
这篇博客文章解释了如何自己实现添加盐的Realm实现。他在GitHub上有源代码,也许可以使用那个。
虽然是针对Glassfish的,但我认为就Realm实现代码而言,这并不重要。

如何在此解决方案中实现密码盐? - perotom
@user2630406,我添加了一个示例,用于将新密码或用户输入进行哈希处理,以便与现有密码进行比较。 - Stijn de Witt
盐是否存储在PBKDF2哈希中?在示例中,您在散列之前添加盐,但这对于PBKDF2不起作用。 - perotom
@user2630406 我不会手动添加盐...这是由哈希算法完成的。实际上,参数和盐可以在哈希密码中清晰地看到。我将在我的答案中添加一个示例结果,希望能够澄清事情。 - Stijn de Witt
完美的例子。非常感谢! - perotom
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接