
С момента запуска сканера безопасности в версии security 12.5.0 прошло около полу года. За это время его рекомендации увидело около 12к+ сайтов (суммарно более 50к проверок). Увы, как показывает статистика подавляющее большинство либо игнорирует его рекомендации, либо не знает, что с ними делать. Именно поэтому я решил более детально описать тесты и каким образом трактовать их результаты. Я постараюсь описать лишь наиболее часто встречающиеся угрозы или угрозы, вызывающее наибольшее количество вопросов. Осторожно, ниже обильное количество хардкора.
Локальное сканирование
Как вы знаете из предыдущего поста . Сканер разделен на две части - локальную и внешнюю. Локальная - ответственна за проверки, которые невозможно/нецелесообразно выполнить “снаружи”, например, настройки сайта или исполнение php/python/perl/etc скриптов в директории хранения загружаемых файлов гораздо эффективнее проверять именно изнутри. Все проверки сгруппированы по типу (настройки окружения, настройки php, настройки сайта и т.д.), поэтому предлагаю начать по порядку:)Настройки окружения
- Директория хранения файлов сессий доступна для всех системных пользователей
Вы можете лицезреть сообщение об этой угрозе, когда директория хранения файловых сессий php (, по умолчанию /tmp) доступна для всех (other), например:Если вы не используете хранение сессий в БД и пользуетесь shared-хостингом, то в большинстве случаев ваш “сосед” сможет получить полный доступ к вашему сайту, модифицировав сессионные данные. Это хороший повод задать ему вопрос и потребовать внести правки в конфигурацию, таким образом дабы сессионные файлы каждого пользователя были отделены друг от друга, и на эти директории были установлены корректные файловые права. Пользователям выделенных серверов это менее критично, но все же рекомендовано, причем что у вашего администратора это займет не более 10 минут времени;)$ stat -c 'Perms: %A' /tmp Perms: drwxrwxrwt
- Предположительно в директории хранения сессий находятся сессии других проектов
Подобное сообщение можно встретить, если несколько сайтов используют одну директорию для хранения сессий. Очень часто это можно встретить при использовании выделенных серверов, когда есть N сайтов и все они хранят свои сессии где-нить в /tmp/php_sess. Начиная с версии main 12.5.0 это стало не столь критично, но тем не менее стоит это исправить указав собственную директорию хранения сессий для каждого сайта. Чем это опасно? При такой конфигурации сессии получаются “сквозные”, т.е., допустим, есть сайт A и сайт B:
a) Мы регистрируемся на сайте B, получаем ID пользователя 7;
b) Теперь зайдя на сайт A с ID сессии от сайта B, мы окажемся авторизованными под пользователем с ID 7, но сайта A, улавливаете?
А что если пользователь с ID 7 на сайте A администратор? - PHP/Python/Perl/etc скрипты исполняются в директории хранения загружаемых файлов
Используя API Битрикс, пользователь сайта не может загрузить .php, .py, .psp, .pl и т.д. файлы без наличия необходимых прав. Но к сожалению, как в пользовательском коде, так и в коде разработчиков Маркетплейс все еще встречается “кастомная” загрузка файлов, которая может позволить загрузить файлы с потенциально опасными расширениями. Именно поэтому лучше исключить эту возможность, корректно сконфигурировав ваш веб-сервер. - .htaccess файлы обрабатываются Apache в директории хранения загружаемых файлов
Аналогично предыдущему, только вектор атаки через загрузку файлов направлен на загрузку .htaccess файлов с кастомными конфигами. Например такой:Необходимо найти все текущие правила:<Files ~ "^\.ht"> Order allow,deny Allow from all </Files> AddHandler zend-enabler-script .htaccess <IfModule mod_mime.c> AddType application/x-httpd-php .htaccess </IfModule> #<?php assert($_GET[0]); ?>
Перенести их в конфигурацию виртуального хоста вашего сайта и добавить AllowOverride None для директории загружаемых файлов, например так:$ find ./upload -type f -name '.htaccess' -print -exec cat {} \; ./upload/support/not_image/.htaccess Deny from all ./upload/.htaccess <IfModule mod_mime.c> RemoveHandler php .php3 .php4 .php5 .php6 .phtml .pl .asp .aspx .cgi .dll .exe .ico .shtm .shtml .fcg .fcgi .fpl .asmx .pht .py .psp AddType text/plain php .php3 .php4 .php5 .php6 .phtml .pl .asp .aspx .cgi .dll .exe .ico .shtm .shtml .fcg .fcgi .fpl .asmx .pht .py .psp </IfModule> <IfModule mod_php5.c> php_flag engine off </IfModule><Directory /home/bitrix/www/upload/support/not_image> AllowOverride none Order allow,deny Deny from all </Directory> <Directory /home/bitrix/www/upload> AllowOverride none AddType text/plain php .php3 .php4 .php5 .php6 .phtml .pl .asp .aspx .cgi .dll .exe .ico .shtm .shtml .fcg .fcgi .fpl .asmx .pht .py .psp php_value engine off </Directory>
- Apache Content Negotiation разрешен в директории хранения загружаемых файлов
Суть проблемы заключается в том, что в конфигурации Apache по умолчанию можно встретить такую строку:Это означает, что если в директории загружаемых файлов у вас будет лежать файл с именем test.var.gif и содержимым:AddHandler type-map .var
(вполне валидная картинка по мнению PHP!), то при запросе этого файла нам будет отдано тело с типом text/html, что логично, т.к. обработчики в Apache вызываются до определения типа:GIF89: any Content-language: ru Content-type: text/html; Body:----------ru-- <img src=x onerror=prompt(/XSS/)> ----------ru--
А не как мы ожидали image/gif, что разумеется приводит к возможности XSS нападения:$ http -v http://bus-win.my/upload/test.var.gif GET /upload/test.var.gif HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate, compress Host: bus-win.my User-Agent: HTTPie/0.7.2 HTTP/1.1 200 OK Accept-Ranges: bytes Content-Language: ru Content-Length: 34 Content-Type: text/html Date: Sun, 27 Oct 2013 09:57:40 GMT Server: Apache/2.4.3 (Unix) OpenSSL/1.0.1c PHP/5.4.7 <img src=x onerror=prompt(/XSS/)>

Эта возможность придает гибкости Apache для обработки мультиязычной статики, но безопасности вашего сайта только вредит.
Еще не устали? Тогда продолжаем! По настройкам PHP зачастую не возникает вопросов, кроме двух:
- Разрешено чтение файлов по URL (URL wrappers)
Это разумеется один из тез пунктов, за который на меня зол не один разработчик. Но природа PHP такова, что никогда не знаешь с какой стороны получишь поддых:) И если мы хотим повысить безопасность нашего сайта - allow_url_fopen должен быть Off, дабы оградить разработчика от "сюрпризов" - Cookies доступны из JavaScript
Имеется в виду, что при установке cookie ваш сайт не передает дополнительный флаг httpOnly для HTTP-заголовка Set-Cookie, который указывает на запрет чтения/записи данных Cookie посредством JavaScript, отсюда и название. Увы XSS атаки наиболее распространены, и получить пользовательские cookies это самый простой их вектор (сейчас все чаще XSS нападение используется для CSRF атак). Поэтому необходимо использовать любую возможность для уменьшения рисков. Флаг httpOnly рекомендуется указывать как минимум для ID сессии, для этого достаточно в настройках php указать:Подробнее о httpOnly на OWASP:session.cookie_httponly = On
Подробнее о директиве php:
Так же как и в случае с настройками PHP - проблем обычно не возникает, т.к. исправление обнаруженных угроз достаточно тривиально. По моему мнению требует объяснений лишь одна:
- Ограничен список расширений исполняемых файлов
Т.к. администратор сайта вправе изменять этот список по своему усмотрению, он может устаревать со временем (когда мы решаем добавить какое-либо расширение в список опасных, к примеру, как было с var). Сканер безопасности сообщит вам, если в вашем кастомизированном списке содержаться не все необходимые расширения.
Эти проверки появились только в security 14.0.3. Основная их цель - проверить все ли привилегированные пользователи используют MFA, у всех ли установлен пароль достаточной сложности и т.д. Увы, на текущий момент по политическим соображениям включена только одна:
- У некоторых пользователей административной группы установлен слабый пароль
Сканер безопасности берет список пользователей из административной группы и пытается подобрать пароль к ним методом перебора по словарю. В случае успеха будет выведен список пользователей, которым необходимо установить более сложный пароль. Зачастую слабый пароль у пользователей административной группы оказывается в следствии того, что изначально они небыли администраторами, т.е. административный доступ предоставляется ранее зарегистрированному пользователю, чьи политики безопасности не требовали стойкого пароля.
Внешнее сканирование
Внешнее сканирование, кажется, заслуживает отдельного поста, но я постараюсь вкратце осветить основные моменты.- Доступен листинг директорий
Увы, включенный Directory AutoIndex встречается повсеместно и сулит как минимум неконтролируемым доступом к загруженным пользовательским файлам. Для nginx необходимо убрать директиву autoindex, она выглядит примерно так:Для Apache это Options +Indexes, как-то так будет выглядеть в конфиге:location / { autoindex on; ... }<Directory /home/bitrix/www> Options +Indexes </Directory>
- Открыт доступ к важным сервисам
Всегда помните - все сервисы, необходимые только сайту, не должны “торчать” наружу. Увы, случаи неконтролируемого доступа к критически важным сервисам (например, memcached) - совсем не редкость. Это важный момент, т.к. доступ к memcached, где ваш сайт хранит свой кеш - это по сути полный контроль над ним. Если вы пользуетесь shared-хостингом - это отличный повод для разговора с ним:) Если у вас не кластерная архитектура проекта, то правильнее всего использовать unix-сокет, когда у вас memcached используется для кластера - корректные настройки firewall + SASL. - Инъекция PHP-CGI параметров из строки запроса
Тут все достаточно просто:) Есть уязвимость в php:
Она позволяет как читать файлы вашего сайта ( /some_script.php?-s ), так и в большинстве случаев исполнять произвольный php код в контексте вашего сайта. Рекомендуется незамедлительно обновить версию php, либо не использовать php-cgi вовсе - Неправильно сконфигурирована связка Nginx + php-fpm
Сколько не бейся над этой темой, но в интернете все еще достаточно много ужасных HowTo’шек по настройке связки nginx + php-fpm, в которых ни слова не сказано о том, что php-fpm с конфигами по умолчанию и локейшн в nginx примерно следующего содержания:позволит злоумышленнику интерпретировать любой файл как php скрипт. К примеру, обратившись к аватару пользователя таким образом: /upload/main/f6f/photo.jpg/some.php, злоумышленник выполнит php код содержащийся в аватаре (например в EXIF или конце PNG). Наиболее распространенными вариантами решения является либо указание в php.ini (если это удовлетворяет требованиям вашего проекта):location ~* \.php$ { fastcgi_pass backend; ... }, либо корректно сконфигурировать nginx, учитывая особенности вашего проектаcgi.fix_pathinfo=0
- Открыт доступ к служебным "статус" страницам
Так называемые статус-страницы позволяют злоумышленнику получить дополнительную информацию о вашем сайте, которая им столь нужна. Не стоит их радовать, ограничив доступ к ним (а лучше отключив/закрыв авторизацией, т.к. доверять localhost так же не стоит). Наиболее распространенные:
Apache . Например:
И PHP-FPM Status Page () - Найдены временные файлы
При редактировании файлов на сервере по SSH или при использовании DCVS могут создаваться временные копии текущих файлов, в которых может содержаться важная информация (например, все еще актуальные данные о подключении к БД). Внешнее сканирование отобразит вам список всех таких файлов, которые необходимо удалить и понять причину их появления. Так же, возможно, стоит ограничить доступ к таким файлам на уровне веб-сервера. - Найдены опасные файлы
Так же достаточно часто встречаются сайты на которых остались какие-то файлы после отладки, установки и т.д. Например: bitrixsetup.php, bx_1c_import.php, restore.php, log.txt и т.д. Внешнее сканирование сообщит вам список найденных файлов, которые в обязательном порядке (!) необходимо удалить. - Доступны настройки PhpMyAdmin
Еще одна частая проблема - доступны настройки PhpMyAdmin (папочка setup в новых версиях). Увы, они как минимум позволяют прочесть текущую конфигурацию PhpMyAdmin + в них постоянно находятся новые уязвимости. Внешнее сканирование сообщит вам, куда нужно смотреть;) - Публичный доступ к файлам контроля версий
Как ни странно - публичный доступ к служебным каталогам DCVS все еще достаточно актуальное явление. Зачастую это крайне опасно для вашего сайта - необходимо в срочном порядке закрыть доступ к таким каталогам (.git, .hg, .bzr и т.д.) и к файлам игнорирования (.gitignore, .hgignore и т.д.). В идеале необходимо пользоваться экспортом в вашей DCVS. Разумеется, внешнее сканирование сообщит вам куда необходимо смотреть:) - Проверяемый сайт отвечает на хост по умолчанию
Это пожалуй одна из самых распространенных ошибок конфигурации для выделенных серверов. Суть проблемы заключается в том, что сайт отвечает на любой Host в заголовке запроса, в следствие чего, например, если $_SERVER["HTTP_HOST"] попадет в кеш компонента, то получаем классический content spoofing.
Проверить очень легко, запрашиваем наш сайт с правильным хостом:А теперь с произвольным:$ http -v head some.info HEAD / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate, compress Host: some.info User-Agent: HTTPie/0.6.0 HTTP/1.1 200 OK Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Connection: keep-alive Content-Encoding: gzip Content-Type: text/html; charset=windows-1251 Date: Fri, 25 Oct 2013 06:57:31 GMT Expires: Thu, 19 Nov 1981 08:52:00 GMT P3P: policyref="/bitrix/p3p.xml", CP="NON DSP COR CUR ADM DEV PSA PSD OUR UNR BUS UNI COM NAV INT DEM STA" Pragma: no-cache Server: nginx/1.2.6 Set-Cookie: PHPSESSID=vp93uc1j3avoibvfkusn5p6gc5; path=/; HttpOnly X-Frame-Options: SAMEORIGIN X-Powered-CMS: Bitrix Site Manager (a0b80388d20et47833773cf8f6b7c738)
Если мы видим одинаковый контент отданный для правильного и произвольного хоста - у нас неправильно сконфигурирован веб-сервер. Для решения этой угрозы, например, в nginx достаточно добавить сервер по умолчанию с перенаправлением на основной домен, например, такой (domain.com замените на ваш домен):$ http -v head some.info 'Host: batman.inc' HEAD / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate, compress Host: batman.inc User-Agent: HTTPie/0.6.0 HTTP/1.1 200 OK Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Connection: keep-alive Content-Encoding: gzip Content-Type: text/html; charset=windows-1251 Date: Fri, 25 Oct 2013 06:57:35 GMT Expires: Thu, 19 Nov 1981 08:52:00 GMT P3P: policyref="/bitrix/p3p.xml", CP="NON DSP COR CUR ADM DEV PSA PSD OUR UNR BUS UNI COM NAV INT DEM STA" Pragma: no-cache Server: nginx/1.2.6 Set-Cookie: PHPSESSID=55up92i9r2sorg24j78lud9li2; path=/; HttpOnly X-Frame-Options: SAMEORIGIN X-Powered-CMS: Bitrix Site Manager (a0b80388d20et47833773cf8f6b7c738)
Перед этим не забудьте убедится что больше нет явно указанных серверов по умолчанию (с директивой default_server)server { listen 80 default_server; access_log /var/log/nginx/default.host.access.log main; return 301 $scheme://domain.com$request_uri; }
Подробнее в - Найден phpinfo()
Честно говоря, я этого искренне не понимаю, но с завидным постоянством вижу на сайтах файлы x.php, pi.php, phpinfo.php и т.д. с выводом phpinfo(). Не надо так! Внешнее сканирование укажет список таких файлов, которые необходимо удалить и впредь использовать встроенную в Битрикс админскую страницу с выводом phpinfo() - Включен Automatic MIME Type Detection для Internet Explorer
По умолчанию в Internet Explorer включен mime-сниффинг (, ), что никак не идет на пользу безопасности пользователей вашего сайта. В двух словах, если в заголовке ответа Content-Type сказано "text/plain," "application/octet-stream,", он отсутствует либо пуст - IE сам решает какой тип у контента основываясь, на его содержимом. Благо начиная с IE8 этим поведением можно управлять при помощи заголовка X-Content-Type-Options.
Самый простой пример эксплуатации этого - загрузка файла без расширения. Допустим, у нас есть скрипт позволяющий загружать только картинки, но сохраняющий их без расширения...
1. Загружаем через него файл test.gif с содержимым:2. Т.к. это вполне валидная картинка с позиции PHP, она благополучно попадет на сервер, но сохранится без расширения (по условиям примера). Допустим будет доступна по адресу:GIF89 <html> <script> prompt('XSS on ' + document.domain); </script> </html>
3. Для начала проверяем как его обработает IE10 с включенным mime-сниффингом:Т.к. тип отдаваемого контента application/octet-stream (по умолчанию, регулируется директивой default_type), IE включает mime-сниффинг, и мы видим, что наша “картинка” была обработана как html-код:$ http head http://192.168.1.185:8080/upload/test HTTP/1.1 200 OK Accept-Ranges: bytes Connection: keep-alive Content-Length: 80 Content-Type: application/octet-stream Date: Sun, 27 Oct 2013 12:14:45 GMT ETag: "526d026b-50" Last-Modified: Sun, 27 Oct 2013 12:09:15 GMT Server: nginx/1.4.3

4. А теперь с заголовком "X-Content-Type-Options: nosniff".
В nginx это можно сделать через add_header:Проверяем:add_header X-Content-Type-Options nosniff;
И видим, что IE теперь предлагает нам сохранить этот файл:$ http head http://192.168.1.185:8080/upload/test HTTP/1.1 200 OK Accept-Ranges: bytes Connection: keep-alive Content-Length: 80 Content-Type: application/octet-stream Date: Sun, 27 Oct 2013 12:18:21 GMT ETag: "526d026b-50" Last-Modified: Sun, 27 Oct 2013 12:09:15 GMT Server: nginx/1.4.3 X-Content-Type-Options: nosniff

Всем безопасных проектов и если у вас есть какие-либо вопросы - спрашивайте пожалуйста:)



