Ответ 1
Мне кажется, что "способ WildFly" справиться с паролями - это делать то, что делают большинство контейнеров, и поставлять незащищенное решение из коробки. Я не знаю, почему, но каждая стандартная реализация JDBC, которую я видел до сих пор, просто хэширует пароли без соли... Что совершенно небезопасно.
Решение с открытым исходным кодом
EDIT: я нашел решение, которое работает на WildFly. Я закончил тем, что использовал его сам, и он работает хорошо. Я могу порекомендовать его:
Вот как я его настроил:
Сначала добавьте модуль в WildFly, создав папку ниже modules/
, например:
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);
password
будет выглядеть примерно так:
"192EAEB3B7AA40B1:1000:4C137AF7AD0F3999D18E2B9E6FB726D5C07DE7D5"
При сравнении паролей вы вызываете одну и ту же функцию, передавая исходный пароль, а затем сравниваете результаты:
String enteredPassword = hash(userInput, password);
if (enteredPassword.equals(password)) {
// Ok!
}
Причина, по которой вам нужно передать исходный пароль, заключается в том, что параметры хэширования и соль хранятся в хэше пароля, поэтому алгоритм нуждается в сохраненном пароле, чтобы получить эти параметры и использовать их для нового хэша. Однако вам обычно не нужно сравнивать пароли самостоятельно, поскольку это уже сделано в модуле входа.
Или сверните свой собственный
Это сообщение в блоге дает некоторое объяснение о том, как свернуть свою собственную реализацию Realm, которая добавляет соль. У него исходный код на GitHub, поэтому, возможно, используйте это.
Это для Glassfish, но я думаю, что это не имеет значения, насколько реализуется код реализации Realm.