WildFly:Java EE 应用程序中的随机加盐密码
WildFly: randomly salted passwords in Java EE application
使用存储在数据库中的随机加盐密码的 WildFly (8.2) 方法是什么?
org.jboss.crypto.digest.DigestCallback
(在密码验证过程中)的实现是否意味着可以从数据库访问 salt 部分?
或者我应该在将密码交给 HttpServletRequest
的 login
方法之前自己简单地散列和加盐密码?
在我看来,处理密码的 'WildFly way' 是做大多数容器做的事情,并提供开箱即用的非安全解决方案。我不知道为什么,但到目前为止,我所看到的每个标准 JDBC 领域实现都只是在不加盐的情况下散列密码……这是完全不安全的。
开源解决方案
编辑:我找到了适用于 WildFly 的现成解决方案。我最终自己使用了它并且效果很好。我可以推荐它:
这是我的配置方式:
首先通过在 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>`
然后,添加realm配置到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);
password
最终看起来像这样:
"192EAEB3B7AA40B1:1000:4C137AF7AD0F3999D18E2B9E6FB726D5C07DE7D5"
比较密码时,调用相同的函数,传递原始密码,然后比较结果:
String enteredPassword = hash(userInput, password);
if (enteredPassword.equals(password)) {
// Ok!
}
您需要传递原始密码的原因是散列参数和盐存储在密码散列中,因此算法需要存储的密码来获取这些参数并将它们用于新散列。然而,您通常不需要自己比较密码,因为这已经在登录模块中完成了。
或者,自己滚动
This blog post gives some explanation on how to roll your own Realm implementation that does add salt. He has source code on GitHub 所以也许可以使用它。
它适用于 Glassfish,但我认为就 Realm 实现代码而言并不重要。
使用存储在数据库中的随机加盐密码的 WildFly (8.2) 方法是什么?
org.jboss.crypto.digest.DigestCallback
(在密码验证过程中)的实现是否意味着可以从数据库访问 salt 部分?
或者我应该在将密码交给 HttpServletRequest
的 login
方法之前自己简单地散列和加盐密码?
在我看来,处理密码的 'WildFly way' 是做大多数容器做的事情,并提供开箱即用的非安全解决方案。我不知道为什么,但到目前为止,我所看到的每个标准 JDBC 领域实现都只是在不加盐的情况下散列密码……这是完全不安全的。
开源解决方案
编辑:我找到了适用于 WildFly 的现成解决方案。我最终自己使用了它并且效果很好。我可以推荐它:
这是我的配置方式:
首先通过在 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>`
然后,添加realm配置到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);
password
最终看起来像这样:
"192EAEB3B7AA40B1:1000:4C137AF7AD0F3999D18E2B9E6FB726D5C07DE7D5"
比较密码时,调用相同的函数,传递原始密码,然后比较结果:
String enteredPassword = hash(userInput, password);
if (enteredPassword.equals(password)) {
// Ok!
}
您需要传递原始密码的原因是散列参数和盐存储在密码散列中,因此算法需要存储的密码来获取这些参数并将它们用于新散列。然而,您通常不需要自己比较密码,因为这已经在登录模块中完成了。
或者,自己滚动
This blog post gives some explanation on how to roll your own Realm implementation that does add salt. He has source code on GitHub 所以也许可以使用它。
它适用于 Glassfish,但我认为就 Realm 实现代码而言并不重要。