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

Настройка сервера apache для безопасной работы вебсайта
Настройка сервера apache для безопасной работы вебсайта

Что вообще из себя подразумевает безопасность веб-сайта? Это целый комплекс мер, нарушение целостности хоть одного компонента может привести ко взлому. Поэтому важно соблюдать все аспекты для защиты своего проекта. Минимальный набор подразумевает в себе надёжное интернет подключение (не публичный Wi-Fi) с охраной компьютера в виде антивируса и фаервола на страже порядка. Используйте защищенные протоколы для редактирования файлов сайта такие как HTTPS, SSH, SFTP - это предотвратит передачу данных в открытом виде. Так мы защитим сайт от атак со своей стороны, однако злоумышленники чаще пользуются уязвимостями серверов или CMS.

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

Настройка Apache для повышения безопасности

Начнём с простых основ (будем считать, что наши сайты используют PHP, а не другие технологии) и сконфигурируем пхп под требования безопасности. Эта часть статьи может подойти и для шаред хостингов: многие провайдеры позволяют частично либо полностью редактировать конфигурационный документ php.ini, так и для выделенных серверов с различными связками apache, nginx, php-fpm.

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

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

Открываем и редактируем значения либо добавляем следующие строки:

allow_url_fopen = Off
allow_url_include = Off

Этими директивами мы запретим исполнение опасных скриптов с посторонних сайтов. Если по каким-либо причинам это нарушает работоспособность, к примеру компонента видеокаталога с ютуба, то можно разрешить исполнение. Кроме этого необходимо быть внимательными при наличии Recaptcha Google - если Вы не проверяете секретный ключ посредством curl, то allow_url_fopen придется включить для корректной работы рекапчи.

Скрыть версию PHP

Следующим шагом минимизируем информацию о программном обеспечении на сайте. Совсем ни к чему отсылать в заголовках версию PHP - на работоспособность эти строчки не повлияют никоим образом!

expose_php = Off
track_errors = Off
html_errors = Off

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

display_errors = off

Список disable_functions в php.ini для Joomla и Wordpress

Важным моментом будет запретить опасные функции. Список их может варьироваться от необходимо функционала на сайте, я приведу оптимальную на свой взгляд конфигурацию. При необходимости можно убирать или добавлять сюда свои значения. Ищем в php.ini строку с disable_functions ( создаём, если нету) и отключаем следующие функции:

disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,popen,pclose,proc_nice,proc_open,proc_terminate,proc_close,exec,system,passthru,shell_exec,symlink,putenv,getmyuid,fsockopen,posix_setuid,posix_setsid,posix_setpgid,posix_kill,apache_child_terminate,chmod,chdir,pcntl_exec,phpinfo,virtual,proc_get_status,getmygid,proc_getstatus,getmypid,escapeshellarg,show_source,safe_dir,dl,ini_restore,chown,chgrp,shown_source,mysql_list_dbs,getmyid,pfsockopen,get_current_user,syslog,touch,php_uname,posix_uname

Остановимся немного подробнее, за что они отвечают и зачем их вырубать. 

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

popen и pclose отвечают за открытие и закрытие файловых указателей процессов, proc_open позволяет выполнить команду в новом процессе, а proc_close завершить вызванный процесс.

proc_terminate уничтожает процесс, запущенный с помощью proc_open, а функция  proc_nice позволяет контролировать приоритет процессов.

Однако это не все функции, которые позволяют открывать программы.

Запустить внешнюю программу можно с exec, а увидеть необработанный результат вывода в придачу позволяет passthru

Исполнять утилиты можно с php расширением system, в то же время shell_exec выполнит команду посредством шелла (оболочки) и вернёт полный вывод строкой.

Внимание стоит обратить на семейство posix_ функций, отключаем отвечающее за ид процессов (posix_setuidposix_setsid), за снятие процесса (posix_kill) и вывод информации о системе (posix_uname)

Присмотреться можно и к ветке pcntl_ - мы лишь обойдёмся ограничением запуска программы в новом процессе посредством pcntl_exec

Загружать библиотеки во время исполнения позволяет функция dl, а если использовать ini_restore, то можно сбросить настройки до заводских настроек - это нам согласитесь совсем ни к чему.

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

Кроме этого часто выставляют права на директории и файлы 555 и 444 соответственно, дабы защитить от записи. Однако без блокировки chmod и правильной настройки владельцев и их прав это просто бесполезно - любой скрипт спокойно изменит атрибуты файла и снимет ограничение на изменение файла. Сюда же стоит отнести и команду chown - она позволяет изменять владельцев файлов, и chgrp - модификация группы владельцев файла.

Удаляем возможность получить информацию о системе: php_uname и phpinfo (для разработчиков часто требуется, только для завершенных проектов), а также внесение изменение в системные логи через syslog

Более детальную функцию можно посмотреть в документации, там же можно поискать чем дополнить список. Приведенный выше вариант успешно работал на популярных CMS Joomla, Wordpress и другие. При этом основная функциональность не была нарушена, невозможно просмотреть информацию о системе и при загрузке файлов или установке расширений можно увидеть предупреждение, что не удалось сменить права на файл. Для цмс ModX Evo стоит убрать touch из списка, иначе загрузить файлы в медиа-менеджере не получится, а будете получать ошибку "Нет доступа или невозможно создать папку миниатюр."

Параноидальная защита сайта в php.ini

Можно поэксперементировать и с таким вариантом, он немного более расширенный, добавлены все функции posix:

disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,popen,pclose,php_uname,symlink,chgrp,getmyuid,getmygid,putenv,getmypid,passthru,fsockopen,listen,apache_child_terminate,diskfreespace,tmpfile,link,ignore_user_abord,shell_exec,dl,set_time_limit,exec,system,highlight_file,source,show_source,fpaththru,virtual,touch,posix_ctermid,escapeshellarg,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid,posix_getgrnam,syslog,posix_getgroups,posix_getlogin,pfsockopen,posix_getpgid,posix_getpgrp,shown_source,posix_getpid,posix_getppid,mysql_list_dbs,posix_getpwnam,posix_getpwuid,posix_getrlimit,safe_dir,posix_getsid,posix_getuid,posix_isatty,chown,posix_kill,posix_mkfifo,posix_setegid,ini_restore,posix_seteuid,get_current_user,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_times,posix_ttyname,posix_uname,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,proc_getstatus,phpinfo,chmod,chdir,ftp_exec,phpcredits

В комментариях можете предлагать свои вариации.

На этом мы не будем останавливаться и добавим директиву open_basedir. За что она отвечает? Ответ прост, по умолчанию мы не ограничиваемся папкой чтения и запросив каталог на уровень выше можем попасть к системным и конфигурационным файлам либо же к файлам другого домена, если сайтов на аккаунте несколько. Это самый примитивный способ разделить проекты, если по какой либо причине не можете выделить под каждый веб-сайт отдельный хостинг. При этом не стоит полагаться только на этот метод, он распространяется на php интерпретатор, если же у вас будет разрешено исполнение bash, python, cgi и другого рода скриптов, то они с легкостью смогут обойти данное ограничение.

Обезопасить сайты ограничением open_basedir

В файл php.ini необходимо добавить путь к сайту плюс путь к временным файлам через двоеточие:

open_basedir=path/to/site:path/to/tmp

Для .htaccess файлов можно использовать код ниже, только желательно, чтобы файл был выше корня сайта (иначе файл может быть перезаписан и ограничение будет снято):

php_value open_basedir "path/to/site:path/to/tmp"

Для нескольких сайтов можно воспользоваться директивой host:

[HOST=sitename.com]
open_basedir=path/to/site:path/to/tmp

Однако если есть возможно, то лучше сразу делать это в конфигурацинных файлах апача (httpd.conf или конфиг сайта в папках vhosts или sites). Синтаксис в этом случае будет немного другим:

php_admin_value open_basedir "path/to/site:path/to/tmp."

Кроме этого есть варианты конфигурации для более старых версий php - на данный момент морально устарели и по умолчанию имеют уже необходимое значение. К таким функциям относятся "волшебные кавычки" magic_quotes_gpc, регистрация глобальных переменных register_globals и защищенный режим safe_mode.

Конфигурация php.ini против DDos

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

Почему же так делать не стоит? Ответ достаточно прост, если создать ресурсоемкий запрос, а потом ещё один, а потом ещё несколько - вот пример элементарной атаки DDos на сайт. Этим могут воспользоваться не только хакеры, но и ваши конкуренты. Чем вообще грозит этот тип атаки и к чему может привести? Оперативная память и процессор вашего блога или магазина не безграничны, и в какой-то определенный момент они иссякнут. Тогда сервер не сможет обрабатывать запросы и сайт перестанет быть доступным и не будет открываться. И совсем не вовремя будет, если провайдер решит применить санкции за превышение лимитов использования ресурсов и заблокировать аккаунт и приостановить действие услуг.

Минимализируем время исполнения скриптов следующими строчками:

max_execution_time = 20
max_input_time = 30

Если сайт шустрый и хорошо оптимизирован, то можно выставить значение:

max_execution_time = 10

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

Уменьшаем расход памяти исполняемых программ. Можно поварьировать значениями и добиться необходимого результата, чтобы хватало на исполнение и не было большого излишка. Слишком большие аппетиты тоже могут навести на мысль о плохой производительности сайта. Руководствоваться в этом случае для небольших сайтов можно таким значением:

memory_limit = 128M

Добавляем ограничение на размер вводимых данных посредством POST запросов:

post_max_size = 1K

Защищаем куки от XSS атак:

session.cookie_httponly = 1
session.referer_check = sitename.com

Отключаем ненужные приложения пхп

Если есть необходимость в загрузке документов и изображений на сервер, то ограничиваем размер файлов:

upload_max_filesize = 2M

В противном случае отключаем возможность загружать файлы на сервер:

file_uploads = Off

Если ваш сервер не использует отправку писем и в почтовой службе вообще нету необходимости, то не будет лишним убрать эту возможность, добавив функцию mail() в список запрещенных:

disable_functions = mail

После всех манипуляций с файлом php.ini сохраняем его и нам надо применить настройки. В режимах php-cgi или fastcgi изменения сразу подхватываются, иначе нам придется перезагрузить apache. Сделать это можно посредством командной строки SSH, в зависимости от операционной системы будет надо написать:

service apache2 reload

 или

service httpd reload

И проверяем работу веб сайта на практике.

Мануал по настройке безопасности PHP

Приступим к грамотной конфигурации Apache для защиты конфиденциальных данных от посторонних посетителей. Разновидностей связок предостаточно: от стандартного mod_php до fcgid и fpm, поэтому возможно придётся использовать свои значения для достижения цели.

Первоочередной задачей у нас будет использование разграничение пользователей, а точнее назначение отдельной группы и пользователя сервису апач. По дефолту такое не выставляется, поэтому создадим нового непривилегированнного юзера:

groupadd newacc
useradd -d /var/www/ -g newacc -s /bin/nologin newacc

Не забываем добавить пользователя в конфиг:

vi etc/apache2/envvars
User newacc
Group newacc

Выставляем права доступа для файлов дабы избежать постороннего вмешательства:

chown -R 750 /etc/apache2/bin /etc/apache2/conf
chmod 511 /usr/sbin/apache2
chmod 750 /var/log/apache2/
chmod 750 /etc/apache2/conf/
chmod 640 /etc/apache2/conf/*
chgrp -R <newacc> /etc/apache2/conf

Повышение уровня защиты Apache

Открываем файл apache2.conf (можно сделать следующей командой):

vi /etc/apache2/apache2.conf

И добавляем следующие строки для запрета доступ к системным папкам через директиву allow, deny:

<Directory />
 Options None
 Order deny,allow
 Deny from all
</Directory>

Рекомендуется поддерживать версии программного обеспечения в актуальном состоянии - это касается не только CMS сайта, но и модули и оболочку сервера. Поэтому не ленитесь проверять наличие обновлений и устанавливать последние версии. И не забывайте про резервные копии, если что пойдёт не так. Также не стоит держать лишние расширения, неиспользуемое лучше удалять или отключать. Просмотреть установленные модули Apache можно командой SSH:

apache2 -l

А выключить ненужный модуль апача:

a2dismod <module>

Выключаем отображение информации об версии и сервере в заголовках. За это у нас будут отвечать следующие строки в файле конфигурации:

ServerTokens Prod
ServerSignature Off
<IfModule mod_headers.c>
  Header unset Server  
  Header unset X-Powered-By  
</IfModule>

Не будет лишним избавиться от выполнения опасных скриптов, в следующем коде мы отключаем исполнение CGI, запрещаем SSI (Server-Side Includes) и листинг директорий. Данный участок кода необходимо вставить в конфиг либо можно в главный apache2.conf:

<Directory /var/www/protect/site>
  Options -Indexes -Includes -ExecCGI
  Order allow,deny
  Allow from all
</Directory>

Устраняем уязвимость перехвата сессий

Многие хостинги по умолчанию используют один путь для хранения сессий /tmp для всех сайтов. На самом деле это достаточно небезопасно. В качестве простого примера представим такую ситуацию, мы сохраним авторизацию в сессию для пользователя с ид 1 для первого сайта. Но так как у нас одинаковый путь хранилища, то на втором сайте мы можем спокойно быть авторизованными с ид 1. А представьте, если это ещё будет пользователь с администраторскими правами. Конечно, здесь намного больше нюансов, чем в этом упрощенном примере. Однако это открывает возможность к различным манипуляциям сессий чужих сайтов. Именно поэтому стоит разделять пути для сессий, мало того, что это небезопасно, это может привести и к другим проблемам.

Для php.ini редактируем директиву session.save_path:

session.save_path = "/path/to/tmp"

В PHP для этого можно использовать следующий код:

ini_set('session.save_path', '/path/to/tmp')

Если шаред хостинг, то можно прописать в .htaccess следующую строку:

php_value session.save_path /path/to/tmp

Не забываем перезагружать апач для применения правок!

Предотвращаем кражу cookies и упрочняем заголовки

Сюда же можем добавить защиту от XSS атак:

<IfModule mod_headers.c>
 Header set X-XSS-Protection "1; mode=block"
</IfModule>

Для предотвращения одной из разновидности межсайтового скриптинга CROSS-SITE TRACING (XST) следует включенное по умолчанию значенение trace:

TraceEnable off

Полезным будет добавить запрет сниффинга контента - таким образом можно защититься от атак подмены MIME типов файлов. По аналогии добавляем следующую строку:

<IfModule mod_headers.c>
 Header set X-Content-Type-Options nosniff
</IfModule>

Если Вы когда-нибудь проверяли вебсайт сканером уязвимостей от Acunetix, то довольно часто встречается слабая угроза под кодовым именем Clickjacking Attack (или угон клика). Если на сайте не планируется использование ифреймов (iframe) вообще, то можно запретить их следующей конструкцией:

<IfModule mod_headers.c>
 Header always append X-FRAME-OPTIONS DENY 
</IfModule>

Однако этот вариант слишком категоричен: те же визуальные редакторы не смогут работать. Поэтому лучше будет разрешить только для внутренних вставок:

<IfModule mod_headers.c>
 Header always append X-Frame-Options SAMEORIGIN
</IfModule>

На крайний случай при необходимости разрешить доступ с определенных ресурсов советую использовать следующий синтаксис:

X-Frame-Options: ALLOW-FROM sitefrom.name

Современные браузеры поддерживают Content Security Policy - технологию защиты от атак XSS, кликджекинга, подмены данных и других уязвимостей, реализованных уже в самом браузере, и с надеждой с включением в будущем в консорциум WC3. Некоторые тесты безопасности, в частности от Mozilla Firefox достаточно критично относится к отсутствию таких заголовков. На практике хватает пока проблем: это и поддержка браузерами, и не всегда корректная работоспособность (косячит почему-то именно мозилла, что самое забавное), так и противоречивость директив. Если взять самый простой пример и установить только подгрузку с собственного сайта, это будет выглядеть так:

Header set Content-Security-Policy "default-src 'self';"

Но наверняка процентов на 90 Вы столкнетесь с ошибками в консоли и неработоспособностью сайта. Это могут быть ошибки встроенных (inline) скриптов и стилей:

Refused to execute inline script because it violates the following Content Security Policy directive: "default-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-/hNPcBGfN6GyFfPAeUUJxtXBmTv2161TeZeHAaxBT44='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.

для которых придется дописывать отдельные правила типо

Header set Content-Security-Policy "script-src 'unsafe-inline'  *;"
Header set Content-Security-Policy "style-src 'unsafe-inline' *;"

Так и подгрузка с других доменов вызовет ворох ошибок:

Refused to load the font 'https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFW50bbck.woff2' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'font-src' was not explicitly set, so 'default-src' is used as a fallback.

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

<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src https:; script-src 'unsafe-eval' 'unsafe-inline' https:; style-src 'unsafe-inline' https:; img-src https: data:; font-src https: data:; report-uri /csp-report"
</IfModule>

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

Если объединить все заголовки вместе, то суммарно можно добавлять следующий код:

ServerTokens Prod
ServerSignature Off
TraceEnable off
<IfModule mod_headers.c>
Header unset Server
Header unset X-Powered-By
Header set X-XSS-Protection "1; mode=block"
Header always append X-Frame-Options SAMEORIGIN
Header set X-Content-Type-Options nosniff
Header set Content-Security-Policy "default-src https:; script-src 'unsafe-eval' 'unsafe-inline' https:; style-src 'unsafe-inline' https:; img-src https: data:; font-src https: data:; report-uri /csp-report"
</IfModule>

Повысить устойчивость к ддос-атакам

Для снижения риска Denial of service attack - атак от переполнения ресурсов ограничим размер HTTP запросов:

<Directory "/path/to/www/">
 LimitRequestBody 512000
</Directory>

Не будет лишним уменьшить время ожидания сервера, по умолчанию значение составляет 300 секунд:

Timeout 45

В стандартной конфигурации Apache поддерживается большой список методов передачи HTTP: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, на практике обычно нужны только GET, HEAD, POST. Поэтому оставим только их, данный код необходимо вставлять между тегами <Location /> ... </Location>

<LimitExcept GET POST HEAD>
 deny from all
</LimitExcept>

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

service apache2 reload

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

Комментарии   
0 # Д***а 13.12.2018 18:45
Добрый день!
Для битрикс, настройки актуальны?
Многое наверно уже прописано, но есть то, что может вызвать конфликт?
Ответить | Ответить с цитатой | Цитировать
0 # Protect Your Site 14.12.2018 09:17
Да, для битрикса тоже актуальны, только обязательно стоит защитить админку от постороннего вторжения. Это несложно, можно взять материал https://protectyoursite.ru/полезные-материалы/защищаем-админку-joomla-от-посторонних-посетителей и делать это для папки /bitrix/admin/
Ответить | Ответить с цитатой | Цитировать
0 # Д***а 16.12.2018 22:12
спасибо огромное, хотела бы столько же знать, как и вы ))
Ответить | Ответить с цитатой | Цитировать
0 # Пётр 27.04.2020 15:42
По поводу: Предотвращаем кражу cookies и упрочняем заголовки. А в какой файл нужно вписать в wordpress*е Header set X-XSS-Protectio n "1; mode=block" и т.д. ???
Ответить | Ответить с цитатой | Цитировать
0 # Protect Your Site 20.02.2021 08:16
В корневой htaccess файл, если есть доступ, то в файлы конфига апача
Ответить | Ответить с цитатой | Цитировать
Добавить комментарий