Аутентификация в спящем режиме без паролей, хранящихся в виде простого текста - PullRequest
15 голосов
/ 21 апреля 2011

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

Два вопроса:

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

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

Мое решение :

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

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

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

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

Ответы [ 9 ]

14 голосов
/ 25 мая 2011

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

вы можете указать 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 всегда будет выдавать одно и то же значение хеш-значения для одного и того же ввода, вы можете указать JDBCRealm Tomcat использовать этот алгоритм для проверки паролей.

<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, который имел ожидаемый формат и извлекал его данные из пользовательских данных моих веб-приложений:

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

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

7 голосов
/ 27 мая 2011

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

В настоящее время вы должны настроить JDBC passsword 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) Один из основных способов может быть в основном: - Вы можете зашифровать свой пароль с помощью любого jlog 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()

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

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

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

РЕДАКТИРОВАНИЕ ДЛЯ УТОЧНЕНИЯ комментария keylM ПО КАК ШИФРОВАТЬ ПАРОЛЬ JDBC

Допустим, у вас есть пара закрытых и открытых ключей:= privare.key и public.cer.Вы можете зашифровать пароль JDBC с помощью закрытого ключа и сохранить зашифрованный пароль в файле конфигурации.Вы можете использовать OpenSSL для импорта открытого сертификата в файл jks (хранилище ключей java) и поместить его в свой 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 ...

5 голосов
/ 22 апреля 2011

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

2 голосов
/ 24 мая 2011

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

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

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

2 голосов
/ 24 мая 2011

Проверьте ответы на аналогичный вопрос, Как использовать зашифрованный пароль в apache BasicDataSource? .

2 голосов
/ 23 мая 2011

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

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

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

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

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

</p> <pre><code><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>

1 голос
/ 25 мая 2011

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

  1. Создать обычный текстовый файл или реестр (в случае Windows), разместить где-нибудь на другом сервере в зашифрованном режиме.

  2. ИЛИ вы можете использовать этот алгоритм одноразового пароля Лампорта

1 голос
/ 24 мая 2011

Вы можете использовать источник данных 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

1 голос
/ 24 мая 2011

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

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

Преимущества этого подхода:

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