Как я могу хешировать пароли в postgresql?

Мне нужно хэшировать некоторые пароли с помощью соли в postgresql, и я не смог найти никакой соответствующей документации о том, как это сделать.

Итак, как я могу хешировать пароли (с некоторыми солями) в postgresql?


person Kzqai    schedule 15.04.2010    source источник


Ответы (3)


Прошло некоторое время с тех пор, как я задал этот вопрос, и теперь я гораздо лучше знаком с криптографической теорией, поэтому вот более современный подход:

Рассуждение

  • Не используйте md5. Не используйте один цикл быстрых хэшей семейства sha. Быстрые хэши помогают злоумышленникам, так что вам это не нужно.
  • Вместо этого используйте ресурсоемкий хэш, такой как bcrypt. Bcrypt проверен временем и масштабируется, чтобы быть готовым к будущему.
  • Не утруждайте себя созданием своей собственной соли, вы можете испортить собственную безопасность или переносимость, полагайтесь на gen_salt(), чтобы генерировать потрясающие уникальные соли для каждого использования самостоятельно.
  • В общем, не будьте идиотом, не пытайтесь написать свою собственную доморощенную крипту, просто используйте то, что предоставили умные люди.

Пакеты установки Debian/Ubuntu

sudo apt-get install postgresql   // (of course)
sudo apt-get install postgresql-contrib libpq-dev   // (gets bcrypt, crypt() and gen_salt())
sudo apt-get install php5-pgsql   // (optional if you're using postgresql with php)

Активируйте crypt() и bcrypt в postgresql в вашей базе данных.

// Create your database first, then:
cd `pg_config --sharedir` // Move to the postgres directory that holds these scripts.
echo "create extension pgcrypto" | psql -d yOuRdATaBaSeNaMe // enable the pgcrypo extension

Используйте crypt() и gen_salt() в запросах

Сравните :pass к существующему хешу с:

select * from accounts where password_hash = crypt(:pass, password_hash);
//(note how the existing hash is used as its own individualized salt)

Создайте хэш :password с большой случайной солью:

insert into accounts (password) values crypt(:password, gen_salt('bf', 8));
//(the 8 is the work factor)

Немного предпочтительнее хэширование bcrypt из-в-Php.

В php 5.5 и выше есть password_* функций, которые позволяют тривиально просто хешировать пароли с помощью bcrypt (время!), и есть библиотека обратной совместимости для версий ниже этого. Как правило, хеширование в любом случае возвращается к оболочке системного вызова linux для более низкой загрузки ЦП, хотя вы можете убедиться, что оно установлено на вашем сервере. См.: https://github.com/ircmaxell/password_compat (требуется php 5.3.7+)

Будьте осторожны с регистрацией

Обратите внимание, что с pg_crypto пароли находятся в открытом тексте во время передачи из браузера в php и в базу данных. Это означает, что они могут быть зарегистрированы в виде открытого текста из запросов, если вы не будете осторожны с журналами базы данных. например наличие журнала медленных запросов postgresql может перехватывать и регистрировать пароль из выполняемого запроса на вход.

В итоге

Используйте php bcrypt, если можете, это уменьшит время, в течение которого пароль остается нехешированным. Постарайтесь убедиться, что в вашей Linux-системе установлен bcrypt в crypt(), чтобы он работал. Настоятельно рекомендуется обновить как минимум до php 5.3.7+, так как реализация php немного глючит с php 5.3.0 до 5.3.6.9 и неуместно возвращается к сломанному DES без предупреждения в php 5.2.9 и ниже.

Если вам нужно/нужно хеширование в Postgres, установка bcrypt — это то, что вам нужно, так как установленные по умолчанию хэши старые и неработающие (md5 и т. д.).

Вот ссылки для дополнительного чтения по теме:

person Kzqai    schedule 08.09.2013
comment
Итак, лучше делать хеширование с помощью pgcrypto, а не на стороне приложения? В общем, должно ли рутинное хэширование, генерация руководств и т. д. выполняться pg вместо приложения? Спасибо! - person paulkon; 19.10.2014
comment
Я отредактировал свой ответ выше с более подробной информацией. Поскольку pg_crypto требует, чтобы открытый текст пароля попадал в запросы к базе данных, с потенциальными проблемами, когда возникают случайные журналы запросов, я рекомендую сначала попробовать in-php password_hash() в эти дни, если вы можете это сделать. Bcrypt — это современный уровень хеширования паролей, поэтому он превосходит другие варианты, будь то в postgresql или php. Хеширование Bcrypt является ресурсоемким по своей конструкции, поэтому, если вы используете его в php, попробуйте получить доступ к bcrypt из crypt(), чтобы уменьшить использование ресурсов вашего сервера. - person Kzqai; 19.10.2014
comment
не используйте md5, он сломан, postgres слышит, что он использует md5, потому что это то, что он использует для хеширования своих паролей... - person xenoterracide; 25.02.2017
comment
У меня был ГИГАНТСКИЙ психоз, и я переписал кучу кода, прочитав здесь о проблеме с логированием. Затем я понял, что использовал параметризованные запросы, а это означало, что в моих журналах базы данных не было открытого текста. Примечательно, что при использовании шифрования pgp мне также нужно было передать строку открытого/закрытого ключа в качестве параметра, чтобы избежать ведения журнала. - person deltree; 28.04.2017
comment
Postgres 11+ использует схему паролей scram-sha-256 (от RFC 7677). Поскольку он использует SCRAM, в некоторых случаях он может быть альтернативой password_*-функциям PHP. - person Code4R7; 31.12.2019
comment
Насколько я понимаю, sha-256 — это быстрый хеш, вам нужны медленные хэши для паролей, чтобы замедлить атакующего, если он получит копию данных вашей базы данных. - person Kzqai; 21.04.2021

Приложение должно хэшировать свои пароли, используя функцию получения ключа, такую ​​как bcrypt или pbkdf2. Дополнительная информация о безопасном хранении паролей.

... но иногда вам все еще нужны криптографические функции в базе данных.

Вы можете использовать pgcrypto, чтобы получить доступ к sha256, который является членом Семья Ша2. Имейте в виду, что sha0, sha1 md4 и md5 очень повреждены и не должны никогда использоваться для хэшей паролей.

Ниже приведен хороший метод хеширования паролей:

digest("salt"||"password"||primary_key, "sha256")

Соль должна быть большим случайно сгенерированным значением. Эта соль должна быть защищена, потому что хэши не могут быть взломаны, пока соль не будет восстановлена. Если вы храните соль в базе данных, ее можно получить вместе с хэшем пароля с помощью sql-инъекции. Объединение первичного ключа используется для предотвращения того, чтобы 2 человека имели одинаковый хэш пароля, даже если у них одинаковый пароль. Конечно, эту систему можно было бы улучшить, но она намного лучше, чем большинство систем, которые я видел.

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

person rook    schedule 15.04.2010
comment
Да, я немного опоздал. Удалил мой ответ, так как ты был первым и более подробным ;). - person Tagore Smith; 15.04.2010
comment
@T Дункан Смит, спасибо, чувак, я дал тебе несколько баллов за то, что ты хороший член SO. - person rook; 15.04.2010
comment
Хммм, я полагаю, что проблема с ведением журнала — хороший момент, но по практическим причинам я хочу иметь возможность запускать оператор sql, чтобы не персонализировать пароли (вместе с другой личной информацией), чтобы опубликовать очищенную базу данных. - person Kzqai; 15.04.2010
comment
Эээ, не могли бы вы уточнить утверждение. Соль должна быть большим случайно сгенерированным значением? Могу ли я добавить эту соль случайного значения с помощью традиционных средств конкатенации строк? Имеет ли смысл: update account set pswhash = crypt('global salt' || 'new password' || 'user created date', gen_salt('sha256')) where account_id = 5 или что-то в этом роде для создания начального хэша? Или я что-то упустил в функции crypt()? - person Kzqai; 15.04.2010
comment
Да, используйте конкатенацию строк случайного значения, а также используйте функцию дайджеста. pswhash = digest('global salt'||"password"||primary_key, "sha256") Использование идентификатора гарантирует, что полученный хеш будет неверным, даже если 2 человека используют один и тот же пароль и создают учетную запись в один и тот же день. Вы можете внести некоторые улучшения в генерацию соли, но это намного лучше, чем большинство реализаций, которые я видел. - person rook; 15.04.2010
comment
Да, я пытался получить доступ к pgcrypto, но установка пакета (postgresql-contrib), в котором он должен быть, похоже, не разрешает доступ, как вы получаете доступ к дайджесту ()? - person Kzqai; 16.04.2010
comment
Ах, похоже, мне нужно запустить некоторый sql из модуля, прежде чем функции станут доступны, а не просто запустить установку. - person Kzqai; 16.04.2010
comment
Документация на странице pgcrypto довольно хороша и объясняет, почему это действительно глупый способ сделать хэш. На самом деле рецепт катастрофы. Вместо этого используйте функцию шифрования с хэшем «bf». Узнайте больше, в том числе о том, как сделать собственный взлом с несколькими миллиардами солевых хэшей в секунду, на codahale.com/how-to-safely-store-a-password - person nealmcb; 28.03.2011
comment
Этот последний комментарий @nealmcb верен, но он не говорит, почему, он оставляет его для вас, чтобы вы могли найти ответ в документации PGSQL. Причина в том, что если вы вычисляете хэш в БД, то пароль отправляется по сети в БД, где он может быть перехвачен. Эту проблему можно смягчить, зашифровав соединение с БД, но я бы сказал, что лучше избегать отправки открытого пароля по сети больше раз, чем это абсолютно необходимо, поскольку каждый раз это потенциальная возможность для хакера перехватить его. - person Nate C-K; 23.01.2014

Примеры и документация по: http://www.postgresql.org/docs/8.3/static/pgcrypto.html

UPDATE ... SET pswhash = crypt('new password', gen_salt('md5'));

SELECT pswhash = crypt('entered password', pswhash) FROM ... ;
person Matej Puntar    schedule 15.04.2010
comment
Да, pgcrypto выглядит как то, что я ищу, но мне трудно понять, как его использовать, говорит ли пример использования, что мне не нужно жестко кодировать свою соль в хэш? т.е. Мне больше не нужно предоставлять свои собственные данные соли, такие как: update account set pswhash = crypt('global salt' || 'new password' || 'user created date', gen_salt('sha256')) where account_id = 5 ? или соление все еще ручной процесс? - person Kzqai; 15.04.2010
comment
Использование алгоритма md5 без подсчета итераций (адаптация к увеличению скорости хэширования с течением времени) — это прямой путь к катастрофе. Вместо этого используйте 'bf': gen_salt('bf'). Узнайте больше, в том числе о том, как сделать собственный взлом с несколькими миллиардами солевых хэшей в секунду, на codahale.com/how-to-safely-store-a-password - person nealmcb; 28.03.2011
comment
@Tchalvak прав - вам больше не нужно предоставлять свои собственные данные о соли. На самом деле gen_salt также кодирует алгоритм, который на самом деле должен быть «bf», как я заметил выше — см. ссылку для получения дополнительной информации. Учитывая использование «bf», этот ответ намного лучше, чем ответ ладьи. - person nealmcb; 28.03.2011
comment
Это правильный ответ. Вы не должны использовать функцию digest для шифрования паролей, это недостаточно безопасно. Просто убедитесь, что вы используете алгоритм Blowfish, а не MD5. - person GetFree; 05.06.2013