Базовая фортификация Linux: выбираем ежи и учимся рыть траншеи


    Несмотря на то, что Linux по праву считается более защищенной системой, чем MS Windows, самого по себе этого факта мало.


    Поэтому я хочу рассказать про базовую настройку безопасности в семействе Linux. Статья ориентирована на начинающих Linux-администраторов, но возможно и матерые специалисты почерпнут для себя что-нибудь интересное. В тексте не будет пошаговых инструкций – лишь базовое описание технологий и методов, а также несколько личных рекомендаций.


    Где начать закручивать гайки


    Первая и самая главная рекомендация ― аккуратнее относиться к инструкциям в интернете. К сожалению, часто эти инструкции содержат неактуальную, а то и вредную информацию и не объясняют, почему делается так, а не иначе. Всегда надо понимать, что именно вы делаете. Копировать же команды в консоль и вовсе опасно.


    Как правило, большинство продуктов достаточно хорошо документированы, и информацию лучше черпать из официальных источников.


    В сети часто встречаются рекомендации не работать под пользователем root ― суперпользователем, обладающим полными правами на все. Отчасти рекомендация верная: работать под root небезопасно с точки зрения фатальности возможных ошибок и опасности перехвата пароля.


    Так как реально на сервере вы работаете пару раз за год, и при этом занимаетесь в основном обновлением или небольшой правкой конфигов, работа с рут-правами напоминает как раз временное повышение привилегий с помощью sudo. Но ряд разумных мер предосторожности все равно не помешает:


    • в идеале настроить вход на сервер по ключам;


    • не вводить пароль от суперпользователя на ненадежных машинах;


    • не использовать простые или словарные пароли. Можно и вовсе переименовать пользователя root, только сначала лучше проверить последствия в тестовой среде.

    Установка обновлений безусловно нужна и полезна. Только вот не один раз именно обновление как отдельных пакетов, так и операционной системы приводило к краху. Поэтому всегда перед обновлениями стоит проверить их установку на копии рабочего сервера.


    Защищаем файловую систему


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


    В каждом дистрибутиве используется так называемая избирательная система доступа. Например, возможность пользователя открыть файл проверяется по списку управления доступом (Access Control List, ACL) ― какие «галочки» для этого пользователя включены.


    Хороший принцип в обеспечении безопасности – предоставлять только те права, которые действительно необходимы для работы.

    В частности, в системах Linux для файлов используется следующий механизм предоставления доступа:


    • у каждого объекта есть три параметра доступа ― для владельца, для группы пользователей, куда входит владелец и для всех остальных;


    • каждый параметр может принимать комбинацию из трех значений ― можно читать, можно изменять, можно запускать.

    Право доступа удобно представить в числовом виде. Число будет трехзначным, вычисляемым по простой схеме:


    Тип доступа Владалец Группа Все
    Право читать 400 40 4
    Право изменять 200 20 2
    Право запускать 100 10 1

    Таким образом, право на полные права для всех на объект будут выглядеть как: (400+200+100) + (40+20+10)+(4+2+1) = 777. Такие права, как правило, не нужны никогда и никому, допустимо их выставлять лишь в процессе отладки.


    Подобный механизм доступа иногда называется UGO (User-Group-Others).


    Подробнее о правах доступа и работе с ними можно почитать в соответствующих материалах.


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


    По умолчанию эта система отключена. Для ее включения необходимо монтировать жесткий диск с опцией acl. Для примера включим acl для корневого раздела, добавив опцию монтирования в /etc/fstab:



    Теперь система загрузится с поддержкой расширенных ACL.


    Теперь можно управлять списками доступа с помощью команды setfacl. Просмотр текущих разрешений ― getfacl.


    Подробнее ознакомиться можно в документации, я же для примера дам полные права доступа пользователю user на файл test.txt:



    Предоставление полных прав пользователю user.


    Механизм защиты довольно прост, эффективен… и напоминает ACL в файловой системе NTFS.


    Огненная стена на автобане


    Основной механизм для защиты доступа к серверу ― традиционно фаерволл. В системах GNU\Linux для этого используется встроенный в ядро netfilter.


    Для желающих освежить в памяти основные принципы работы этого фаервола ― добро пожаловать под спойлер.

    В системе netfilter трафик проходит через так называемые цепочки. Цепочка ― это упорядоченный список правил. В каждом правиле есть критерии для фильтрации пакета и действие, которое нужно совершить с пакетом, попавшим под эти критерии. Критериев существует довольно много, действия по умолчанию:


    • ACCEPT. Пропускаем пакет;


    • DROP. Удаляем пакет;


    • QUEUE. Передаем пакет на анализ внешней программе;


    • RETURN. Возвращаем пакет в предыдущую цепочку.

    Цепочки по умолчанию выглядят так:


    • PREROUTING. Изначальная обработка входящих пакетов;


    • INPUT. Обработка входящих пакетов, адресованных непосредственно локальному процессу;


    • FORWARD. Обработка входящих пакетов, перенаправленных на выход. Нужно отметить, что перенаправляемые пакеты проходят сначала цепочку PREROUTING, затем FORWARD и POSTROUTING;


    • OUTPUT. Обработка пакетов, генерируемых локальными процессами;


    • POSTROUTING. Окончательная обработка исходящих пакетов.

    Разумеется, цепочки можно создавать и свои. В свою очередь цепочки для удобства работы объединены в следующие таблицы:


    • raw. Эта таблица просматривается до передачи пакета системе определения состояний. Используется довольно редко, содержит цепочки PREROUTING и OUTPUT;


    • mangle. Содержит правила модификации IP‐пакетов. Как правило, модифицируется заголовок пакета. Содержит все пять стандартных цепочек;


    • nat. Работает только с пакетами, создающими новое соединение. Помимо стандартных, поддерживает действия DNAT, SNAT, MASQUERADE, REDIRECT. В современных операционных системах содержит цепочки PREROUTING, INPUT, OUTPUT, и POSTROUTING;


    • filter ― основная таблица. Используется по умолчанию, если название таблицы не указано. Содержит цепочки INPUT, FORWARD, и OUTPUT.

    Цепочки с одинаковым названием, но в разных таблицах независимы друг от друга. Например, raw PREROUTING и mangle PREROUTING обычно содержат разный набор правил: пакеты сначала проходят через цепочку raw PREROUTING, а потом через mangle PREROUTING.


    Также в фаерволе есть специальный модуль определения состояний пакетов ―conntrack. Состояния могут быть следующих видов:


    • NEW. Новое подключение, соединение получает это состояние, если обнаружен первый пакет в соединении;


    • ESTABLISHED. Уже состоявшееся подключение. Соединение получает это состояние, если пакет уже не первый. Очень удобно использовать для разрешения ответного трафика;


    • RELATED. Самое «хитрое» состояние соединения. Соединение получает его, только если само было инициировано из другого соединения. Типичный пример ― работа FTP-сервера, в котором канал передачи данных поднимается отдельно от канала приема команд;


    • INVALID. Состояние, когда пакет не может быть идентифицирован. Обычно к таким пакетам применяют действие DROP.


    Путь проверки пакета в системе netfilter.


    Для управления фаерволом чаще всего используется утилита iptables. Материала по ней достаточно, поэтому ограничусь общей рекомендацией ― блокируем все, что не разрешено. А что разрешено ― максимально ограничиваем.


    Например, если доступ по SSH к серверу необходим только с определенных внешних адресов ― разрешите доступ только с них.


    Но с iptables работать не всегда удобно, потому что требуется глубокое понимание пути прохождения пакетов. В качестве альтернативы часто используются другие утилиты, вроде ufw в системах Ubuntu.


    Например, для предоставления доступа по ssh с помощью ufw достаточно выполнить команду:


    ufw allow from 1.2.3.4 to any port 22
    

    Тоже самое с помощью iptables выглядело бы более громоздко. Разрешим входящий трафик:


    iptables -A INPUT -p tcp -s 1.2.3.4 --dport 22 -j ACCEPT
    

    Затем разрешим ответный трафик:


    iptables -A OUTPUT -p tcp --sport 22 -d 1.2.3.4 -j ACCEPT
    

    Надо сказать, что чаще вместо того чтобы делать два явных правила для входящего и ответного трафика, просто разрешают трафик установленных соединений (ESTABLISHED) и связанных с установленными (RELATED). Для этого достаточно разрешить все подключения ESTABLISHED и RELATED следующими командами:

    iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    
    iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
    

    В современных RPM-дистрибутивах вроде CentOS, Fedora и Red Hat в качестве замены iptables используют демона firewalld. От привычного механизма он отличен тем, что может применять правила на ходу без перезагрузки списка, а также работой с зонами ― уровнями доверия к сетевым подключениям. Немного напоминает встроенный фаервол Windows. Правда, использовать его после iptables немного непривычно, и часто системные администраторы предпочитают вернуть сложный, но привычный iptables.


    В связке с фаерволом тесно работает и такой механизм как fail2ban, который делает следующее:


    • мониторит лог какого-либо сервиса, например ssh или ftp;


    • если слишком много подключений с одного IP-адреса с неверными логинами и паролями ― блокируем этот IP с помощью фаервола на некоторое время. Вдруг это брутфорс.

    Подробнее с настройкой fail2ban можно ознакомиться в официальной Wiki.


    АНБ на страже


    SELinux ― дополнительный механизм принудительной системы контроля доступа. В отличие от классической избирательной, доступ основан на специальных политиках, а не ACL.


    Минусы системы доступа на базе ACL:


    • пользователь сервера может предоставить доступ к своим файлам ― например, к закрытым ключам;


    • процессы наследуют права пользователя и могут изменить права доступа к файлам ― например, скомпрометированный браузер может получить доступ к почтовой переписке.

    Устранить эти недостатки может SELinux, созданный АНБ (Агентство Национальной Безопасности США) и Red Hat еще в 1998 году. В ядре Linux-систем эта технология присутствует уже давно. Тем не менее в некоторых инструкциях до сих пор часто встречается рекомендация ее отключить, что не всегда справедливо. Подробнее про SELinux можно почитать в профильной статье на Хабре, поэтому ограничусь небольшим ликбезом.


    У SELinux есть три режима работы:


    • enforcing. Режим работы по-умолчанию, все неразрешенные действия блокируются;


    • permissive. Все неразрешенные действия выполняются, но записываются в журнал;


    • disabled. SELinux отключен.

    Узнать текущий режим работы можно командой getenforce, переключиться между режимами enforcing и permissive можно командой setenforce. Выключение же SELinux требует перезагрузки системы.


    Механизм защиты применяется после классического, и базируется на специальной маркировке объектов. Посмотреть текущую маркировку можно командой:


    ls -Z
    


    Смотрим маркировку свежесозданного файла.


    В качестве примера настройки я разберу ситуацию, когда мы хотим разместить сайт в папке не по умолчанию и «повесить» веб-сервер на другой порт. Одной смены значений в конфигурационном файле httpd.conf будет недостаточно, необходимо сказать SELinux, что веб-серверу следует предоставить доступ к папке и к порту. Для этого необходимо:


    • установить пакет администрирования policycoreutils-python;


    • сказать системе о маркировке папки командами:


      semanage fcontext -a -t httpd_sys_content_t "/path/to/www(/.*)?"
      semanage fcontext -a -t httpd_sys_rw_content_t "/path/to/www(/.*)?"

    • восстановить маркировки командой:


      restorecon -R /path/to/www

    • предоставить доступ к порту:

    semanage port -a -t http_port_t -p tcp 81

    Разумеется перед тем, как проделывать все это, рекомендую детально ознакомиться с работой SELinux.


    SELinux как решение не уникален. Второй по популярности механизм защиты ― это AppArmor. Его разработку изначально курировала Novell, но после инструмент забросили как бесперспективный. Однако теперь над AppArmor работает Canonical, и продукт тесно связан с системой Ubuntu. Что касается отличий, то AppArmor удобнее SELinux благодаря множеству готовых политик.


    Есть и механизм обучения, при котором действия пользователей записываются в журнал, но не блокируются ― так можно запустить новую защиту в качестве «пилота» и сразу устранить огрехи. Если в SELinux этот режим включается для всей системы, то с AppArmor его можно активировать для конкретного приложения. Пример такого назначения:


    aa-complain /path/to/bin
    

    Ключевое отличие AppArmor от SELinux заключается в том, что AppArmor привязывает политику к пути, а SELinux опирается на дескриптор файла. Если заблокировать исполнение файла и потом переместить его, то AppArmor позволит файлу запуститься, а SELinux ― нет.


    Если же файл перезапишут по исходному пути, то уже AppArmor заблокирует его, а SELinux разрешит выполнение. Избежать этих недоразумений можно включением политики «блокировать все, кроме явно разрешенного».


    Если описать отличия коротко, то разработчики SELinux делали упор не на простоту использования, а именно на безопасность. С AppArmor все обстоит с точностью до наоборот. Почитать об AppArmor подробнее можно в документации от производителя, либо в библиотеке Ubuntu.

    Увы, не могу дать однозначный совет, что вам выбрать, потому что это вопрос приоритетов и предпочтений по дистрибутиву ОС. Поклонники Centos и Red Hat чаще выбирают SELinux, а любители Ubuntu ― AppArmor.


    Кстати, напишете в комментариях, какой механизм предпочитаете вы?


    Набор отмычек на всякий случай


    В этом разделе я расскажу про несколько полезных, но не must-have механизмов для защиты сервера.


    Запрет подключений root к терминалу


    В системах GNU\Linux можно ограничить список терминалов, куда может подключаться пользователь root. Сделать это можно путем модификации файла /etc/securetty. Если файл пустой, то root не сможет напрямую подключаться вовсе, и для получения полных прав понадобится su или sudo.


    Политика паролей


    Также может быть полезно задать срок действия пароля следующей командой:


    chage -M 20 username
    

    Где 20 ― это срок действия пароля в днях. Другим вариантом будет изменение общей политики паролей в файле /etc/login.defs. Допустим, мы хотим, чтобы пароль нужно было менять каждые 20 дней, и чтобы пользователь за 5 дней получал напоминание об этом. Тогда содержимое файла будет следующим:


    PASS_MAX_DAYS 20 
    
    PASS_MIN_DAYS 0
    
    PASS_WARN_AGE 5
    

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


    password required pam_cracklib.so minlen=8 lcredit=1 ucredit=1 dcredit=1 
    

    в файл /etc/pam.d/system-auth.


    Уведомления о случаях повышения прав


    Еще одна нужная опция ― уведомление о каждом вводе sudo для контроля доступа к правам суперпользователя. Для этого достаточно добавить в файл /etc/sudoers следующие строки:


    mailto [admin@domain.com](mailto:admin@domain.com)
    
    mail_always on
    

    Разумеется, в системе должен быть настроен агент отправки почты. Неплохим вариантом замены стандартного sendmail является ssmtp, который легко сдружится с отправкой писем даже через бесплатные почтовые сервисы.


    Деактивация компиляторов


    Во избежание компиляции и запуска зловредного ПО не лишним будет отключить компиляторы на сервере для использования пользователями.


    В качестве примера под спойлером отключим доступ к gcc.

    Для начала посмотрим список исполняемых файлов командой:


    rpm -q --filesbypkg gcc | grep 'bin'
    


    Исполняемые файлы gcc.


    Теперь будет удобно создать отдельную группу командой:


    groupadd compilerGroup
    

    Затем сменить группу-владельца для нужных файлов:


    chown root:compilerGroup /usr/bin/gcc
    

    И задать права доступа, запрещающие доступ к файлам всем прочим:


    chmod 0750 /usr/bin/gcc
    

    Иммунитет для файлов конфигураций


    Хороший способ защитить системные файлы и конфигурации даже от суперпользователя ― это атрибут иммуности. Для его применения используется команда chattr +i filename.



    Даже root не может удалить иммунный файл.


    Для снятия этого атрибута достаточно выполнить команду chattr -i filename.


    Я думаю у каждого администратора есть еще свои best-practices по безопасности серверов. Предлагаю поделиться ими с коллегами в комментариях.

    Сервер Молл 37,30
    Refurbished-серверы HP, Dell и IBM (Lenovo)
    Поделиться публикацией
    Комментарии 24
    • +1
      Можно и вовсе переименовать пользователя root

      можно.
      админам локалхоста всё можно...


      К сожалению, часто эти инструкции содержат неактуальную, а то и вредную информацию и не объясняют, почему делается так

      вот-вот.
      можно узнать, чем переименование рута лучше * ему в /etc/shadow?

      • 0
        Ну если начать уже так придираться, но можно например такое
        а) * в /etc/shadow не блокирует подключение по ключам.
        б) на неправильный логин отлуп на несколько инструкций «быстрее», чем сравнение хешей.
      • 0
        Ограничивать срок действия пароля больше не считается хорошей идеей:

        https://nakedsecurity.sophos.com/2016/08/18/nists-new-password-rules-what-you-need-to-know/
        • 0
          Еще можно было бы про port-knocking рассказать
          • +1

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


            Что касается компиляторов, то компиляторы на сервере лучше бы не устанавливать вовсе(если есть такая возможность), а нужное ПО компилить для сервера в контейнере докер/виртуалке или на отдельном билдсервере.

            • 0
              Злоумышленник может не знать об этом флаге, как итог он потратит больше времени чем расчитывал.
              • 0

                Возможно. Но это уже будет какой-то низкоквалифицированный злоумышленник, большинство из них всё-таки знают что такое lsattr и chattr и как ими пользоваться.

                • +1
                  А почему злоумышленник не может быть низкоквалифицированным? Более того, он вообще может быть роботом — пролез через какую-нибудь свежую дырку в установленном софте и хозяйничает не сервере. В этом случае даже простейшие методы защиты могут оказаться эффективны.
                  • 0
                    Согласен, часто попадаются взломы которые сделаны роботом. Так например один робот пытался запустить на FreeBSD зловреда, который упорно искал /proc. т.к на FreeBSD слоя совместимости с Linux не было, то он висел в бесконечном цикле и просто потреблял ресурсы. При этом не было никакой активности типа спама или ddos.
                    • 0

                      Могут. И нередко так оно и есть, и использование флага иммутабельности в таких случаях очень даже может помочь. Но про регулярный бэкап конфигов навесив на них флаг i забывать не стоит, а что может быть лучше не просто бэкапа, а сохранения изменений в git?

              • 0
                Актуальный сейчас firewall в RH-based firewalld. Ещё можно рассказать про логи и про монитоирнг checksum для ключевых файлов.
                • 0
                  Может быть я ретроград в этом плане, но, честно говоря, не особо люблю эту обертку, потому, как правило, удаляю и настраиваю с нуля чистый iptables.
                  Хороший мануал нашел в 2000 бородатом году, актуален и по сей день http://www.opennet.ru/docs/RUS/iptables/
                  • 0
                    Он весьма удобен, но другие дистры как-то не подхватили тренд.
                  • 0
                    Не помешало бы описать монтирование разделов, tcp_wrappers, audit, AIDE, файловым системам, да и в целом пробежаться по CIS рекомендациям — https://www.cisecurity.org/cis-benchmarks/, для тех кто пользуется ansible, есть плейбуки https://github.com/MindPointGroup/RHEL7-CIS — сам не проверял, но выглядит многообещающе.
                    • 0
                      Спасибо всем за замечания и пожелания. Всё будет учтено в следующей статье.
                      • 0

                        Интересно, для какой атаки необходим компилятор на сервере? Что мешает злоумышленнику с shell'ом скачать готовый зловред под нужную архитектуру, или запустить скрипт на том же shell?

                        • 0
                          Скрипт на том же самом шелле, например, не сможет быть модулем для апача, например.
                          • 0

                            Если есть доступ к шеллу — проще скачать готовый модуль.

                            • 0
                              Проще-непроще, я про рабочие кейсы говорю, которые сам видел и чинил, а не в теории рассуждаю, что якобы проще злоумышленнику.
                        • 0
                          Linux по праву считается более защищенной системой, чем MS Windows

                          Мне кажется, или вы сравниваете ядро, с нафаршированной под завязку операционной системой общего назначения?
                          Даже если так, где можно увидеть развернутое сравнение, которое подтвердит ваш тезис?
                          • 0
                            По умолчанию эта система отключена.

                            кстати, если брать Арч то acl по умолчанию установлен(как зависимость systemd) и включен.
                            • 0
                              Думаю, что было бы плюсом к статье рассказать про логирование в сторонку и дать рекомендации по организации бэкапа.
                              • 0
                                а) * в /etc/shadow не блокирует подключение по ключам.

                                а должен? ;)
                                что было раньше: /etc/shadow или sshd?


                                б) на неправильный логин отлуп на несколько инструкций «быстрее», чем сравнение хешей.

                                ой, я вас умоляю…
                                переименование рута внесёт гораздо больше разнообразия (в т.ч. и лишних "инструкций") в сисадминскую рутину...

                                • 0
                                  Например?
                                  Просто переименовать юзера и ВСЕ, никаких других инструкций нет.

                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                Самое читаемое