PostgreSQL: SCRAM включён, а роли на MD5 — как перейти
АйТи Фреш
1С и базы данных

В PostgreSQL включили SCRAM, а старые роли всё ещё на MD5: переводим без остановки приложений

Автор: , директор ООО «АйТи-Фреш» · · ~16 мин чтения
Замена старых ключей на новые в серверной стойке: переход PostgreSQL с MD5 на SCRAM без остановки
Роли переезжают по одной, а соединения при этом не рвутся.

Включить password_encryption = 'scram-sha-256' мало: параметр действует только в момент установки пароля, поэтому старые роли так и остаются с MD5-секретом. Переводить их нужно по одной, заново задавая пароль, а pg_hba.conf менять в самом конце. Ниже порядок, проверки клиентов и разбор на живом кейсе.

Почему параметр SCRAM есть, а роли всё равно на MD5

Самая частая история, которую я вижу на проверках: администратор выставил в postgresql.conf строку password_encryption = 'scram-sha-256', перезагрузил конфигурацию, поставил галочку в чек-листе и пошёл пить чай. Через полгода аудит показывает, что половина ролей по-прежнему хранит пароль в виде MD5-хэша. Не потому, что что-то сломалось, а потому, что параметр никогда не был конвертером. Если вы ведёте PostgreSQL для 1С и учётных систем, эта проверка должна стоять в списке рядом с бэкапом.

Что говорит документация, без вольностей. Параметр password_encryption определяет алгоритм, которым шифруется пароль в момент, когда он задаётся командой CREATE ROLE или ALTER ROLE. Значения два: scram-sha-256 и md5, и в актуальных версиях по умолчанию стоит scram-sha-256. Всё, что было записано раньше, лежит в каталоге pg_authid в прежнем виде. Хэш из MD5 в SCRAM превратить нельзя: исходного пароля сервер не знает, а знает только его необратимый отпечаток. Поэтому единственный путь — заново задать пароль каждой роли.

Отсюда вытекает неприятное следствие для тех, кто мигрировал базу годами раньше. Дамп и восстановление, обновление через pg_upgrade и переезд на новый сервер переносят роли вместе с их секретами. Вы можете сидеть на PostgreSQL 18 и при этом хранить хэши, созданные ещё на десятой версии. На странице об уязвимости CVE-2026-6478 PostgreSQL прямо напоминает: базы, обновлённые с версии 13 и ниже, могут до сих пор содержать MD5-пароли, и их стоит поискать. Спойлер: их обычно находят.

Вторая половина путаницы связана с pg_hba.conf. Там тоже есть слово md5, и многие думают, что это ровно тот же алгоритм. На деле это название метода аутентификации, и по документации метод md5 выполняет «SCRAM-SHA-256 или MD5» в зависимости от того, как сохранён пароль роли. Если роль уже с SCRAM-секретом, сервер сам выберет SCRAM, даже при записи md5 в HBA. Это сделано специально, чтобы облегчить переход, и именно этим мы воспользуемся.

Как найти роли с MD5 и понять, кто и откуда к ним подключается

Начинаем с инвентаризации. Формат секрета в pg_authid различается по префиксу: MD5-пароль начинается со строки md5 и 32 шестнадцатеричных символов, SCRAM-секрет имеет вид SCRAM-SHA-256$ с числом итераций, солью и ключами. Читать pg_authid имеет смысл под суперпользователем, потому что каталог содержит хэши, и публично он недоступен. Для остальных есть представление pg_roles, но поле пароля там скрыто. Запрос короткий:

SELECT rolname,
       CASE WHEN rolpassword LIKE 'md5%' THEN 'md5'
            WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram'
            ELSE 'нет пароля' END AS тип_секрета,
       rolcanlogin
FROM pg_authid
ORDER BY 2, 1;

Меня интересуют строки, где тип_секрета равен md5 и rolcanlogin истинно. Роли без права входа (группы, владельцы схем) пароль не используют, и переводить там нечего.

Дальше нужен ответ на вопрос «кто к этой роли ходит». Тут начинается самое интересное: пароль для роли app_crm знает не один человек. Он лежит в конфиге приложения, в скрипте выгрузки, в настройках отчётной системы и, подозреваю, в заметке на рабочем столе у бывшего подрядчика. Я составляю таблицу из четырёх колонок: роль, откуда подключается (адрес и приложение), чем подключается (библиотека и её версия), где хранится пароль. Колонка «где хранится пароль» заполняется дольше остальных и пугает больше всего.

Отдельно смотрим правила pg_hba.conf. Сервер применяет первую подходящую запись по типу соединения, адресу, базе и имени роли, и дальше не проваливается: если запись выбрана, а проверка не прошла, остальные записи не рассматриваются. Поэтому порядок строк важен. Чтобы увидеть, как сервер на самом деле прочитал файл, есть системное представление pg_hba_file_rules. Оно же полезно для проверки правки до перезагрузки: строки с непустым полем error показывают, что именно не разобрано.

SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules
ORDER BY line_number;

Про устаревшие записи стоит сказать отдельно. В HBA годами копятся правила вида «временно разрешим этой подсети», и именно по ним подключаются самые старые клиенты. Не удаляйте ничего на этом шаге, только фиксируйте. Задача инвентаризации — получить честный список клиентов, а не навести красоту. Красота будет позже, когда станет понятно, что от чего зависит.

Дерево решений по значению rolpassword в pg_authid: MD5 требует нового пароля, SCRAM не трогаем
По префиксу секрета сразу видно, какие роли ещё на MD5.

Какие клиенты не переживут SCRAM и как проверить это заранее

Самое больное место перехода — клиентские библиотеки. По документации метод scram-sha-256 самый безопасный из доступных, но он не поддерживается старыми клиентскими библиотеками. Сколько «старых» в вашем случае, зависит от того, что подключается к базе: драйвер ODBC на рабочем месте бухгалтера, JDBC в самописном сервисе, библиотека в скрипте, который кто-то написал в 2016 году и с тех пор не трогал. Документация не называет конкретных версий библиотек, и я не буду выдумывать цифры за неё. Минимальную версию для вашего драйвера смотрите в его документации и в changelog.

Рабочая проверка не требует догадок. Я создаю тестовую роль с SCRAM-секретом и пробую зайти под ней каждым клиентом из таблицы: приложением, скриптом выгрузки, ODBC-источником на рабочем месте. Не читаю версию, а именно подключаюсь. Клиент, который не умеет SCRAM, на тестовой роли упадёт сразу, и вы увидите это в понедельник утром за чашкой кофе, а не в пятницу вечером в боевой базе.

SET password_encryption = 'scram-sha-256';
CREATE ROLE scram_probe WITH LOGIN PASSWORD 'временный-пароль';

Пароль в команде попадёт в историю клиента и, возможно, в журнал сервера. В документации ALTER ROLE это отмечено прямо: открытый пароль в команде передаётся серверу в чистом виде и может быть записан в историю клиента и журнал. Для интерактивной работы используйте команду psql \password: она запрашивает пароль, шифрует его на клиенте и отправляет серверу как ALTER ROLE, так что открытый пароль не светится ни в истории, ни в журнале.

Теперь про то, что делать с клиентом, который проверку не прошёл. Вариантов три, и порядок предпочтения такой. Первый — обновить библиотеку или драйвер: это правильно, и обычно занимает меньше времени, чем кажется. Второй — оставить именно эту роль на MD5 и вынести её в отдельную строку HBA выше общей записи. Документация приводит такой же пример: для одного пользователя со старым клиентом остаётся md5, для остальных ставится scram-sha-256. Третий — отказаться от тихого «авось» и записать срок, когда эту роль всё же переведут. Исключение без срока превращается в постоянное правило, а временное правило в HBA — самое долговечное из всех, что я встречал.

Отдельный момент касается пулеров соединений и других промежуточных компонентов перед базой. Если между приложением и PostgreSQL стоит промежуточный компонент, он тоже участвует в аутентификации, и его настройки нужно проверить по его собственной документации. Я здесь не пишу параметры, потому что они зависят от конкретного продукта и версии. Правило простое: каждый компонент на пути соединения проверяется тестовой ролью так же, как приложение.

Не меняйте метод в pg_hba.conf на scram-sha-256 раньше, чем у всех ролей появился SCRAM-секрет. По документации роль с MD5-секретом при методе scram-sha-256 войти не сможет. Сначала пароли, потом HBA — и никак иначе.

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

Если после инвентаризации вам нужна помощь с таблицей клиентов и тестами, мы сделаем это за вас: аудит ролей и проверка клиентов у нас занимают, как правило, рабочий день, а переключение идёт без остановки сервисов. А если делаете сами, вот последовательность, на которой я стою.

Шаг первый — параметр. В postgresql.conf выставляем password_encryption = 'scram-sha-256' (в современных версиях он и так по умолчанию, но запись в файле убирает сомнения). Применяем перечитыванием конфигурации, перезапуск здесь не нужен. Шаг второй — роли. Для каждой роли из списка md5 с правом входа задаём пароль заново. Ключевая хитрость: если вы знаете текущий пароль и задаёте точно такой же, приложению ничего менять не придётся. Секрет в базе станет SCRAM, а пароль, который знает приложение, останется прежним. Разумеется, при условии, что клиент умеет SCRAM, и вы это уже проверили.

SHOW password_encryption;
-- затем под psql, по одной роли:
-- \password app_crm

Шаг третий — пока HBA содержит md5, ничего не ломается. Записи md5 в pg_hba.conf в связке с SCRAM-секретом автоматически выполняют SCRAM-аутентификацию, а роли, ещё не переведённые, продолжают входить по MD5. Именно это и даёт переход без остановки: роли переезжают поодиночке, в удобное окно, и каждая проверяется сразу после смены. Если что-то не пошло, возвращаем пароль обратно при установленном md5 в password_encryption, и роль снова с MD5-секретом. Откат на уровне одной роли обходится секундами.

Если пароль вам неизвестен, придётся придумать новый и обновить его в приложении. Здесь без короткого перезапуска не обойтись, и я честно говорю об этом заказчикам. Но это перезапуск одного сервиса, а не простой всей базы, и его можно поставить на ночь. Часто именно на этом шаге обнаруживается, что пароль знает только сама программа, а в вашей таблице стоит прочерк, и это хороший повод навести порядок в хранении секретов. Подробнее о том, что делать с подключениями в момент смены настроек, у меня написано в материале про резерв подключений в PostgreSQL.

Шаг четвёртый, финальный — когда в списке не осталось ролей с MD5 (кроме осознанных исключений), меняем метод в pg_hba.conf на scram-sha-256 и сначала проверяем правку через pg_hba_file_rules. Затем перечитываем конфигурацию: pg_ctl reload, SQL-функция pg_reload_conf() или сигнал SIGHUP. В Windows файл применяется при каждом новом соединении без перечитывания, имейте в виду.

SELECT pg_reload_conf();
Четыре шага перехода PostgreSQL с MD5 на SCRAM: параметр, тест клиентов, пароли ролей, правка pg_hba.conf
Пароли идут раньше pg_hba.conf, а не наоборот.

Разбор: 11 рабочих мест, 6 ролей и один старый драйвер

Условный клиент: психологическое консультирование «ПсихоПричал», 11 рабочих мест. База на PostgreSQL 16 жила на одном Linux-сервере, под ней крутились система записи клиентов, бухгалтерская база, скрипт ночной выгрузки и отчётность. Базу когда-то поднимали на более ранней версии, потом несколько раз обновляли, поэтому из шести ролей с правом входа пять хранили пароль как MD5. В postgresql.conf стояло password_encryption = 'scram-sha-256' ещё с прошлого переезда, и директор искренне считал, что вопрос закрыт. Я его не виню: так пишут в большинстве инструкций.

Подготовка заняла около часа: запрос к pg_authid, таблица клиентов, разбор pg_hba_file_rules. Выяснилось три вещи. Две роли использовало одно и то же приложение, но с разных адресов. Пароль одной роли никто в организации не помнил. А на одном рабочем месте бухгалтера отчёты шли через ODBC-драйвер, поставленный много лет назад. Дальше всё по порядку из предыдущего раздела: тестовая роль со SCRAM, проверка каждого клиента. Драйвер на рабочем месте бухгалтера проверку не прошёл.

Тактика получилась такой. Четыре роли мы перевели за два вечера по две: пароль знали, меняли тем же значением через \password, проверяли вход и работу сервиса. Роль с забытым паролем получила новый, который внесли в приложение в окно обслуживания: короткий перезапуск одного сервиса, остальные продолжали работать. Роль отчётов с устаревшим драйвером оставили на MD5 и вынесли в отдельную строку HBA над общим правилом scram-sha-256. Через четыре дня драйвер обновили, роль перевели, а исключение удалили. Простоя базы не было ни минуты, а одно окно ушло на перезапуск приложения.

Параллельно мы закрыли вторую проблему. На сервере стоял PostgreSQL 16 ниже версии 16.14, то есть без исправления CVE-2026-6478, которое касается именно MD5-паролей. Минорное обновление до 16.14 прошло в то же окно. Итог: нет ролей с MD5, в HBA единственное правило scram-sha-256 для сети офиса, версия базы исправленная. По времени всё вместе — около шести часов работы растянутых на неделю, без остановки учёта. Ещё один побочный эффект: мы нашли и убрали две старые записи в HBA, о которых никто не помнил. Тоже спойлер: их находят всегда. Вопросы доступа к 1С и прав ролей — в материале про безопасность 1С и аудит.

Было и стало в кейсе: 5 из 6 ролей на MD5 до перехода и 0 ролей на MD5 после перехода на SCRAM
Результат кейса: ноль ролей на MD5 и ноль минут простоя.

CVE-2026-6478 и зачем вообще торопиться с MD5

Многие откладывают переход фразой «MD5 пока работает». Работает. Только документация PostgreSQL уже называет поддержку MD5-паролей устаревшей, которая будет удалена в одном из будущих релизов, а в релизных заметках PostgreSQL 18 (вышел 25 сентября 2025 года) deprecation оформлена как несовместимость миграции. При этом начиная с PostgreSQL 18 команды CREATE ROLE и ALTER ROLE выдают предупреждение при установке MD5-пароля, и отключается оно параметром md5_password_warnings = off (в 16-й и 17-й версиях этого предупреждения нет, так что тишина в логе там ничего не значит). Ради спокойствия лог от предупреждений чистят, а не пароли меняют, и это мой любимый способ решать проблему, не решая её.

Теперь про уязвимость. CVE-2026-6478 описана на сайте PostgreSQL как скрытый канал по времени при сравнении MD5-хэшей паролей во время аутентификации: атакующий может восстановить учётные данные, достаточные для входа. Исправления вышли 14 мая 2026 года в версиях 18.4, 17.10, 16.14, 15.18 и 14.23, затронуты версии ниже этих в ветках 14–18. Оценка CVSS 3.0 — 6.5, средняя. SCRAM-SHA-256 пароли уязвимость не затрагивает. То есть обновление закрывает дыру, но не отменяет необходимость уходить с MD5: с SCRAM класс проблемы не возникает.

Заключение простое. Обновите минорную версию в любом случае, это не обсуждается. А затем переводите роли: документация среди прочего отмечает, что MD5 не защищает при краже хэша с сервера, и хэш можно использовать как пароль. В SCRAM кража хранимого значения даёт меньше. Если у вас ещё и контейнерный PostgreSQL, не забудьте проверить, какой именно образ подтягивается после перехода, об этом я писал в статье про переход на образ postgres 18.

Что проверить после перехода и как откатиться

После переключения HBA я прогоняю короткий чек-лист. Повторяю запрос к pg_authid: md5-строк с правом входа быть не должно, кроме зафиксированных исключений. Просматриваю pg_hba_file_rules: нет ли строк с ошибкой и нет ли более ранних записей с методом md5 или trust, которые перехватят соединения раньше нужной строки. Подключаюсь по очереди каждым клиентом из таблицы. И просматриваю журнал сервера за первые сутки на предмет отказов аутентификации: ошибки входа после такой смены чаще всего означают клиента, про которого забыли.

Откат продумываем заранее. Он двухуровневый. Если упал один клиент, возвращаем строку md5 для его роли выше общего правила и пересоздаём пароль при password_encryption = 'md5', пока не обновится библиотека. Если проблема массовая, возвращаем в HBA прежний метод и перечитываем конфигурацию: роли со SCRAM-секретом продолжат входить, потому что метод md5 сам выберет SCRAM. Именно поэтому порядок «пароли, потом HBA» безопаснее обратного: ошибка при нём стоит одной строки конфига.

Последнее — гигиена. Держите шаблон проверки в регламенте обслуживания: новые роли создаются уже при password_encryption = 'scram-sha-256', секреты хранятся в менеджере, а не в заметках, раз в квартал выполняется запрос из второго раздела. Скучно, зато через год вам не придётся снова выяснять, почему «настроено» не значит «работает». Параметр scram_iterations по умолчанию равен 4096, и менять его без причины не нужно, лучше потратить время на инвентаризацию клиентов.

Частые вопросы

Конвертирует ли password_encryption существующие пароли в SCRAM?

Нет. Параметр определяет алгоритм только в момент установки пароля командами CREATE ROLE и ALTER ROLE. Для существующих ролей пароль нужно задать заново, иначе секрет останется в формате MD5.

Что будет, если в pg_hba.conf стоит scram-sha-256, а у роли MD5-пароль?

Роль не сможет войти: MD5-секрет работает только с методами md5 и password. Поэтому сначала переводим пароли ролей на SCRAM, а метод в HBA меняем в самом конце.

Нужно ли останавливать приложения при переходе на SCRAM?

Не нужно, если вы знаете текущие пароли и задаёте те же значения, а клиенты поддерживают SCRAM. Метод md5 в HBA автоматически использует SCRAM для ролей со SCRAM-секретом. Остановка нужна только там, где приходится придумывать новый пароль и менять его в приложении.

Как узнать, какие роли ещё на MD5?

Под суперпользователем выберите rolname и rolpassword из pg_authid: MD5-пароль начинается с md5 и 32 шестнадцатеричных символов, SCRAM-секрет начинается с SCRAM-SHA-256$. Публичное представление pg_roles поле пароля скрывает.

Закрывает ли обновление до 16.14 или 18.4 необходимость переходить на SCRAM?

Нет. Обновление устраняет CVE-2026-6478, но поддержка MD5 в PostgreSQL объявлена устаревшей и будет удалена в одном из будущих релизов, дата в документации не указана. SCRAM-пароли этой уязвимостью не затронуты.

Как перечитать pg_hba.conf после правки?

Выполните pg_ctl reload, вызовите SQL-функцию pg_reload_conf() или отправьте процессу сервера сигнал SIGHUP. До перечитывания проверьте правку через представление pg_hba_file_rules. В Windows изменения подхватываются новыми соединениями сами.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи