Одна из тысячи похожих историй.
После известных событий компании моего знакомого пришлось оперативно перейти с удобного зарубежного хостинга на площадку попроще. Площадка была настолько проще, что речь уже не шла о штатном мониторинге, логировании или даже привычных группах безопасности для фильтрации трафика. Это был один из тех переездов, которые не успели спланировать. И вот эти самые группы безопасности и подвели. На новом хостинге не было никакого межсетевого экрана на уровне VPS, и Redis оказался доступен для злоумышленников. Они этим естественно воспользовались. Веб-сервис взломали. Сервис был необходим для разработки и поддержки продукта, который через различные сторонние API агрегировал определенную информацию, а затем выдавал её клиентам по запросу. В какой-то момент данных стало много, и было решено с помощью Redis кэшировать часть запросов. Redis стоял на том же сервере, где запускался веб-сервер и никому в голову не приходило как-то особенно заниматься его безопасностью. Но, как водится, порвалось, там, где тонко.
---
Может показаться что, Redis, используемый для хранения кэша и временных ключей, – это не слишком интересная добыча. Но на самом деле, хакеры провернули следующий трюк:
root@belowzero273:~# redis-cli -h <ip-address>
10.85.0.52:6379> config set dir /usr/share/nginx/html
OK
10.85.0.52:6379> config set dbfilename redis.php
OK
10.85.0.52:6379> set test "<?php phpinfo(); ?>"
OK
10.85.0.52:6379> save
OK
Подключившись, они сменили путь для директории, где хранится база Redis – указали корень веб-сервера, сменили её название на redis.php, а затем, проверив, что phpinfo() успешно выполняется, положили внутрь этого файла свой веб-шелл. Redis не запускался от имени root, но всё равно было неприятно, и часть внутренних данных в итоге утекла.
Redis здорового человека
Это история про ту самую безопасность, в которой не бывает мелочей. После этого случая я решил собрать лучшие практики о том, как можно обезопасить Redis в одном документе. Получилось 7 тезисов:
1. Сделать Redis доступным только с IP-адреса клиента
Для этого нужно, во-первых, отредактировать файл
sudo nano /etc/redis/redis.conf
и указать в нём
bind 127.0.0.1
Теперь наш сервер слушает только локальные подключения, и мы можем убедиться в этом:
sudo netstat -lnp | grep redis
Output
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 5815/redis-server 1
2. Использовать межсетевой экран
Необходимо на уровне самого сервера добавить правило по фильтрации портов.
sudo ufw status
Output
Status: active
To Action From
-- ------ ----
6379/tcp ALLOW Anywhere
Не стоит полагаться только на какое-то внешнее решение. Межсетевой экран на уровне самого сервера – это необходимость.
3. Установить пароль
Да, у Redis нет каких-то продвинутых механизмов аутентификации, но даже теми, что есть, пренебрегать не стоит. В конфигурационном файле можно найти и раскомментировать ключ:
# requirepass foobared
А затем вместо foobared указать свой пароль. При этом, в комментарии к этому ключу указано, что, поскольку Redis штука довольно быстрая (а защиты от перебора паролей в ней нет), то 150к паролей можно перебрать за секунду. Соответственно, пароль должен быть длинным и сложным. В общем-то, как и любой другой пароль.
4. Переименовать опасные команды
Redis позволяет переименовывать или даже совсем отключать отдельные команды. Делать это имеет смысл с теми командами, которые условно можно считать опасными, вроде FLUSHALL или SHUTDOWN. Для отключения, например, команды FLUSHALL в конфигурационный файл нужно добавить:
rename-command FLUSHALL ""
А если вы хотите переименовать команду, синтаксис будет выглядеть так:
rename-command FLUSHDB "pleaseflushmydbiknowwhatimdoing"
Конечно, это классический Security by obscurity, но это тоже мера, которой можно пользоваться на боевых системах, чтобы сбить с толку потенциальных злоумышленников.
5. Включить TLS
Redis поддерживает использование TLS как для взаимодействия между узлами кластера, так и для клиентских подключений. Этим тоже стоит воспользоваться, особенно если вы администрируете свой Redis удалённо. Для этого нужно сторонними средствами сгенерировать сертификат и ключ, а затем использовать эту информацию при каждом запуске сервера Redis.
6. Не запускать Redis от имени root
У Redis нет никаких задач, которым даже в теории потребовался бы доступ уровня root, поэтому и давать его для упрощения жизни не стоит. Но вы это и так знаете и, конечно же, так не делаете, правда?
7. Использовать ACL
Да, в Redis есть Access Control List’ы. Если у вас сложная конфигурация, где к Redis имеет доступ несколько разных пользователей, то хорошей идеей будет использовать ACL. В ACL можно указать к каким командам или к каким ключам у пользователя есть доступ. Например, давайте создадим нового пользователя:
> ACL SETUSER gisuser
OK
Теперь проверим, что может делать наш новый пользователь:
> ACL LIST
1) "user gisuser off &* -@all"
2) "user default on nopass ~* ~& +@all"
По умолчанию нашему пользователю не задан пароль, и он не имеет доступа ни к командам, ни к каким-либо ключам. Строго говоря, такой пользователь сейчас абсолютно бесполезен. Давайте зададим ему пароль и дадим доступ к команде GET, которую можно будет применить к любым ключам, которые начинаются с «cached».
> ACL SETUSER gisuser on >pa$$w0rd ~cached:* +get
OK
Теперь попробуем:
> AUTH gisuser pa$$w0rd
OK
> GET foo
(error) NOPERM this user has no permissions to access one of the keys used as arguments
> GET cached:1234
(nil)
> SET cached:1234 zap
(error) NOPERM this user has no permissions to run the 'set' command
Итак, мы успешно аутентифицировались, посмотрели содержимое ключа 1234 (оно оказалось пустым), затем попробовали задать значение этому ключу, и на это нам не хватило прав.
Настройка ACL в Redis – это довольно несложная задача, при условии, что вы хорошо спланировали, какие пользователи и с какими правами вам потребуются.
После случившегося инцидента мой приятель провел большую работу, выявившую ещё не одну уязвимость, которые возникли только потому, что он привык полагаться на высокий уровень сервиса своего прежнего облачного провайдера. Какие выводы можно сделать из
всей это ситуации? В изменившихся обстоятельствах отдельные подходы к обеспечению безопасности нужно кардинально пересматривать. И в следующий раз не стоит пренебрегать фазой планирования и тестирования, даже при простых на первый взгляд операциях.
Материал подготовил руководитель группы защиты инфраструктурных ИТ-решений компании «Газинформсервис» Сергей Полунин, блог Сергея можно почитать по ссылке.