9 February 2013

На пути к созданию безопасного веб-ресурса. Часть 1 — серверное ПО

Information Security
Tutorial
Я уже довольно долгое время хочу формализовать все свои мысли, опыт, ежедневно применяемый на практике, и многое другое в одном месте и предоставить их общественности. Уверен, многим этот материал будет полезен. Он посвящен различным моментам в конфигурации серверного ПО Linux и безопасным подходам к созданию сайтов/приложений на php (все же это до сих пор одна из самых популярных связок, хоть её успешно и подвигают другие технологии. Но советы так же легко применимы и к веб-ресурсам на других технологиях).

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

Конфигурация серверного ПО


Nginx + php-fpm

Начал бы я с объяснения выбранной связки. У меня были различные ресурсы, довольно высоконагруженные, где нужно было уживаться сразу нескольким приложениям, а кроме того, не только вебу. Я перепробовал всевозможные связки (apache, apache с отдачей статики nginx'ом, nginx + php в режиме cgi и т.д.) и наилучшим вариантом все-таки оказалась связка nginx + php-fpm. Как по стабильности, так и по гибкости настройки, так и в плане безопасности. Ну а если у вас до сих пор Apache, то прекратите им пользоваться прямо сейчас (С) не помню откуда (хотя следующие советы легко портируются и подходят и для любой другой связки).
Прежде всего хотел бы сказать, что стоит разделять машины для каждого ресурса. Да, можно каждый сайт изолировать друг от друга, как это делается на shared-хостингах, но все же сейчас аренда виртуальных серверов не так высока (задумайтесь над этим, прежде чем разместить еще один сайт на этой же машине, пусть даже соблюдая различные правила: разные юзеры для каждого ресурса и т.д. Ну или пытайте jail ;).

Начнем с конфига самого сайта:

location /index.php {
...
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.socket;
...
}

Желательно спроектировать веб-приложение так, чтобы оно могло работать всего от одного php-файла в htdocs и подобным образом настроить location — /index.php. Это исключает вообще возможность выполнения залитого php-шелла в htdocs. Мы вернемся к этому во второй части этой статьи.

Фиксим багу с fix_pathinfo, описанную тут. Редактируем php.ini и меняем значение параметра fix_pathinfo на

cgi.fix_pathinfo=0

Усложняем жизнь скрипт-кидди и блочим популярные сканеры по UA (из статьи):

if ( $http_user_agent ~* (nmap|nikto|wikto|sf|sqlmap|bsqlbf|w3af|acunetix|havij|appscan) ) {
    return 403;
}

Верьте мне, львинная часть «хакеров» отсеется :)

Костыль для защиты от CSRF

Следующее правило я крайне не рекомендую к использованию, но если столкнулись с проблемой, что кто-то активно юзает CSRF на ваших юзерах следующее правило может помочь, если нет никакой нормальной возможности добавить защиту от CSRF

# ANTI CSRF HACK
    valid_referers blocked example.com www.example.com;
    if ($invalid_referer) {
	set $possible_csrf 1;
}
    if ($request_method = POST) {
	set $possible_csrf "${possible_csrf}2";
}
    if ($possible_csrf = 12) {
	return 403;
}

Подобные страшные конструкции нужны, так как nginx не поддерживает множественные условия в if, а так же не поддерживает вложенные if'ы. В первой строчке указываем реферы, которые будут валидны (blocked — порезанные фаирволлом и реферы с нашего сайта). И если метод = POST, то блочим пользователя. В наше время почти никто не использует прокси-сервера, которые вырезают referer в запросах клиентов, но такая вероятность есть. Поэтому пример выше — не решение, а лишь грязный хак.

Anti-DNS pinning

Правила разбора host нужно настроить так, что если значение HOST в HTTP заголовке не нашего ресурса, то отдавать 404. Пример.

X-Frame-Options

Добавляем жизненно необходимые заголовки (так же почерпнем информации из статьи VladimirKochetkov). Во-первых, запретим показ нашего ресурса в iframe:

add_header X-Frame-Options DENY;

Это спасет наш ресурс от возможного DDOS'a через iframe, а так же от возможного clickjacking'a на сайте. Не стоит забывать и про трюки с CSS с использованием iframe.

X-Content-Type-Options

add_header X-Content-Type-Options nosniff;

Это скажет IE, что нет необходимости автоматически определять Content-Type, а необходимо использовать уже отданный content-type. Уже были security-баги у IE, связанные именно с автоматическим определением типа содержимого.

X-XSS-Protection

add_header X-XSS-Protection "1; mode=block;";

Так же заголовок для IE. Активирует встроенную XSS-защиту.

X-Content-Security-Policy

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

add_header X-Content-Security-Policy "allow 'self';";
add_header X-WebKit-CSP "allow 'self';";

Определяет, с каких доменов можно подгружать JS (X-Content-Security-Policy для IE10 и X-WebKit-CSP для FF/Chrome). В примере выше указано правило, которое позволит подгружать JS только с этого же домена.

Strict-Transport-Security

Если Ваш ресурс работает через https и происходит редирект с 80го порта на 443 (для удобства) то клиент может поддерживать некоторое время незащищенное соединение. Данный заголовок исключает возможность MITM в этот самый, довольно короткий, промежуток времени (перехват трафика в TOR). Подробнее здесь.

Firewall

Одна из важнейших конфигураций. Общая идея такая — разрешаем несколько, запрещаем все остальное. Я не гуру iptables, возможно кто-нибудь в комментариях меня поправит и мы придем к более лучшему решению. Считаем, что eth0 у нас внешний интерфейс и будем ограничивать именно его (обычно доступ из внутренней сети полный).

-A INPUT -i eth0 -p icmp -j ACCEPT # разрешаем пинг до нашего ресурса
-A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT # разрешаем только уже поднятые или порождаемые соединения
-A INPUT -s 12.34.56.78 -i eth0 -j ACCEPT # здесь указываем IP адрес, с которого бы нам желательно иметь полный доступ ко всем портам (если это требуется)
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT  # ssh
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT # web
-A INPUT -i eth0 -j DROP # запрещаем все остальное

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

Мониторим сервер

Отличным инструментом для мониторинга сервера (нагрузка, сеть, кол-во запросов, логирование исключений) является New Relic. При «правильной» (мой взгляд на это я изложу во второй части) архитектуре даже не будет необходимости мониторить access.log / error.log. Установка и под Win, и под Linux очень проста. Регистрируетесь, добавляете сервер, добавляете репозиторий и ставим демон этого сервиса. А потом в одну строчку его активируем и запускаем. Must have, в общем.

Мониторим файловую систему

Неплохо было следить за изменениями файловой системы, вдруг кто чего залил или изменил? Linux для мониторинга файловой системы предоставляет отличное API — inotify (более подробная статья от youROCK). И существует уже готовый скрипт на perl (конечно, есть аналоги) — iwatch, который полностью автоматизирует процесс мониторинга нужных нам директорий. Установка в debian системах проста:

apt-get install iwatch


И получаем отличные часики Конфиг файл находится по адресу etc/iwatch/iwatch.xml и выглядит следующим образом:

<?xml version="1.0" ?>
<!DOCTYPE config SYSTEM "/etc/iwatch/iwatch.dtd" >

<config lang="xml">
  <guard email="youremail@gmail.com" name="IWatch"/>
  <watchlist>
    <title>Operating System</title>
    <contactpoint email="root@localhost" name="Administrator"/>
    <path type="single" syslog="on">/bin</path>
    <path type="single" syslog="on">/sbin</path>
    <path type="single">/etc</path>
    <path type="recursive">/lib</path>
    <path type="exception">/lib/modules</path>
  </watchlist>
</config>

Все довольно очевидно. Перечисляем нужные нам папки, что надо — исключаем и указываем почту, куда слать отчеты (на gmail все отлично приходит).

Если решите просто скачать скрипт с sourceforge, то нужные зависимости в perl доставляются очень просто — cpan #modulename, например cpan XML::SimpleObject::LibXML.

AppArmor, SELinux, chroot и другие приблуды

К сожалению, если в гугле ввести «SELinux» то первой подсказкой будет «SELinux disable». С AppArmor похожая песня. Частично это связано с тем, что эти средства защиты включены по-умолчанию и доставляют проблемы работающему софту. И ты уже потратил битый час и выпил третью кружку кофе, разбираясь, почему не работает нужный скрипт/софт. Я бы предложил все-таки разобраться с этими «магиями мира Linux» и ознакомиться со следующими статьями:


Хочу сказать, что на практике действительно бывают проблемы при пентесте/взломе от подобных механизмов, так что постарайтесь не пренебрегать ими.

IPS, IDS, WAF

Если у вас уже действующий бизнес-проект, то предлагаю пропустить чтение каких-либо статей по настройке WAF/IPS/IDS и воспользоваться готовыми решениями, например от F5 или от Cloudflare. С Cloudflare вообще куча проблем (для атакующих). Если я вижу, что ресурс на нем, это сразу означает потраченное время х 5. Могу сказать, что Anonymous, 1337day.com (inj3ct0r) и другие pro-security используют именно Cloudflare (никакой рекламы, это просто факт). Конечно, есть варианты обхода и этих систем, но они обычно требуют от атакующего дополнительных растрат, к примеру на аренду машин в облаке с кучей разных IP-адресов, но это уже тема немного другого топика.

Ну а если проект только в начале своего пути и нет денег на подобные сервисы, то предлагаю следующие статьи к прочтению:


На Хабре ничего нет про Suricata (мне ее настойчиво рекомендовал один знакомый хакер из Африки). К сожалению, сам ничего сказать не могу о ней, и не знаю ссылок на хорошие обзоры. Я придерживаюсь использования защитных проксирующих сервисов перечисленных в начале.

Безопасность DNS

Если Вы используете свой DNS-сервер (или чей-либо) не забудьте проверить AXFR-запросы к нему (ним) для используемых доменов. Подробно описывал проблему здесь.

Grsecurity

Надеюсь, когда-нибудь мои руки дойдут до Grsecurity. И тогда я добавлю информацию о нем в топик.

Про ведение бэкапов, верные chmod/chown, мониторинг логов (error.log в т.ч.) и событий системы я умолчу, это должно быть само собой разумеющимся.

Серии:
Tags:nginxphpsecurityidsipswaf
Hubs: Information Security
+148
96.5k 1614
Comments 47
Ads