Проверка подлинности в спящем режиме без паролей, хранящихся в текстовом виде

Моя цель - безопасная аутентификация базы данных с помощью JDBC/Hibernate без сохранения паролей в текстовом формате. Обоснованы примеры кода. Я уже использую waffle для аутентификации пользователя, поэтому, если есть какой-то способ использовать учетные данные, полученные waffle от пользователя, и перенаправить их в БД, это будет хорошо.

Два вопроса:

  • Каков рекомендуемый способ аутентификации нескольких хостов (клиент, веб-сервер и база данных - все разные машины) с tomcat/hibernate/ spring на веб-сервере, базе данных SQL и, очевидно, в браузере клиента?
  • Я также соглашаюсь на способ использования одной учетной записи пользователя для аутентификации, если информация об учетной записи пользователя не хранится в обычном тексте в любом месте. Учетная запись пользователя будет иметь права на чтение и запись в БД.

Я нашел полезную информацию о подключении к SQL Server в этом потоке. Тем не менее, я ожидаю, что Tomcat будет работать под учетной записью по умолчанию, которая похожа на локальную систему или что-то в этом роде. Насколько я знаю, эта учетная запись не может использоваться для проверки подлинности Windows в базе данных.

Мое решение:

В конце концов я использовал подход, упомянутый в приведенном выше потоке. Вместо того, чтобы запускать службу Tomcat как Local System, она теперь работает как пользователь. У этого пользователя есть разрешение на доступ к базе данных. Мой конфигурационный файл спящего режима настроен следующим образом:

    <property name="hibernate.connection.url">
jdbc:sqlserver://system:port;databaseName=myDb;integratedSecurity=true;
</property>

Тем, кто предоставил ответы

Я благодарен всем за помощь, и я попробую некоторые из техник, упомянутых в потоке. Моя проблема с некоторыми ответами заключается в том, что они требуют симметричного шифрования, требующего секретного ключа. Сохранение секретности ключа - это почти та же проблема, что и сохранение пароля в виде обычного текста.

Ответы

Ответ 1

Хорошо, давайте рассмотрим проблему. Вы хотите, чтобы информация об аутентификации была доступна, но не была закодирована в любом месте кода или в файловой системе. Что я хотел бы предложить:

  • требуется, чтобы администратор приложения указывал информацию об аутентификации при запуске приложения либо через jmx, либо через веб-страницу, которая не требует подключения к базе данных.
  • Добавить фильтр сервлетов, чтобы ограничить доступ до тех пор, пока не будет введена информация о проверке подлинности базы данных.

Это решение требует некоторой расширенной загрузки контекста spring, чтобы он ожидал, пока не будет указана информация аутентификации (через страницу входа).

Ответ 2

i недавно написал об этом в блоге:

вы можете сказать tomcat jdbcrealm использовать алгоритм дайджеста на пароле, например sha-256, и сохранить хеш, а не пароли открытого текста.

Предположим, что ваши пользовательские объекты выглядят следующим образом:

@Entity
@Table(name = "cr_users")
public class UserDetails{
    @Id
    @GeneratedValue
    private long id;
    private String name;
    private String passwordHash;
    @ManyToMany
    private Set<Group> groups;
}

при создании нового пользователя через службу можно создать хэш пароля с помощью MessageDigest:

public UserDetails createNewUser(String username,String passwd,Set<Group> groups){
       UserDetails u=new UserDetails();
       u.setname(username);
       u.setGroups(groups);
       u.setPassword(createHash(passwd));
       return u;
}
public String createHash(String data){
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(password.getBytes());
        byte byteData[] = digest.digest();
        //convert bytes to hex chars
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < byteData.length; i++) {
         sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
        }
        return sb.toString();
}

так как SHA-256 всегда будет давать одно и то же значение hashval для того же входа, вы можете сказать tomcat JDBCRealm использовать этот алгоритм для проверки паролей.

<Realm className="org.apache.catalina.realm.JDBCRealm"
       driverName="org.postgresql.Driver"
       connectionURL="jdbc:postgresql://localhost:5432/mydb"
       connectionName="myuser" connectionPassword="mypass"
       userTable="tc_realm_users" userNameCol="username" userCredCol="passwordhash" 
       userRoleTable="tc_realm_groups" roleNameCol="groupname"
       digest="sha-256"/>

проблема в том, что tomcat ожидает отдельный формат для следующего типа:

+----------------------+  +-------------------+
|   tc_realm_users     |  | tc_realm_groups   |
+----------------------+  +-------------------+
| username     varchar |  | username  varchar |
| passwordhash varchar |  | groupname varchar |
+----------------------+  +-------------------+

если ваша модель пользовательских данных подходит вам, вам повезло, но мои сгенерированные таблицы Hibernate выглядели следующим образом:

+----------------------+  +-------------------+  +--------------------+
|     cr_users         |  |      cr_groups    |  | cr_users_cr_groups |
+----------------------+  +-------------------+  +--------------------+
| id              long |  | id           long |  | cr_users_id   long |
| name         varchar |  | name      varchar |  | groups_id     long |
| passwordhash varchar |  +-------------------+  +--------------------+
+----------------------+

поэтому я создал View, используя SQL, который имел ожидаемый формат и извлекал данные из моих пользовательских данных webapps:

create view tc_realm_groups as
select 
  cr_users.name as username,
  groups.name as groupname
from cr_users 
left join (
        select 
                cr_users_cr_groups.cr_users_id,cr_groups.name 
        from cr_groups 
        left join 
                cr_users_cr_groups 
                on cr_users_cr_groups.groups_id=cr_groups.id
) as groups on groups.cr_users_id=id;

create view tc_realm_users as
select 
  name as username
from cr_users;

с этим tomcat смог аутентифицировать/авторизировать снова мои уже существующие пользовательские данные и написать данные в контексте, чтобы я мог использовать его в Джерси (JSR-311) ресурсы:

public Response getEvent(@Context SecurityContext sc,@PathParam("id") long id) {
                log.debug("auth: " + sc.getAuthenticationScheme());
                log.debug("user: " + sc.getUserPrincipal().getName()); // the username!
                log.debug("admin-privileges: " + sc.isUserInRole("webapp-admin"));
                return Response.ok("auth success").build();
        }

существуют также некоторые другие реализации Realm:

  • JDBCRealm
  • DataSourceRealm
  • JNDIRealm
  • UserDatabaseRealm
  • MemoryRealm
  • JAASRealm
  • CombinedRealm
  • LockOutRealm

некоторые ссылки:

Ответ 3

Если я правильно понимаю, ваша среда - это веб-приложение с поддержкой hibernate, развернутое в tomcat.

Теперь в настоящее время вы должны настроить протокол передачи JDBC i) либо в файле конфигурации hibernate (обычно файл hibernate.cfg.xml) в свойстве: -

hibernate.connection.password

ii) или в файле конфигурации tomcat: -

<Resource name="jdbc/myoracle" ......password="tiger".../>

Теперь вы хотите НЕ хранить ясный пароль в любом из вышеуказанных файлов.

В коде приложения вы должны: -

Line1: org.hibernate.cfs.Condiguration configuration=new Configraution().configure(<hibernate configuration path>);

then,Line2:  configuration.buildSessionFactory().openSession() to create a hibernate session which has underlying JDBC connection.

1) Один из способов может быть в основном: - Вы можете зашифровать свой пароль, используя любой java-security alogirthm, используя любой поставщик JCE. Вы храните зашифрованный пароль в любом из вышеуказанных конфигурационных файлов (спящий режим или tomcat в соответствии с вашей средой проекта).

а затем между Line1 и Line2, вы можете использовать логику дешифрования: -

Line1: org.hibernate.cfs.Condiguration configuration=new Configraution().configure(<hibernate configuration path>);

String encrpytedPassword=
configuration.getProperty("hibernate.connection.password"); \\will return encrypted password

//decryption logic to decypt the encrypted password:-
String decryptedPwd=decrypt(encrpytedPassword);

configuration.setProperty("hibernate.connection.password",decryptedPwd);

then,Line2:  configuration.buildSessionFactory().openSession()

Вы можете сделать шифрование и дешифрование такими сложными, как вы хотите, например. шифрование пароля с обратной строкой-clear-password. Вы можете использовать любой JCE API: - jasrypt, bouncy castle. Вам должно понадобиться понимание java-криптографии. Пожалуйста, обратитесь к: -

http://download.oracle.com/javase/1.4.2/docs/guide/security/CryptoSpec.html

2) В случае, если вы беспокоитесь о том, что пароль передается в ядре в протоколе соединения JDBC, вы можете использовать поддержку SSL от поставщика БД для безопасного подключения. Напр. для подключения SSL JDBC к вашему серверу БД. Для этого обратитесь к реестру сервера БД.

ИЗМЕНИТЬ, ЧТОБЫ ЗАКЛЮЧИТЬ keylM comment ON КАК ОБЕСПЕЧИТЬ ПАРОЛЬ JDBC

позволяет сказать, что у вас есть пара частных и открытых ключей: = privare.key и public.cer. Вы можете зашифровать пароль JDBC с помощью закрытого ключа и сохранить зашифрованный пароль в файле конфигурации. Вы можете использовать OpenSSL для импорта открытого сертификата в файл jks (java keystore) и использовать его в JAVA_HOME\jre\lib\security.

В вашей логике дешифрования: -

  KeyStore ks = KeyStore.getInstance("JKS");
  ks.load(new FileInputStream("keystore.jks"),<jks password>); //jks password can be hardoded
Certificate cert=      ks.getCertificate(<certificate alias>);
//use certificate to decrypt the encrypted password

Итак, в этом случае: -  хакеру понадобится 3 вещи, чтобы захватить пароль JDBC, что делает систему менее уязвимой: i) зашифрованный пароль JDBC ii) Магазин JKS iii) Пароль магазина JKS

Теперь вы можете задать вопрос о том, как в JKS хранить пароль, ну, будь то ключ, кодовая фраза или пароль, в системе шифрования-дешифрования, по крайней мере, одна вещь должна быть очень безопасной; в противном случае это подвергает опасности всю систему.... в приведенном выше сценарии сертификат может быть предоставлен каждой машине разработчика, чтобы он мог импортировать его в свой файл jks, защищенный одним и тем же паролем магазина jks. Каждый (разработчик) знал бы только пароль магазина JKS, но никогда Пароль JDBC...

Ответ 4

Обычно вы должны аутентифицировать приложение в базе данных sql только под одним именем пользователя, передавая детали пользователя, если это необходимо, в качестве данных в своих запросах, чтобы вы возвращали данные, относящиеся только к этому конечному пользователю. Указывают ли ваши клиенты, что каждый конечный пользователь должен аутентифицироваться в базе данных как отдельный пользователь?

Ответ 5

Чтобы иметь возможность прозрачно шифровать/дешифровать пароли в вашей базе данных с помощью спящего режима, вам необходимо интегрировать что-то вроде Jasypt.

Домашняя страница: www.jasypt.org См. Раздел: Jasypt + Hibernate 3

Вот как его интегрировать:

  • Загрузите jasypt.jar и добавьте его в свой путь к среде выполнения

  • Я бы предложил использовать зарегистрированный шифр:

<typedef name="encrypted" class="org.jasypt.hibernate.type.EncryptedStringType">
  <param name="encryptorRegisteredName">strongHibernateStringEncryptor</param>
</typedef>
<class name="User" table="USER">
  <property name="password" column="PASSWORD" type="encrypted" />
<class>

Код >

Ответ 7

Обычно это обрабатывается с использованием подхода "sysadmin" - с использованием ОС:

Основная концепция - "внешние параметры конфигурации". Пароли хранятся в открытом тексте в "файле свойств" (который веб-сервер обращается во время выполнения). Пароли защищены путем ограничения доступа к файлам с использованием разрешений на уровне ОС. Как правило, только сотрудники "операций" могут читать/записывать файл, а веб-сервер должен запускаться с правами доступа только для чтения.

Преимущества такого подхода заключаются в следующем:

  • Простота понимания и реализации (без ввода зашифрованных значений)
  • Защищено программным обеспечением, предназначенным для защиты - это одна из немногих вещей, которые делает ОС (также может быть взломан шифрование, если файл можно прочитать)
  • Простая настройка среды разработки/тестирования - просто откройте разрешения для dev/test. Кроме того, только сервер времени выполнения должен иметь надлежащую безопасность.
  • Избегает зависимости от библиотек "без бизнес-ценности" (которые не помогают решить вашу бизнес-проблему).

Ответ 8

Вы можете использовать источник данных JDNI на своем сервере приложений, который будет иметь информацию о соединении для базы данных.

Затем вы можете просто сообщить своему приложению через ваш web.xml, чтобы использовать источник данных на сервере веб-приложений.

Вот как я сделал это на Weblogic 9, используя Hibernate 3:

В Hibernate.cfg.xml

<property name="connection.datasource">jdbc/MYJDNINAME</property>  
<property name="connection.autocommit">true</property> 
<property name="hibernate.connection.release_mode">on_close</property>

В weblogic.xml

    <reference-descriptor>
    <resource-description>
        <res-ref-name>jdbc/MYJDNINAME</res-ref-name>
        <jndi-name>MYJDNINAME</jndi-name>
    </resource-description>
</reference-descriptor>

Аналогичные решения могут использоваться для серверов tomcat и других серверов приложений:

Инструкции Tomcat 6

Ответ 9

Я получил вашу точку зрения KyleM. Вы можете сделать: