RE:NODE

Базы данных10 мин чтения

Безопасность Valkey: пароли, пользователи ACL и открытые порты

Защищаем сервер Valkey: requirepass, пользователи ACL с ограничением ключей и команд, опасные команды, protected mode, TLS и почему открытый порт заканчивается майнером.

0 прочтений

Valkey без аутентификации, доступный из интернета, - это не утечка данных, а удалённый shell. Набор команд позволяет клиенту изменить, куда сервер пишет файл снимка и как этот файл называется, а этого достаточно, чтобы положить на машину ключ SSH или файл cron от имени пользователя, под которым работает Valkey. Автоматические сканеры находят открытые экземпляры за считанные минуты, и после себя они обычно оставляют майнер криптовалюты. Каждый шаг защиты ниже существует из-за этого одного факта.

Защита в порядке важности: никогда не выставляйте сервер наружу без аутентификации; используйте длинный случайный пароль; дайте каждому приложению собственного пользователя ACL только с теми ключами и командами, которые ему нужны; держите административные и разрушительные команды подальше от учётных данных приложений; и помните, что протокол текстовый и открытый, если не настроен TLS. В этой статье разобран каждый пункт с настоящей конфигурацией и командами.

Почему открытые экземпляры взламывают#

Атака старая и простая, а понимание её устройства объясняет защиту.

  1. Просканировать интернет в поисках порта 6379 (и других распространённых портов), отвечающего на протоколе Redis.
  2. Отправить INFO. Если ответ пришёл без NOAUTH, экземпляр открыт.
  3. С помощью CONFIG SET dir и CONFIG SET dbfilename направить вывод снимка в чувствительное место - /root/.ssh/ и authorized_keys или каталог cron.
  4. Записать ключ, значение которого содержит открытый ключ SSH или строку cron, выполнить SAVE - и файл снимка теперь содержит рабочую нагрузку.
  5. Войти по SSH или дождаться cron и установить майнер.

Варианты загружают вредоносный модуль через MODULE LOAD или злоупотребляют репликацией через REPLICAOF, чтобы подтянуть модуль с сервера злоумышленника. Всем им нужны две вещи: подключение без аутентификации и право выполнять административные команды. Уберите любую - и атака не удастся.

Современный Valkey уже частично закрывает это по умолчанию. enable-protected-configs, enable-debug-command и enable-module-command по умолчанию равны no, что блокирует изменение чувствительных путей вроде dir во время работы и блокирует MODULE LOAD со стороны клиентов. Это реальное улучшение по сравнению с серверами нескольколетней давности, но всё равно не повод оставлять экземпляр открытым: сами данные может читать, менять и удалять любой, кто подключится.

Protected mode и привязка к интерфейсу#

Две настройки решают, кто вообще может подключиться.

valkey.conf
bind 127.0.0.1 -::1protected-mode yesport 6379

bind перечисляет интерфейсы, на которых слушает Valkey. На машине, где он нужен только локальным процессам, правильный ответ - loopback, и это сразу убирает большую часть риска. Ведущий - в -::1 означает «не отказываться от запуска, если этот адрес недоступен».

protected-mode yes - это страховочная сетка: если пароль не задан и bind не менялся с значения по умолчанию, сервер отказывает в подключениях откуда-либо, кроме loopback, и сообщает клиенту причину. Он не защищает экземпляр, явно привязанный к публичному адресу без пароля, - сервер считает, что это ваш сознательный выбор.

Когда приложение работает на другой машине, что для размещённого у провайдера Valkey - обычный случай, сервер должен слушать доступный адрес, и главной защитой становится пароль. Ограничение адресов-источников, которым разрешено подключаться, на файрволе перед портом добавляет вторую линию там, где этим файрволом управляете вы.

В RE:NODE тариф Valkey создаётся с паролем, сгенерированным для этого сервера, и доступен по собственному хосту и порту тарифа; у тарифов баз данных нет слота прокси перед ними. Экземпляр никогда не продаётся без аутентификации, что устраняет классическую ошибку. За вами остаётся не допускать пароль туда, где ему не место, и всё остальное из этой статьи.

Пароли: requirepass и AUTH#

Простейшая аутентификация - один общий пароль:

valkey.conf
requirepass 9fK2pQ7x-a-long-random-string-from-a-generator

Тогда клиенты проходят аутентификацию командой AUTH <password> перед любой другой командой или указывают пароль в URL подключения: redis://:password@host:port/0. Внутри requirepass задаёт пароль встроенного пользователя ACL default, поэтому AUTH default <password> тоже работает.

Требования к паролю здесь иные, чем у формы входа. Valkey настолько быстр, что злоумышленник, способный подключиться, может перебирать огромное число паролей в секунду, а блокировки нет. Используйте 32 и больше случайных символов из генератора, а не запоминающуюся фразу. Сгенерировать пароль можно так:

bash
$ openssl rand -base64 32

Если пароль пойдёт в URL, избегайте @, /, : и # или кодируйте их через проценты, потому что во многих клиентах они ломают разбор URL, - либо используйте openssl rand -hex 32, который выдаёт только безопасные символы.

Храните пароль там же, где остальные секреты: в переменных окружения или хранилище секретов, никогда не коммитьте его в репозиторий и не вставляйте в чат поддержки или трекер задач. Где им место, описано в статье переменные окружения и секреты, а чек-лист безопасности баз данных применим к Valkey так же, как к любому SQL-серверу.

Смена одного общего пароля означает одновременную замену на сервере и во всех клиентах, что неудобно. Пользователи ACL решают и это.

Откуда пароли утекают на практике

Пароль редко крадут из самого Valkey. Он утекает из окружения:

  • Логи. URL подключения, напечатанный при запуске («connecting to redis://:hunter2@...»), попадает в файлы логов, системы сбора логов и на скриншоты. Логируйте хост и порт, но никогда не URL.
  • Отчёты об ошибках. Трекеры исключений по умолчанию захватывают переменные окружения и объекты конфигурации. Вычищайте переменную, в которой лежит URL.
  • Клиентские сборки. Сборка фронтенда, читающая переменные окружения, может встроить переменную, предназначенную только для сервера. Учётные данные Valkey никогда не должны попадать в браузер.
  • Общие экраны и тикеты. Вставленный куда-то файл .env - это опубликованный пароль.
  • Бывшие участники команды. Один общий пароль, который знают все, кто когда-либо работал над проектом, - это пароль, который невозможно отозвать у одного человека.

Последний пункт - самый сильный довод в пользу отдельных пользователей ACL для каждого приложения и регулярной смены паролей как рутины, а не экстренной меры. Когда кто-то уходит, меняйте пароль.

Пользователи ACL: по одному на приложение#

Списки управления доступом, унаследованные от архитектуры Redis 6, позволяют создавать именованных пользователей, у каждого из которых свои пароли, набор разрешённых команд и набор разрешённых шаблонов ключей. Смысл - минимальные привилегии: взломанное веб-приложение не должно иметь возможности выполнить FLUSHALL, прочитать ключи другого приложения или перенастроить сервер.

code
ACL SETUSER shop on >s3cr3t-shop-password ~shop:* &shop:* +@all -@dangerousACL SETUSER reports on >s3cr3t-report-password ~shop:* resetchannels -@all +@read +pingACL SETUSER default off

Читаем первую строку слева направо:

ПравилоЗначение
onПользователь включён
>passwordДобавляет пароль (у пользователя их может быть несколько)
~shop:*Доступ только к ключам, подходящим под shop:*
&shop:*Может использовать каналы pub/sub, подходящие под shop:*
+@allРазрешает все категории команд...
-@dangerous...затем убирает категорию опасных

Правила применяются по порядку, так что +@all -@dangerous - это «всё, кроме опасных команд». Второй пользователь только читает и не имеет никаких каналов. Третья строка отключает пользователя default, а значит, никто не сможет подключиться, не назвав имя пользователя, - делайте это только убедившись, что каждый клиент проходит аутентификацию с именем пользователя.

Клиенты проходят аутентификацию через AUTH shop <password> или с именем пользователя в URL: redis://shop:password@host:port/0. Большинство актуальных клиентских библиотек это поддерживают; очень старые, которые отправляют только AUTH <password>, могут использовать лишь пользователя default.

Полезные команды для проверки:

code
ACL WHOAMIACL LISTACL GETUSER shopACL CAT dangerousACL DRYRUN shop FLUSHALLACL LOG 10

ACL DRYRUN проверяет, разрешена ли пользователю команда, не выполняя её. ACL LOG записывает недавние отказы и неудачные попытки аутентификации, а это и инструмент отладки, и раннее предупреждение о том, что кто-то подбирает пароли.

Пользователи, созданные через ACL SETUSER, живут в памяти. Чтобы пережить перезапуск, их нужно сохранить: либо в файл ACL, заданный через aclfile и записываемый командой ACL SAVE, либо в valkey.conf в виде строк user с сохранением через CONFIG REWRITE. Если забыть этот шаг, тщательно настроенные права исчезнут при следующем перезапуске.

Можете ли вы сами управлять пользователями ACL на размещённом у провайдера экземпляре, зависит от прав выданного вам пользователя. Выполните ACL WHOAMI и ACL LIST; если вторая команда запрещена, ваш пользователь не может администрировать ACL, и границей доступа служит сгенерированный пароль - поэтому обращаться с ним нужно как с паролем root.

Опасные команды#

Категория @dangerous - это набор команд, которые приложению выполнять незачем. Самые важные из них:

КомандаРиск
FLUSHALL, FLUSHDBМгновенно удаляет всё
CONFIGЧитает и меняет настройки сервера
KEYSОбходит всё пространство ключей одним блокирующим вызовом
DEBUGМожет обрушить или подвесить сервер
SHUTDOWNОстанавливает сервер
MODULEЗагружает нативный код
REPLICAOF, SLAVEOFПревращает сервер в реплику сервера злоумышленника
SAVEБлокирующий снимок
MONITORТранслирует каждую команду каждого клиента, включая пароли
Подкоманды CLIENTПеречисляют и обрывают чужие подключения

Старый способ отключать команды - rename-command в файле конфигурации, переименовывающий FLUSHALL в пустую строку или случайное имя. Он по-прежнему работает, но действует по принципу «всё или ничего» для всех пользователей и ломает инструменты, ожидающие, что команда существует. ACL - инструмент получше: пользователь приложения просто не может выполнить FLUSHALL, а пользователь-администратор по-прежнему может.

KEYS заслуживает отдельного упоминания, потому что опасна скорее по случайности, чем по злому умыслу. Отладочная строка разработчика с KEYS * на продакшен-экземпляре с миллионами ключей замораживает его на секунды. Используйте SCAN с шаблоном MATCH и уберите KEYS у пользователей приложений.

Шифрование при передаче#

Протокол Redis - открытый текст. Без TLS команда AUTH, пароль в ней и каждое значение, которое вы читаете и пишете, идут по сети в виде, доступном для чтения любому на пути.

Valkey поддерживает TLS, если собран с ним; настраивается он через tls-port, tls-cert-file, tls-key-file и tls-ca-cert-file, а клиенты подключаются по схеме rediss:// (с двумя s). Предлагает ли конкретный размещённый экземпляр TLS на своём порту - это свойство самой услуги, так что проверьте, прежде чем на это рассчитывать: если в тарифе указаны только хост и порт, считайте, что это обычный TCP. Там, где TLS недоступен:

  • Держите приложение и Valkey в одной локации, чтобы трафик не ходил по публичному интернету больше необходимого.
  • Не храните в Valkey данные, чтение которых при передаче стало бы серьёзным инцидентом: номера карт, персональные записи в открытом виде, долгоживущие секреты.
  • Меняйте пароль, если у вас когда-либо появятся подозрения насчёт канала между приложением и сервером.

Никогда не ставьте Valkey за HTTP обратный прокси в надежде, что тот добавит шифрование. Протокол - не HTTP; веб-прокси не умеет его передавать, а TLS-терминатор на уровне TCP перед ним защищает лишь участок до этого терминатора.

Мониторинг, смена паролей и реагирование на инциденты#

Безопасность - это ещё и умение заметить, что что-то не так.

  • Следите за `ACL LOG` на предмет повторяющихся неудачных аутентификаций. Всплеск с незнакомого адреса означает, что кто-то подбирает пароль.
  • Следите за `INFO clients`: connected_clients намного выше того, что открывает ваше приложение. Неожиданные подключения стоит расследовать.
  • Следите за `INFO keyspace` и памятью. Пространство ключей, которое внезапно опустело или заполнилось незнакомыми ключами с именами вроде backup1, backup2 и странными значениями, - это почерк атаки, описанной в начале.
  • Меняйте пароли, пользуясь поддержкой нескольких паролей в ACL: добавьте пользователю новый пароль, разверните его во всех клиентах, затем удалите старый через <oldpassword. Без простоя и без «дня икс».

Если вы нашли признаки взлома, считайте, что данные были прочитаны и, возможно, изменены. Смените все учётные данные, хранившиеся в Valkey или использовавшиеся вместе с ним, смените пароль Valkey, проверьте машины, которые к нему подключаются, и восстановите данные из заведомо хорошей копии, если значения могли быть подменены. Общий порядок действий - в статье что делать, если ваш сервер взломали.

Чек-лист#

  1. Аутентификация включена: пароль из 32 и более случайных символов или пользователи ACL.
  2. Порт доступен только тому, кому нужен: loopback на одной машине, список разрешённых адресов на файрволе там, где вы им управляете.
  3. У каждого приложения свой пользователь ACL, ограниченный своим префиксом ключей и без @dangerous, если вы можете создавать пользователей.
  4. Пользователь default отключён или имеет сильный пароль.
  5. Изменения ACL сохранены в файл ACL или в конфигурацию, чтобы пережить перезапуск.
  6. Пароли живут в переменных окружения или хранилище секретов, а не в коде.
  7. TLS используется там, где он предлагается; где нет - чувствительные данные в Valkey не попадают.
  8. За ACL LOG, числом клиентов и памятью следят.
  9. Есть план смены паролей, не требующий простоя.

FAQ#

Достаточно ли одного requirepass?

Для одного приложения с длинным случайным паролем и портом, открытым не шире, чем необходимо, это разумный базовый уровень. Пользователи ACL добавляют минимальные привилегии и безболезненную смену паролей, и их значение растёт с числом приложений, делящих один экземпляр.

Можно ли спрятать Valkey, сменив порт?

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

Почему клиент пишет NOAUTH после того, как я задал имя пользователя?

Клиент отправляет AUTH <password> без имени пользователя, и сервер проверяет пароль у пользователя default. Укажите имя пользователя в URL или в соответствующем параметре клиента и проверьте, что версия библиотеки поддерживает аутентификацию ACL.

Хранятся ли пароли ACL в открытом виде?

Нет. Valkey хранит хэши SHA-256 паролей ACL, и ACL GETUSER показывает хэши, а не пароли. При этом сам пароль идёт по сети открытым текстом, если не используется TLS.

Должны ли кэш и хранилище сессий использовать разных пользователей?

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


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000