[Перевод] Защищаем веб-сервер на Linux
Привет, Хабр!
У нас давно не выходило новых книг по Linux для начинающих — и вот мы беремся за перевод новинки именно такого плана. Книга «Linux in Action» Дэвида Клинтона вышла в издательстве Manning и рассказывает не только о внутреннем устройстве Linux, но и о наиболее распространенных проблемах, и о способах их устранения.
Автор опубликовал на сайте Hackernoon отрывок из 9-й главы, который мы и предлагаем вам оценить.
Собрать LAMP-сервер, как следует его сконфигурировать, обеспечить надежную обработку данных, настроить предметную область и озаботиться TLS-сертификатом — лишь половина пути к победе. Также необходимо убедиться, что ваша инфраструктура защищена от многочисленных устрашающих угроз Интернета.
В этой статье мы исследуем безопасность веб-сайта, научившись правильно работать с системными группами, обеспечивать изоляцию процессов и регулярный аудит системных ресурсов. Разумеется, этот рассказ не полный (в книге Linux в действии рассмотрены и другие темы, например, установка TLS-сертификатов и работа с SELinux), но для начала и этого будет вполне достаточно.
Системные группы и принцип минимальных привилегий
Разработчики, поддержкой которых вы занимаетесь, (наконец-то) начинают осознавать, что необходимо ограничивать общий доступ к данным и конфигурационным файлам, расположенным на сервере приложений, но, в то же время, оставлять такой доступ открытым для различных программерских и прочих айтишных команд.
Первая часть решения — это группы. Группа — это объект в системе (примерно как и пользователь) с той оговоркой, что ни один пользователь никогда не зайдет в систему как группа. Сила групп заключается в том, что их, как и пользователей, можно «присваивать» файлам или каталогам, позволяя каждому члену группы пользоваться предусмотренными для нее полномочиями. Это проиллюстрировано ниже.
Разработчики, входящие в состав группы Developers, могут получить доступ к конкретному каталогу, а для пользователей, не относящихся к данной группе, каталог будет закрыт
Попробуйте сами: создайте в текстовом редакторе новый файл. Запишите в него простой текст, например, «Hello World», чтобы сразу было видно, когда к файлу удалось успешно обратиться. Затем отредактируйте права доступа при помощи chmod 770
, так, чтобы владелец файла и члены группы, к которой он относится, имели полные права на работу с файлом, а другие не могли его читать.
$ nano datafile.txt
$ chmod 770 datafile.txt
Если в вашей системе пока нет других пользовательских аккаунтов кроме вашего собственного — создайте такой аккаунт либо при помощи adduser
— так делается в Debian/Ubuntu — либо при помощи useradd
, как принято в CentOS. Команда useradd
сработает и в Ubuntu.
Команда useradd
в отличие от adduser
из Debian требует, чтобы пользовательский пароль генерировался отдельно:
# useradd otheruser
# passwd otheruser
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
При помощи команды su
переключаемся на нового пользователя. После того, как мы введем его пароль, все следующие команды будут выполняться от имени этого пользователя. Вы будете работать от лица именно этого пользователя; ни больше, ни меньше. Если вы попытаетесь считать файл данных datafile.txt
(при помощи cat
), то ничего у вас больше не выйдет; как вы помните, права на чтение есть только у членов группы. Когда закончите, введите exit
, чтобы выйти из оболочки нового пользователя, и вернитесь в свою исходную оболочку.
$ su otheruser
Password:
$ cat /home/ubuntu/datafile.txt
cat: /home/ubuntu/datafile.txt: Permission denied
$ exit
Все это ожидаемо и вполне понятно. Как видите, когда не можешь прочесть файл, принадлежащий другому пользователю — это порой проблема. Давайте посмотрим, что можно сделать, связав файл с группой, а затем правильно сконфигурировав права доступа к файлу.
Создадим новую группу, при помощи которой сможем управлять данными нашего приложения, а затем отредактируем свойства нашего файла с данными при помощи команды chown
. Аргумент ubuntu: app-data-group оставляет права на владение файлом пользователю Ubuntu, но группа его меняется на новую: app-data-group.
# groupadd app-data-group
# chown ubuntu:app-data-group datafile.txt
Запустите ls, чтобы получить «развернутый» вывод этого файла и просмотреть его новые права доступа и статус. Обратите внимание: как и следовало ожидать, файлом владеет пользователь ubuntu
, относящийся к группе app-data-group
.
$ ls -l | grep datafile.txt
-rwxrwx — — 1 ubuntu app-data-group 6 Aug 9 22:43 datafile.txt
Можно применить usermod
, чтобы добавить вашего пользователя к app-data-group
, а затем — команду su
, чтобы переключиться на оболочку, в которой развернут аккаунт другого пользователя. Теперь, даже несмотря на то, что права доступа к файлу закрывают его от всех «других» —, а вы на данный момент определенно «другой» пользователь — вы должны свободно читать этот файл, поскольку относитесь к нужной группе.
# usermod -aG app-data-group otheruser
$ su otheruser
$ cat datafile.txt
Hello World
При помощи команды su
переключаемся между пользовательскими аккаунтами. Они и записаны в моем файле datafile.txt
. Такая организация — правильный и эффективный способ устранения разнообразных сложных проблем с правами доступа, которые могут возникать в многопользовательской системе.
На самом деле, она применяется не только для предоставления нужных прав доступа отдельным пользователям — многие системные процессы также не могли бы выполнять своих задач, если бы для них не была прописана принадлежность к нужным группам. Можете по диагонали просмотреть файл /etc/group — обратите внимание, как много системных процессов относятся к собственным группам…
Сокращенный листинг содержимого /etc/group file:
$ cat /etc/group
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:syslog
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
news:x:9:
uucp:x:10:
man:x:12:
proxy:x:13:
[…]
Изоляция процессов в контейнерах
Возможно, вы беспокоитесь, что множество служб, работающих у вас на одном сервере, окажутся под угрозой, если хотя бы одна из этих служб окажется взломана? Один из вариантов сгладить такой ущерб, который могут причинить беспечные или злонамеренные пользователи — изолировать системные ресурсы и процессы. Таким образом, даже если кто-то пожелает расширить свои полномочия сверх установленных пределов, он не получит физического доступа к данным.
Ранее эту проблему было принято решать так: на каждую службу выделяли свою физическую машину. Однако, благодаря виртуализации становится гораздо проще и дешевле выстроить «ячеистую» архитектуру. Сегодня такая архитектура часто именуется микросервисной и позволяет запускать сразу множество контейнеров, в одном из которых может работать, к примеру, база данных, в другом — Apache, а в третьем — медиа-файлы, которые могут встраиваться в ваши веб-страницы. Микросервисная архитектура позволяет не только значительно повысить производительность и эффективность, но и значительно снижают риск взлома каждого отдельного компонента.
«Контейнеры», о которых я говорю, не обязательно должны обладать убедительностью LXC. Сегодня гораздо популярнее становятся и другие контейнерные технологии, например, Docker.
Проверяем наличие опасных значений пользовательского ID
Конечно, любой пользователь с правами администратора может временно предоставить рут-доступ командой sudo
, но лишь админ — подлинный админ. Как вы уже знаете, небезопасно выполнять регулярные функции под рут-доступом. Однако, может так произойти — либо чисто случайно, либо из-за злонамеренной подделки данных — что обычный пользователь фактически без перерывов будет обладать административными правами.
В данном случае хорошо, что выявить таких самозванцев не составляет труда: их пользовательский и/или групповой ID, как и у админа, будет »0». Взгляните на файл passwd в каталоге /etc/. В этом файле содержится по записи для каждого обычного и системного пользовательского аккаунта, уже существующего в системе. В первом поле содержится имя аккаунта (в данном случае — root и ubuntu), а во втором вместо пароля может стоять x (если пароль существует — он будет в зашифрованном виде находиться в файле/etc/shadow). Но в следующих двух полях содержатся пользовательский и групповой ID. В случае с ubuntu
в данном примере оба ID равны 1000. А у администратора, как видите, здесь стоят нули.
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
[…]
ubuntu:x:1000:1000::/home/ubuntu:/bin/bash
Если когда-нибудь встретите обычного пользователя с пользовательским или групповым ID = 0, то можете не сомневаться, что дело тут нечисто, и ситуацию нужно исправить. Быстрый и легкий способ выявить такую проблему — проверить файл passwd
командой awk
, которая выведет все строки, в третьем поле которых нет ничего кроме 0. В моем случае (можно выдохнуть) нашлась всего одна такая строка — рут. Можете запустить ее повторно, заменив $4 на $3 — так вы проверите поле группового ID.
$ awk -F: ‘($3 == "0”) {print}’ /etc/passwd
root:x:0:0:root:/root:/bin/bash
Аудит ресурсов системы
Чем больше всякой всячины работает у вас в системе, тем выше вероятность, что что-нибудь в ней сломается. Поэтому разумно отслеживать, что и как работает. Речь в данном случае идет о сетевых портах (если порт «открыт», то в него по определению должен быть вход), службах (если служба активна, то должна быть возможность ее использовать) и об установленных программах (если программа установлена, то должна быть возможность ее выполнять).
Чтобы аудит приносил пользу, он должен быть более-менее регулярным. Поскольку все мы забывчивы, гораздо лучше записать инструменты аудита в специальный скрипт, который будет не только регулярно выполняться, но и в идеале парсить результаты, чтобы они получались более удобочитаемыми.
Здесь, однако, я познакомлю вас с тремя ключевыми инструментами аудита, которые помогут вам просматривать открытые порты, активные службы и ненужные программные пакеты. Ваша задача — все это автоматизировать.
Сканирование портов
Порт считается «открытым», если на хосте работает какой-то процесс, слушающий запросы на этом порте. Присматривая за своими открытыми портами, вы будете лучше представлять, что именно происходит у вас на сервере.
Вы уже знаете, что на обычном веб-сервере, вероятно, должны быть открыты порты HTTP (80) и SSH (22), поэтому они вас не удивят. Но гораздо важнее обращать внимание и на другие, неожиданные результаты. Команда netstat выводит все открытые порты, а также массу информации о том, как именно они используются.
В данном примере мы проверяем совершенно типичный многоцелевой сервер, и команда -n
приказывает netstat
включить все числовые порты и адреса. -l
включает лишь слушающие сокеты, а -p
добавляет ID процесса слушающей программы. Естественно, если что-то видите — действуйте.
# netstat -npl
Active Internet connections (only servers)
Proto Local Address Foreign Address State PID/Program name
tcp 127.0.0.1:3306 0.0.0.0:* LISTEN 403/mysqld
tcp 0.0.0.0:139 0.0.0.0:* LISTEN 270/smbd
tcp 0.0.0.0:22 0.0.0.0:* LISTEN 333/sshd
tcp 0.0.0.0:445 0.0.0.0:* LISTEN 270/smbd
tcp6 :::80 :::* LISTEN 417/apache2
[…]
В последние годы вместо netstat
все чаще применяется ss
. Просто на всякий случай: если когда-нибудь вечером окажетесь в компании, и кто-то спросит вас о ss, то этот пример (в котором перечислены все установленные SSH-соединения) должен быть достаточно информативен, чтобы вы могли не ударить в грязь лицом:
$ ss -o state established ‘( dport = :ssh or sport = :ssh )’
Netid Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp 0 0 10.0.3.1:39874 10.0.3.96:ssh
timer:(keepalive,18min,0)
Проверяем активные службы
Если сделать быстрый мгновенный снимок служб, управляемых system
и в настоящее время активных на вашем компьютере, то машина поможет выявить любую нежелательную активность. Команда systemctl
может вывести список всех существующих служб, а потом их список можно сузить до тех, в описании которых содержится enabled
. Так будут возвращены лишь активные службы.
# systemctl list-unit-files — type=service — state=enabled
autovt@.service enabled
bind9.service enabled
cron.service enabled
dbus-org.freedesktop.thermald.service enabled
docker.service enabled
getty@.service enabled
haveged.service enabled
mysql.service enabled
networking.service enabled
resolvconf.service enabled
rsyslog.service enabled
ssh.service enabled
sshd.service enabled
syslog.service enabled
systemd-timesyncd.service enabled
thermald.service enabled
unattended-upgrades.service enabled
ureadahead.service enabled
Если вы найдете что-то такое, чему тут явно не место — можете воспользоваться командой systemctl
, и чтобы остановить службу, и чтобы убедиться, что она не перезапускается при следующей загрузке.
# systemctl stop haveged
# systemctl disable haveged
На самом деле, нет ничего темного и мрачного в службе haveged
, которую я останавливаю в этом примере: это такой инструментик, который я часто запускаю для создания случайной фоновой системной активности, когда создаю ключи шифрования.
Поиск установленных программ
Мог ли кто-то установить в системе программы без вашего ведома? Ну, чтобы узнать — нужно посмотреть. Команда yum list installed
или, в случае Debian/Ubuntu, dpkg — list
выдаст вам подробную сводку, а команда remove должна удалить все пакеты, которые нам не нужны.
# yum list installed
# yum remove packageName
Вот как то же самое делается в Ubuntu:
# dpkg --list
# apt-get remove packageName
Также полезно следить за изменениями, которые вносятся в ваши системные конфигурационные файлы — об этом мы поговорим в главе 11.