[Перевод] Защищаем веб-сервер на Linux

Привет, Хабр!

У нас давно не выходило новых книг по Linux для начинающих — и вот мы беремся за перевод новинки именно такого плана. Книга «Linux in Action» Дэвида Клинтона вышла в издательстве Manning и рассказывает не только о внутреннем устройстве Linux, но и о наиболее распространенных проблемах, и о способах их устранения.

pwvqowqz-ymlimiywgpbhj8rzqq.jpeg


Автор опубликовал на сайте 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.

© Habrahabr.ru