Содержание статьи
Часто, разворачивая сервер для своего ресурса или настраивая другое ПО, мы оставляем большинство опций в конфигурационных файлах по умолчанию. Потом проект обрастает функционалом, и конфиги все реже удостаиваются внимания, превращаясь в бомбы замедленного действия, которые злоумышленник может успешно использовать. Поэтому сегодня мы рассмотрим параметры безопасности популярного серверного ПО, настройку которых лучше не откладывать в долгий ящик.
Apache
Начнем с конфигурации индейца, завоевавшего место на многих серверах в Сети. Первая настройка, которую желательно сделать, — это лишить злоумышленника возможности узнать версию Apache. Для этого существует две директивы, которые надо установить в следующие значения:
ServerSignature Off
ServerTokens Prod
Отдельный пользователь и группа
Вторым пунктом желательно убедиться, что Apache работает под своим отдельным пользователем и группой. Если под этим же пользователем будет работать, например, СУБД, то в случае компрометации веб-сервера злоумышленник сможет получить доступ и к базе данных.
Корневая директория
Затем необходимо убедиться, что файлы, расположенные вне корневой директории, не обрабатываются веб-сервером. Если предположить, что все сайты на сервере находятся в одной директории (допустим, /web
), конфигурация должна выглядеть следующим образом:
<Directory />
Order Deny,Allow
Deny from all
Options None
AllowOverride None
</Directory>
<Directory /web>
Order Allow,Deny
Allow from all
</Directory>
Выключить просмотр содержимого директорий можно внутри тега <Directory>
с помощью Options -Indexes
:
- выключить server side инклуды —
Options -Includes
;
- отключить выполнение CGI —
Options -ExecCGI
;
- не позволять Apache открывать символические ссылки —
Options -FollowSymLinks
.
Ресурсы и DoS
Чтобы смягчить эффект от DoS-атак, можно снизить значение тайм-аута — Timeout 45
. Как вариант, можно еще установить ограничение на размер тела запроса, сделав его, к примеру, равным 1 Мб, — LimitRequestBody 1048576
. А вообще, на поведение сервера при повышенном внимании к нему со стороны ботов будут влиять еще следующие параметры: RequestReadTimeout
, KeepAliveTimeout
, MaxRequestWorkers
, а также директивы, ограничивающие потребление ресурсов: LimitRequestFields
, LimitRequestFieldSize
, LimitRequestLine
и LimitXMLRequestBody
Ограничение доступа
В случае если развернутый на сервере ресурс предназначен только для определенной подсети, можно ограничить доступ к нему:
Order Deny,Allow
Deny from all
Allow from 176.16.0.0/16
или для отдельного IP-адреса: Allow from 127.0.0.1
.
Защита настроек
Чтобы защитить security-настройки, которые ты сделал в конфигурационном файле, и не дать пользователям возможности изменить их, можно отключить поддержку htaccess
-файлов:
<Directory />
AllowOverride None
</Directory>
WWW
Большинство трудно отлавливаемых проблем (которые могут повлиять и на безопасность) с веб-сервером возникают из-за неправильной конфигурации. На сайте Apache приведен список типичных мисконфигураций, с объяснением проблемы и способом решения.
nginx
Следующим гостем нашего обзора следует веб-сервер nginx. Во-первых, можно, как и в случае с Apache, скрыть тип и версию сервера, это так называемое security through obscurity, которое заставит атакующего потратить дополнительное время. Для этого в файле src/http/ngx_http_header_filter_module.c
надо поменять строки
static char ngx_http_server_string[] = "Server: nginx" CRLF;
static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
на
static char ngx_http_server_string[] = "Server: ][akep Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: ][akep Web Server" CRLF;
После чего скомпилировать сервер. Чтобы скрыть версию сервера, нужно в конфигурационном файле nginx.conf
добавить опцию server_tokens off
. Теперь атакующему не так просто будет узнать тип веб-сервера и его версию. Что уже неплохо.
Ограничиваем буферы
Далее, чтобы немного обезопаситься от атак, связанных с переполнением буфера, можно применить следующие настройки:
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
где
- client_body_buffer_size определяет размер буфера для клиентского запроса;
- client_header_buffer_size устанавливает размер буфера для чтения заголовка запроса клиента;
- client_max_body_size — максимальный размер тела запроса клиента;
- large_client_header_buffers задает максимальное число и размер буферов для чтения большого заголовка запроса клиента.
Фильтруем user-агенты
Конфигурационный файл nginx.conf позволяет достаточно гибко настроить веб-сервер под себя. Например, можно запретить доступ определенным user-агентам — ботам, сканерам, downloader’ам:
if ($http_user_agent ~* LWP::Simple|BBBike|wget|libwww-perl) {
return 403;
}
Долой хотлинкинг
Еще одна полезная возможность — запрет на хотлинкинг (когда какой-то сторонний ресурс ссылается на изображение или какой-то другой ресурс твоего сервера):
location /images/ {
valid_referers none blocked www.xakep.ru xakep.ru;
if ($invalid_referer) {
return 403;
}
}
Таким образом можно снизить нагрузку на сервер и расходы на трафик, если у тебя раскрученный ресурс, конечно. Если нет — то ничего страшного, если кто-то сошлется на картинку с твоего сайта.
Ограничение доступа
Еще можно разрешить/ограничить доступ к админке или какой-то другой директории ресурса только для определенных IP-адресов.
location /docs/ {
## block one workstation
deny 192.168.1.1;
## allow anyone in 192.168.1.0/24
allow 192.168.1.0/24;
## drop rest of the world
deny all;
}
Боты под запретом
Бороться с ботами, сканирующими сервер на наличие различных доменов, можно, разрешив запросы только к сконфигурированным виртуальным доменам или reverse-прокси запросы:
if ($host !~ ^(xakep.ru|www.xakep.ru|images.xakep.ru)$ ) {
return 444;
}
Аналогично можно и ограничить число доступных HTTP-методов, например оставив только GET, POST и HEAD:
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}
Реферальный спам
Для борьбы с реферальным спамом, который может негативно отразиться на твоем SEO-ранге, можно использовать подобную конфигурацию:
if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) )
{
return 403;
}
Географический бан
Если из какой-то страны на твой ресурс постоянно идут атаки или просто контент не предназначен для какой-то страны, то доступ пользователям из таких стран также можно ограничить. Сперва надо внутри конфигурационного блока http{}
указать расположение GeoIP базы данных — geoip_country /etc/nginx/GeoIP.dat;
, а затем указать nginx, какие страны следует заблокировать:
if ($geoip_country_code ~ (CN|KR|UK) ) {
return 403;
}
Запрет на выполнение скриптов
Немного обезопасить свой ресурс можно еще одним способом — запретить выполнение скриптов из определенных директорий. Ведь, как это обычно бывает, веб-шелл заливается атакующим в одну из директорий, предназначенных для upload’а. Чтобы, даже если ему удалось обойти все фильтры и залить шелл вместо аватарки, он не смог им воспользоваться, надо сделать так:
location ~* /(images|cache|media|logs|tmp)/.*.(php|pl|py|jsp|asp|sh|cgi)$ {
return 403;
error_page 403 /403_error.html;
}
WWW
Список наиболее часто встречающихся ошибок в конфигурации nginx и советы по их устранению
MySQL
Ну а теперь пришло время немного поговорить о безопасности популярной СУБД. Как ты помнишь, ее конфигурационный файл называется my.cnf
. Обычно первой из настроек тут проверяют/изменяют bind-address
, которая отвечает за то, с каких адресов можно будет подключиться к СУБД. Так как обычно база данных физически располагается на том же сервере, что и сам ресурс, то данная опция выставляется в значение 127.0.0.1
. То есть база данных принимает только локальные подключения. Кстати говоря, как вариант, можно еще просто запретить MySQL открывать сетевой сокет, добавив в конфигурационный файл skip-networking
.
Запрет на чтение файлов
Одна из часто встречающихся уязвимостей — SQL-инъекция. Помимо того, что с ее помощью злоумышленник получает данные из БД, он может также получить возможность читать локальные файлы. Чтобы этого не произошло, необходимо установить параметр local-infile
в значение 0
.
Меняем рут
Еще одним неплохим шагом на пути к безопасности будет изменение имени и пароля суперпользователя. По дефолту это обычно пользователь root. Делается это следующими командами:
mysql> RENAME USER root TO new_user;
mysql> SET PASSWORD FOR 'new_user'@'%hostname' = PASSWORD('new_pass');
Чтобы не смущать плохих парней, лучше также удалить БД test
, создаваемую при установке, и всех анонимных пользователей с пустыми паролями.
Чистим историю
Нелишним будет также подчистить историю, куда сохраняется очень много ценной информации (например, паролей), причем в открытом виде. Делается это следующим образом:
cat /dev/null > ~/.mysql_history
PHP
По безопасности PHP достаточно много написано как в Сети, так и на страницах нашего журнала, поэтому особенно долго останавливаться на этом не будем. Отметим лишь наиболее значимые параметры, на которые стоит обращать внимание в первую очередь.
Опасные функции
Во-первых, можно заблокировать вызов потенциально опасных функций с помощью disable_functions = phpinfo, system, mail, exec
. Затем ограничить использование ресурсов — максимальное время выполнения скрипта (max_execution_time
), время на разбор запроса (max_input_time
), размер потребляемой каждым скриптом памяти (memory_limit
), максимальный размер данных передаваемый POST запросом и так далее.
Ошибки и логи
Потом можно отключить вывод ошибок пользователям — display_errors = Off
и включить логирование:
log_errors=On
error_log=/var/log/httpd/php_scripts_error.log
Маскировка
Отключить expose_php
, чтобы не выдавать факт присутствия PHP на сервере. Правда, такой трюк поможет только в случае использования ЧПУ. В противном случае URL все выдаст.
Еще можно отключить возможность открытия удаленных файлов, для этого в конфигурационном файле security.ini
устанавливаем allow_url_fopen
в значение Off
.
Force redirect
Чтобы предотвратить попытки непосредственного вызова PHP по адресу вида http://my.host/cgi-bin/php/secretdir/script.php
, можно воспользоваться директивой cgi.force_redirect = 0
. В таком случае PHP будет обрабатывать пришедший запрос, только если он был перенаправлен веб-сервером.
Ну и конечно же, можно включить safe_mode
и отключить register_globals
.
Memcached
Современные проекты становятся все сложнее и масштабнее, с ростом числа посетителей растет и нагрузка на сервер. Чтобы бороться с возрастающей нагрузкой, начинают применять кеширование. Наиболее популярным решением является memcached. Очень часто при его развертывании не уделяют должного внимания безопасности. В результате потенциальные дыры могут годами оставаться незамеченными, пока в один прекрасный день какой-нибудь «добрый» человек ее не найдет и не воспользуется. Частенько администраторы забывают о настройке подключения к демону memcached. На хабре есть история о том, как такая бага была найдена на phpclub.ru.
Бороться с этой проблемой достаточно просто — если кеширующий сервис находится на той же машине, что и сам проект, то надо ограничить доступ к нему только с локалхоста. Для этого в конфигурационном файле memcached надо изменить строчку OPTIONS=""
на OPTIONS="-l 127.0.0.1"
и перезапустить memcached. В случае если кеширующий демон расположен на отдельном сервере, необходимо ограничить доступ к нему при помощи файрвола.
Вредные советы
Обращаясь за советом по настройке к интернету, надо помнить, что не всему, что там написано, стоит верить на слово. Иногда те примеры, которые, в общем-то, работают, могут привести к появлению серьезной бреши в безопасности системы.
BaseAuth
Классический пример такой «медвежьей услуги» связан с Apache и настройкой базовой авторизации, которая применяется для ограничения доступа к какому-либо файлу или части ресурса. Один из типичных примеров, который может попасться в Сети, выглядит следующим образом:
AuthUserFile /var/www/.htpasswd
AuthName "My Private Files"
AuthType Basic
<limit GET POST>
require valid-user
</limit>
На первый взгляд все выглядит вроде бы нормально. И такая настройка может работать долго и не приносить никакой головной боли. Так в чем же тут проблема? Дело в том, что она только частично ограничивает доступ к защищаемому ресурсу. Причина в теге <limit>
, который ограничивает доступ к ресурсу только в случае, если используются GET
- или POST
-запросы. И хотя это самые распространенные методы, но не единственные — есть еще HEAD
, OPTIONS
, PUT
, DELETE
, CONNECT
и TRACE
. Другими словами, если кто-то решит использовать другой тип запроса, то сможет обойти авторизацию.
Как правильно
Лучше всего вообще не использовать тег <limit>
. Если он будет опущен, то будут запрещены все типы запросов. Если же возникла ситуация, когда надо разрешить определенный тип запросов, то можно использовать тег <limitexcept>
.
PHP-FPM & nginx
Еще один пример связан с настройкой связки PHP-FPM + nginx. Те, кто настраивал, вполне вероятно могли натыкаться в Сети на код, содержащий следующие строки:
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
Где тут собака зарыта? Дело в том, что если попросить у сервера отдать http://example.com/1px.gif/test.php
, то URI примет вид 1px.gif/test.php
, что, в свою очередь, подпадет под location ~ \.php$
, а SCRIPT_FILENAME
станет /scripts/1px.gif/test.php
. В случае если переменная cgi.fix_pathinfo
в php.ini
будет установлена в 1
(а по дефолту это так), то SCRIPT_FILENAME
станет равным /scripts/1px.gif
, а PATH_INFO
— test.php
. Результатом всего вышеизложенного будет то, что любой пользователь, у которого будет возможность заливать файлы на сервер (допустим, добавлять себе аватарки), сможет создать специальное изображение, которое будет проходить валидацию и в то же время исполняться PHP-интерпретатором. Что позволит выполнять произвольный код на стороне сервера с привилегиями PHP-процесса.
Как правильно
Вариант первый — установить в php.ini
переменную cgi.fix_pathinfo
в 0
. Вариант второй — добавить try_files $fastcgi_script_name =404;
в блок location
:
location ~ \.php$ {
try_files $fastcgi_script_name =404;
}
В заключение
На самом деле о безопасной настройке каждого из рассмотренных продуктов можно говорить достаточно долго. Америки мы сегодня не открыли, а лишь освежили в памяти те параметры, на которые следует обращать внимание при настройке своего сервера, чтобы он не стал легкой мишенью для злоумышленников. Также мы снова убедились, что не всем интернет-советчикам стоит верить. Надеюсь, данный материал мотивирует тебя еще раз проверить свои конфиги и убедиться, что с ними все в порядке.