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

 

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.

Базовая авторизация в Apache

Защита настроек

Чтобы защитить security-настройки, которые ты сделал в конфигурационном файле, и не дать пользователям возможности изменить их, можно отключить поддержку htaccess-файлов:

<Directory />
    AllowOverride None
</Directory>

Прячем Apache от чужих глаз - ServerSignature Off


 

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;
}

Если не выключить server_tokens, то очень просто узнать версию nginx

Боты под запретом

Бороться с ботами, сканирующими сервер на наличие различных доменов, можно, разрешив запросы только к сконфигурированным виртуальным доменам или 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 достаточно много написано как в Сети, так и на страницах нашего журнала, поэтому особенно долго останавливаться на этом не будем. Отметим лишь наиболее значимые параметры, на которые стоит обращать внимание в первую очередь.

Раскрытие версии 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_INFOtest.php. Результатом всего вышеизложенного будет то, что любой пользователь, у которого будет возможность заливать файлы на сервер (допустим, добавлять себе аватарки), сможет создать специальное изображение, которое будет проходить валидацию и в то же время исполняться PHP-интерпретатором. Что позволит выполнять произвольный код на стороне сервера с привилегиями PHP-процесса.

Как правильно

Вариант первый — установить в php.ini переменную cgi.fix_pathinfo в 0. Вариант второй — добавить try_files $fastcgi_script_name =404; в блок location:

location ~ \.php$ {
    try_files $fastcgi_script_name =404;

}

 

В заключение

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

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии