Выберите хэши паролей DBMS_CRYPTO в Oracle 11g

В настоящее время я хэширую свое поле пароля в базе данных Oracle, используя DBMS_CRYPTO.HASH, Однако в этот момент мне нужно разрешить моему Java-приложению иметь возможность аутентифицировать пароль при вводе пользователем способом, аналогичным тому, что делает MySQL. Что-то вроде:

SELECT *
FROM user_login_table
WHERE password = SHA1('MyPassword');

В настоящее время я хэширую с помощью следующей процедуры:

CREATE OR REPLACE PROCEDURE 
  MUNGAI.p_auth_insert_user (
    par_username in varchar2,
    par_password in varchar2,
    par_work in varchar2
  )
IS l_hash raw(2000);
  BEGIN
    l_hash :=
      dbms_crypto.hash(
        utl_i18n.string_to_raw(par_password || par_work || upper(par_username),
        'AL32UTF8'
      ),
      dbms_crypto.hash_sh1
    );

    INSERT INTO user_login_table (user_name, p_word, work_class)
    VALUES (par_username, l_hash, par_work);
  END p_auth_insert_user;
/

Затем я выполняю следующую процедуру, чтобы вставить в таблицу:

EXEC MUNGAI.p_auth_insert_user('MUNGAI', 'gatungo', '999')

Есть ли лучший способ добиться этого в моей ситуации? Я использую Oracle 11g, если это имеет значение.

2 ответа

Решение

Предполагая, что хешированный пароль хранится в RAW колонка в user_login_tableВы могли бы просто позвонить dbms_crypto.hash в вашем заявлении SQL. В зависимости от того, как вы делаете начальное хэширование (в частности, как вы конвертируете простой текстовый пароль в RAW и какой алгоритм и параметры вы используете), как-то так будет работать

select * 
  from user_login_table 
 where password = dbms_crypto.hash( utl_i18n.string_to_raw( 'MYPassword', 'AL32UTF8' ),
                                    <<whatever hash algorithm you want to use>> );

Конечно, как правило, вы должны определить свою собственную функцию, которая хэширует пароль, чтобы вы могли встраивать логику того, как преобразовать строку в RAW и указать алгоритм хеширования в одном месте. Затем вы вызываете эту новую функцию из вашего оператора SQL. Это функция, где, по-видимому, вы также добавили бы подходящую соль. Тогда вы будете использовать эту функцию как для первоначального заполнения хэшированных данных в таблице, так и для проверки хэшей паролей в будущем.

Я также предположил бы, что ваш фактический запрос будет иметь предикат username в дополнение к паролю

select * 
  from user_login_table 
 where password = new_function_name( 'MYPassword' )
   and username = 'YourUserName'

В противном случае отправленный вами запрос просто подтвердит, что пароль совпадает с паролем кого-либо в базе данных, а не конкретного человека, который пытался войти в систему. Кроме того, он вернул бы несколько строк, если бы два человека имели одинаковый хэш пароля.

Поэтому в вашем конкретном случае я бы ожидал, что вы захотите создать новую функцию hash_password

CREATE OR REPLACE function MUNGAI.hash_password(par_username in varchar2,
                              par_password in varchar2,
                              par_work in varchar2
                             )
  return raw
is
  l_hash raw(2000);
begin
  l_hash :=
   dbms_crypto.hash
     (utl_i18n.string_to_raw (par_password || par_work || upper(par_username),
                              'AL32UTF8'
                             ),
      dbms_crypto.hash_sh1
     );
  return l_hash;
end;

Затем вы вызываете эту функцию из вашей процедуры вставки

CREATE OR REPLACE procedure MUNGAI.p_auth_insert_user (par_username in varchar2,
                              par_password in varchar2,
                              par_work in varchar2
                             )
is
  l_hash raw(2000);
begin
  l_hash := hash_password( par_username, par_password, par_work );

  insert into user_login_table
    (user_name, p_word, work_class)
   values
    (par_username, l_hash, par_work);
end p_auth_insert_user;
/

Ваш запрос будет

select * 
  from user_login_table 
 where password = new_function_name( username, 
                                     'MYPassword', 
                                     <<whatever `par_work` is supposed to be>> )
   and username = 'YourUserName'

Я бы порекомендовал вам сделать хеширование в коде, вне базы данных. Таким образом, вы независимы от поставщика БД и вам нужно записать реализацию хеширования только в одно место. Столбец БД может быть обычным varchar.

Это было бы что-то вроде этого:

  1. При добавлении пользователя / смене пароля хеш-код предоставляет пароль с правильным алгоритмом и солью до вставки / обновления. Я бы порекомендовал как минимум SHA-256. Сохраните соль рядом с хешем тоже!

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

Советы по перемешиванию / засолке, например, здесь: http://crackstation.net/hashing-security.htm

Другие вопросы по тегам