F.12. credcheck#
F.12. credcheck #
F.12.1. О расширении credcheck #
Проверка имени пользователя/пароля Tantor SE
Версия: 2.6.0
Авторское право (c) 2021-2023 MigOps Inc.
Авторское право (c) 2023 Gilles Darold
F.12.2. Описание #
Расширение credcheck
Tantor SE позволяет проводить
общие проверки учетных данных, которые будут применяться при создании пользователя,
при изменении пароля и переименовании пользователя. Используя
это расширение, можно определить набор правил:
разрешить определенный набор учетных данных
отклонить определенный тип учетных данных
отклонять пароль, который можно легко взломать
обеспечивает использование срока действия пароля с минимальным сроком в дни
определите политику повторного использования паролей
определять количество неудачных попыток аутентификации, допустимых до блокировки пользователя
Это расширение разработано на основе хука check_password_hook
из Tantor SE.
Это расширение предоставляет все проверки в виде настраиваемых параметров.
Настройки по умолчанию не применяют сложные проверки и пытаются разрешить большинство учетных данных. Используя команду
SET credcheck.<check-name> TO <some value>;
можно применить новые настройки для проверки учетных данных. Настройки могут быть изменены только суперпользователем.
F.12.3. Установка #
Добавьте credcheck
к параметру конфигурации shared_preload_libraries
в вашем файле postgresql.conf
, затем перезапустите базу данных Tantor SE,
чтобы применить изменения.
Проверьте это расширение в одной сессии, используя команду LOAD 'credcheck';
Tantor SE.
Чтобы включить это расширение для всех сессий, выполните команду CREATE EXTENSION credcheck;
.
F.12.4. Проверки #
Пожалуйста, найдите ниже список общих проверок, которые можно применить к учетным данным.
Проверка | Тип | Описание | Значение настройки | Принято | Не принято |
---|---|---|---|---|---|
username_min_length
| имя пользователя | минимальная длина имени пользователя | 4 | ✓ abcd | ✘ abc |
username_min_special
| имя пользователя | минимальное количество специальных символов | 1 | ✓ a@bc | ✘ abcd |
username_min_digit
| имя пользователя | минимальное количество цифр | 1 | ✓ a1bc | ✘ abcd |
username_min_upper
| имя пользователя | минимальное количество заглавных букв | 2 | ✓ aBC | ✘ aBc |
username_min_lower
| имя пользователя | минимальное количество строчных букв | 1 | ✓ aBC | ✘ ABC |
username_min_repeat
| имя пользователя | максимальное количество повторений символа | 2 | ✓ aaBCa | ✘ aaaBCa |
username_contain_password
| имя пользователя | имя пользователя не должно содержать пароль | включено | ✓ имя пользователя - пароль | ✘ имя пользователя + пароль |
username_contain
| имя пользователя | имя пользователя должно содержать один из этих символов | a,b,c | ✓ ade | ✘ efg |
username_not_contain
| имя пользователя | имя пользователя не должно содержать один из этих символов | x,y,z | ✓ ade | ✘ axf |
username_ignore_case
| имя пользователя | игнорировать регистр при выполнении вышеуказанных проверок | включено | ✓ Ade | ✘ aXf |
password_min_length
| пароль | минимальная длина пароля | 4 | ✓ abcd | ✘ abc |
password_min_special
| пароль | минимальное количество специальных символов | 1 | ✓ a@bc | ✘ abc |
password_min_digit
| пароль | минимальное количество цифр в пароле | 1 | ✓ a1bc | ✘ abc |
password_min_upper
| пароль | минимальное количество прописных символов | 1 | ✓ Abc | ✘ abc |
password_min_lower
| пароль | минимальное количество строчных символов | 1 | ✓ aBC | ✘ ABC |
password_min_repeat
| пароль | максимальное количество повторений символа | 2 | ✓ aab | ✘ aaab |
password_contain_username
| пароль | пароль не должен содержать пароль | включено | ✓ пароль - имя пользователя | ✘ пароль + имя пользователя |
password_contain
| пароль | пароль должен содержать эти символы | a,b,c | ✓ ade | ✘ xfg |
password_not_contain
| пароль | пароль не должен содержать эти символы | x,y,z | ✓ abc | ✘ axf |
password_ignore_case
| пароль | игнорировать регистр при выполнении вышеуказанных проверок | включено | ✓ Abc | ✘ aXf |
password_valid_until
| пароль | принудительное использование предложения VALID UNTIL в операторе CREATE ROLE с минимальным количеством дней | 60 |
✓ CREATE ROLE abcd VALID UNTIL (now()+3
months ::interval)::date
| ✘ CREATE ROLE abcd LOGIN; |
password_valid_max
| пароль | принудительное использование предложения VALID UNTIL в операторе CREATE ROLE с максимальным количеством дней | 365 |
✓ CREATE ROLE abcd VALID UNTIL (now()+6
месяцев ::interval)::date
|
✘ CREATE ROLE abcd VALID UNTIL (now()+2
года ::interval)::date;
|
Существует также GUC credcheck.whitelist
, который можно использовать для
установки списка имен пользователей, разделенных запятыми, чтобы исключить
их из проверки парольной политики. Например:
credcheck.whitelist = 'admin,supuser'
отключит любую политику проверки учетных данных для пользователя с именем admin
и supuser
.
F.12.5. Примеры #
Давайте начнем с простой проверки, так как каждое имя пользователя должно быть длиной не менее 4 символов.
postgres=# SHOW credcheck.username_min_length; credcheck.username_min_length ------------------------------- 4 (1 row) postgres=# CREATE USER abc WITH PASSWORD 'pass'; ERROR: username length should match the configured credcheck.username_min_length postgres=# CREATE USER abcd WITH PASSWORD 'pass'; CREATE ROLE
Давайте добавим еще одну проверку, так как каждое имя пользователя должно содержать специальный символ в нем.
postgres=# SHOW credcheck.username_min_special; credcheck.username_min_special -------------------------------- 1 (1 row) postgres=# CREATE USER abcd WITH PASSWORD 'pass'; ERROR: username does not contain the configured credcheck.username_min_special characters postgres=# CREATE USER abcd$ WITH PASSWORD 'pass'; CREATE ROLE
Давайте добавим еще одну проверку для имени пользователя, где имя пользователя не должно содержать более 1 соседнего повторяющегося символа.
postgres=# show credcheck.username_min_repeat ; credcheck.username_min_repeat ------------------------------- 1 (1 row) postgres=# CREATE USER week$ WITH PASSWORD 'pass'; ERROR: username characters are repeated more than the configured credcheck.username_min_repeat times postgres=# CREATE USER weak$ WITH PASSWORD 'pass'; CREATE ROLE postgres=# SHOW credcheck.username_min_repeat ; credcheck.username_min_repeat ------------------------------- 2 (1 row) postgres=# CREATE USER week$ WITH PASSWORD 'pass'; CREATE ROLE
Теперь давайте добавим некоторые проверки для пароля. Давайте начнем с проверки, что пароль не должен содержать следующие символы (!@=$#).
postgres=# SHOW credcheck.password_not_contain ; credcheck.password_not_contain -------------------------------- !@=$# (1 row) postgres=# CREATE USER abcd$ WITH PASSWORD 'p@ss'; ERROR: password does contain the configured credcheck.password_not_contain characters postgres=# CREATE USER abcd$ WITH PASSWORD 'pass'; CREATE ROLE
Давайте добавим еще одну проверку для пароля, так как пароль не должен содержать имя пользователя.
postgres=# SHOW credcheck.password_contain_username ; credcheck.password_contain_username ------------------------------------- on (1 row) postgres=# CREATE USER abcd$ WITH PASSWORD 'abcd$xyz'; ERROR: password should not contain username -- OK, ignore case is disabled postgres=# CREATE USER abcd$ WITH PASSWORD 'ABCD$xyz'; CREATE ROLE postgres=# CREATE USER abcd$ WITH PASSWORD 'axyz'; CREATE ROLE
Давайте проведем проверки, игнорируя регистр.
postgres=# SHOW credcheck.password_ignore_case; credcheck.password_ignore_case -------------------------------- on (1 row) postgres=# CREATE USER abcd$ WITH PASSWORD 'ABCD$xyz'; ERROR: password should not contain username postgres=# CREATE USER abcd$ WITH PASSWORD 'A$xyz'; CREATE ROLE
Давайте добавим еще одну проверку для пароля, так как пароль не должен содержать повторяющихся символов, расположенных рядом.
postgres=# SHOW credcheck.password_min_repeat ; credcheck.password_min_repeat ------------------------------- 3 (1 row) postgres=# CREATE USER abcd$ WITH PASSWORD 'straaaangepaasssword'; ERROR: password characters are repeated more than the configured credcheck.password_min_repeat times postgres=# CREATE USER abcd$ WITH PASSWORD 'straaangepaasssword'; CREATE ROLE
credcheck также может обеспечить использование срока действия пароля путем проверки опции VALID UNTIL, используемой в командах CREATE или ALTER ROLE.
postgres=# SET credcheck.password_valid_until = 30; SET postgres=# SET credcheck.password_valid_max = 180; SET postgres=# CREATE USER abcd$; ERROR: require a VALID UNTIL option with a date older than 30 days postgres=# CREATE USER abcd$ VALID UNTIL '2022-12-21'; ERROR: require a VALID UNTIL option with a date older than 30 days postgres=# ALTER USER abcd$ VALID UNTIL '2022-12-21'; ERROR: require a VALID UNTIL option with a date older than 30 days postgres=# ALTER USER abcd$ VALID UNTIL '2025-12-21'; ERROR: require a VALID UNTIL option with a date not beyond 180 days
Если вы включили использование cracklib для проверки простоты пароля, вы можете получить такие сообщения:
postgres=# CREATE USER my_easy_password with password 'pass123'; ERROR: password is easily cracked
F.12.6. Политика повторного использования паролей #
Tantor SE поддерживает отслеживания срока действия пароля, все другие виды принудительного применения парольной политики предоставляются с помощью расширений. С расширением credcheck, можно принудительно установить длину пароля, задать обязательное определенное количество различных типов символов и сопоставлять его с именем в учетной записи пользователя.
Но одной вещи не хватало, отсутствовала политика запрета повторного использования паролей. Это означало, что когда пользователю требовалось изменить свой пароль, он мог просто повторно использовать свой текущий пароль!
Расширение credcheck добавляет “Политику повторного использования паролей” в версии 1.0. Чтобы использовать эту функцию, расширение credcheck ДОЛЖНО быть добавлено в параметр конфигурации shared_preload_libraries
.
Все пароли пользователей историруются в общей памяти вместе с отметками времени, когда эти пароли были установлены. История паролей сохраняется в файле с именем $PGDATA/global/pg_password_history
для загрузки в общую память при запуске. Этот файл должен быть включен в резервные копии, если вы не хотите потерять историю паролей, надеюсь, pg_basebackup позаботится об этом. Пароли хранятся и сравниваются в виде хешей sha256, никогда в открытом виде.
Размер списка использованных паролей по умолчанию установлен на 65535 записей и
может быть скорректирован с помощью директивы конфигурации
credcheck.history_max_size
. Изменение этого GUC требует перезапуска Tantor SE. Одна
запись в списке занимает 144 байта, поэтому по умолчанию
выделяется около 10 МБ дополнительной общей памяти для списка использованных паролей.
Два параметра позволяют управлять поведением этой функции:
credcheck.password_reuse_history
: количество различных паролей, установленных до того, как пароль может быть повторно использован.credcheck.password_reuse_interval
: количество времени, необходимое, прежде чем пароль можно будет использовать снова.
Значение по умолчанию для этих настроек равно 0, что означает, что все политики повторного использования паролей отключены.
История паролей состоит из паролей, которые пользователь использовал в прошлом. Credcheck может ограничить выбор новых паролей из этой истории:
Если учетная запись ограничена на основе количества изменений пароля, новый пароль не может быть выбран из
password_reuse_history
самых последних паролей. Например, если минимальное количество изменений пароля установлено равным 3, новый пароль не может совпадать с любым из трех самых последних паролей.Если учетная запись ограничена по прошедшему времени, новый пароль не может быть выбран из паролей в истории, которые новее, чем
password_reuse_interval
дней. Например, если интервал повторного использования пароля установлен на 365, новый пароль не должен быть среди ранее выбранных в течение последнего года.
Чтобы иметь возможность просматривать содержимое истории, в базе данных, в которой вы создали расширение credcheck, предоставляется представление. Представление называется public.pg_password_history
. Это представление видно всем.
Суперпользователь также может сбросить содержимое истории паролей, вызвав функцию с именем public.pg_password_history_reset()
. Если она вызывается без аргумента, вся история паролей будет очищена. Чтобы удалить только записи, зарегистрированные для одного пользователя, просто передайте его имя в качестве параметра. Эта функция возвращает количество удаленных записей из истории.
Пример:
SET credcheck.password_reuse_history = 2; CREATE USER credtest WITH PASSWORD 'H8Hdre=S2'; ALTER USER credtest PASSWORD 'J8YuRe=6O'; SELECT rolename, password_hash FROM pg_password_history WHERE rolename = 'credtest' ORDER BY password_date; rolename | password_hash ----------+------------------------------------------------------------------ credtest | 7488570b80076cf9da26644d5eeb316c4768ff5bee7bf319344e7bb328032098 credtest | e61e58c22aa6bf31a92b385932f7d0e4dbaba24fa3fdb2982510d6c72a961335 (2 rows) -- fail, the credential is still in the history ALTER USER credtest PASSWORD 'J8YuRe=6O'; ERROR: Cannot use this credential following the password reuse policy -- Reset the password history SELECT pg_password_history_reset(); pg_password_history_reset --------------------------- 2 (1 row)
Пример для интервала повторного использования пароля:
SET credcheck.password_reuse_history = 1; SET credcheck.password_reuse_interval = 365; -- Add a new password in the history and set its age to 100 days ALTER USER credtest PASSWORD 'J8YuRe=6O'; SELECT pg_password_history_timestamp('credtest', now()::timestamp - '100 days'::interval); pg_password_history_timestamp ------------------------------- 1 (1 row) SELECT * FROM pg_password_history WHERE rolename = 'credtest'; rolename | password_date | password_hash ----------+-------------------------------+------------------------------------------------------------------ credtest | 2022-12-15 13:41:06.736775+03 | c38cf85ca6c3e5ee72c09cf0bfb42fb29b0f0a3e8ba335637941d60f86512508 (1 row) -- fail, the password is in the history for less than 1 year ALTER USER credtest PASSWORD 'J8YuRe=6O'; ERROR: Cannot use this credential following the password reuse policy -- Change the age of the password to exceed the 1 year interval SELECT pg_password_history_timestamp('credtest', now()::timestamp - '380 days'::interval); pg_password_history_timestamp ------------------------------- 2 (1 row) -- success, the old password present in the history has expired and will be removed ALTER USER credtest PASSWORD 'J8YuRe=6O'; SELECT rolename, password_hash FROM pg_password_history WHERE rolename = 'credtest'; rolename | password_date | password_hash ----------+-------------------------------+------------------------------------------------------------------ credtest | 2023-03-25 13:42:37.387629+03 | c38cf85ca6c3e5ee72c09cf0bfb42fb29b0f0a3e8ba335637941d60f86512508 (1 row)
Функция pg_password_history_timestamp()
предназначена только для тестирования и позволяет суперпользователю изменить временную метку всех зарегистрированных паролей в истории.
F.12.7. Блокировка при неудачной аутентификации #
Tantor SE не имеет механизма для ограничения количества
попыток неудачной аутентификации перед тем, как пользователь будет заблокирован. С
расширением credcheck, после количества неудачных попыток аутентификации,
определенного директивой конфигурации
credcheck.max_auth_failure
, пользователь может быть
заблокирован и больше никогда не сможет подключиться, даже если позже введет правильный
пароль.
Расширение credcheck добавляет функцию “Блокировка при неудачной аутентификации”
в версии 2.0. Для использования этой функции расширение credcheck
ДОЛЖНО быть добавлено в
параметр конфигурации shared_preload_libraries
.
Все неудачные попытки аутентификации пользователей регистрируются в общей памяти с отметками времени, когда пользователь был заблокирован. История неудачных попыток аутентификации сохраняется только в памяти, что означает, что история теряется при перезапуске Tantor SE. Я не видел интереса в восстановлении кэша при запуске
Размер кэша отказов аутентификации по умолчанию установлен на 1024 записи и
может быть изменен с помощью директивы конфигурации credcheck.auth_failure_cache_size
.
Изменение этого GUC требует перезапуска Tantor SE.
Два параметра позволяют управлять поведением этой функции:
credcheck.max_auth_failure
: количество неудачных попыток аутентификации, допустимых для пользователя перед блокировкой.credcheck.reset_superuser
: заставить суперпользователя не быть заблокированным или сбросить заблокированного суперпользователя, если установлено значение true.
Значение по умолчанию для первой настройки — 0
, что означает, что
функция блокировки при неудачной аутентификации отключена. Значение по умолчанию для
второй настройки — false
, что означает, что
суперпользователь postgres
может быть заблокирован.
В случае, если суперпользователь postgres
был заблокирован, он
больше не сможет войти в систему. Если нет другой учетной записи суперпользователя,
которую можно использовать для сброса записи заблокированного суперпользователя, установите
директиву конфигурации credcheck.reset_superuser
в значение true
в файле postgresql.conf и
отправьте сигнал SIGHUP процессу PostgreSQL, чтобы он
перечитал конфигурацию. В следующий раз, когда суперпользователь попытается
подключиться, запись о неудачной аутентификации будет удалена.
Пример: kill -1 1234
Суперпользователь также может сбросить содержимое кэша заблокированных пользователей, вызвав
функцию с именем public.pg_banned_role_reset()
. Если она вызывается
без аргумента, весь кэш заблокированных будет очищен. Чтобы удалить только запись,
зарегистрированную для одного пользователя, просто передайте его имя в качестве параметра. Эта функция возвращает
количество записей, удаленных из кэша. Перезапуск Tantor SE также очищает кэш.
Пример:
psql -h localhost -U toban_user -d gilles Password for user toban_user: psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "toban_user" connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "toban_user" psql -h localhost -U toban_user -d gilles Password for user toban_user: psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "toban_user" connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "toban_user" psql -h localhost -U toban_user -d gilles Password for user toban_user: psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: rejecting connection, user 'toban_user' has been banned connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: rejecting connection, user 'toban_user' has been banned
test=# SELECT * FROM pg_banned_role; roleid | failure_count | banned_date --------+---------------+---------------------------- 250362 | 2 | 2023-06-09 20:33:58.490273 (1 row) test=# SELECT pg_banned_role_reset(); pg_banned_role_reset ---------------------- 1 (1 row) test=# SELECT * FROM pg_banned_role; roleid | failure_count | banned_date --------+---------------+------------- (0 rows)
и затем разрешается еще одна попытка входа:
psql -h localhost -U toban_user -d gilles Password for user toban_user: psql: error: connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "toban_user" connection to server at "localhost" (127.0.0.1), port 5432 failed: FATAL: password authentication failed for user "toban_user"
F.12.8. Задержка аутентификации #
Эта функция позволяет сделать паузу при сбое аутентификации. Установка credcheck.auth_delay_ms
вызывает
задержку сервера на заданное количество миллисекунд перед сообщением о сбое аутентификации.
Это усложняет атаки методом подбора паролей к базе данных.
F.12.9. Ограничения #
Это расширение работает только для обычных текстовых паролей.
Пример
postgres=# CREATE USER user1 PASSWORD 'this is some plain text'; CREATE ROLE
Если какой-либо пользователь попытается создать пользователя с зашифрованным паролем, будет выдана ошибка.
Пример
postgres=# CREATE USER user1 PASSWORD 'md55e4cc86d2d6a8b73bbefc4d5b91baa45'; ERROR: password type is not a plain text
Чтобы разрешить использование зашифрованного пароля в CREATE или ALTER ROLE,
включите настройку пользовательской переменной конфигурации credcheck.encrypted_password_allowed
.
Проверки имени пользователя не будут применяться при создании пользователя без пароля и при переименовании пользователя, если у пользователя не определен пароль.
Пример (проверки имени пользователя здесь не будут вызываться)
postgres=# CREATE USER user1;
Пример (проверки имени пользователя здесь не будут вызываться)
postgres=# ALTER USER user1 RENAME to test_user;
Пример (проверки имени пользователя будут вызываться здесь и в операторе переименования)
postgres=# CREATE USER user1 PASSWORD 'this is some plain text'; CREATE ROLE postgres=# ALTER USER user1 RENAME to test_user;
F.12.11. Лицензия #
Это расширение является свободным программным обеспечением, распространяемым под лицензией PostgreSQL.
Copyright (c) 2021-2023 MigOps Inc. Copyright (c) 2023 Gilles Darold Copyright (c) 2024 HexaCluster Corp
F.12.12. Заслуги #
Выражаем благодарность автору расширения passwordcheck
Благодаря автору расширения password policy
Выражаем благодарность автору блога Mickael Paquier, доступному по ссылке здесь