Главной нашей целью при решении данной задачи стало - дать удобный, точный и понятный инструмент для разработчика (да-да, именно для разработчика), который мог бы подсказать узкие места в безопасности его кода. Два основных тезиса были перед глазами на всей стадии разработки:
- Разработчик не пентестер, у него зачастую нет необходимой сноровки, необходимого образа мышления и опыта в данной области, поэтому ему порой достаточно сложно определить критичность потенциального огреха (тем более, если проект достается по «наследству»)
- «Точность обнаружения важнее полноты анализа» - люди склонны уставать и ускорятся, листая «километровые» отчеты в поисках заветной ошибки, а клиенты при виде длинного списка будут считать разработчика не благонадежным (коим он разумеется не является:) )
Этим постом хочу немного приоткрыть завесу и рассказать об этом тесте, найти и опробовать который вы сможете не раньше версии 11.5.2 Главного модуля. Для того что бы найти его, необходимо будет проделать следующий путь: Администрирование -> Настройки -> Инструменты -> "Монитор качества" и выбрать наш новый тест “Предприняты меры по обеспечению безопасности проекта на уровне веб-разработки” в разделе “Безопасность”.
Запустив его, вы сможете просмотреть подробный отчет о его работе (при условии наличия найденных ним проблем):
От слов к делу или «лучше один раз увидеть...»
Как работает на практике тест и какой отчет он составляет, я покажу на примере уязвимого к Cross-site scripting компонента «mega_comp».
И так, сам компонент:
Файл: /bitrix/components/my_comps/mega_comp/component.php <?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); $my_sec_var=htmlspecialchars($_REQUEST['sec_var']); $my_unsec_var=$_REQUEST['unsec_var']; $arResult['sec_var']=$my_sec_var; $arResult['unsec_var']=$my_unsec_var; $this->IncludeComponentTemplate(); ?> |
Модификация результатов перед выводом:
Файл: /bitrix/templates/minimal_black/components/my_comps/mega_comp/.default/result_modifier.php <?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); $arResult['~sec_var']=htmlspecialcharsback($arResult['sec_var']); ?> |
Сам шаблон компонента:
Файл: /bitrix/templates/minimal_black/components/my_comps/mega_comp/.default/template.php <?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die(); //безопасные данные echo $arResult['sec_var']; //данные которые стали не безопасны в процессе работы скрипта echo $arResult['~sec_var']; //изначально небезопасные данные, выводятся с условием if (isset($arResult['unsec_var'])) echo $arResult['unsec_var']; ?> |
Файл: /test.php <?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); $APPLICATION->IncludeComponent('my_comps:mega_comp','',Array()); require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");?> |
Как видно из скриншота он нашел две XSSки, которые выводятся в шаблоне как $arResult['~sec_var'] и $arResult['unsec_var'], определив при этом что переменная $arResult['sec_var'] полностью безопасна. Показал полный путь следования переменных от начала инициализации пользовательскими данными до попадания их в вывод (указав слева номера строк, а справа файл содержащий эту конструкцию). Не забыв при этом указать, что для вывода переменной $arResult['unsec_var'] должно быть соблюдено определенное условие.
На текущий момент он нацелен искать ошибки, которые могут привести к:
- XSS (Cross-site scripting) нападению
- SQL инъекции
- Выполнению произвольного php кода
- Выполнение произвольных системных комманд
- Инъекции в заголовок ответа (HTTP Response Splitting)
- File Inclusion
Статический taint-анализ (или taint checking) решает задачу поиска уязвимых мест в лоб, и в основе лежит всего лишь несколько правил:
- Данные, полученные скриптом из http-запросов, считаются небезопасными по определению
- Небезопасные данные в ходе работы скрипта могут стать безопасными (приведение типов, фильтрация, кодирование, нормализация и т.д.)
- Безопасные данные, содержащие пользовательские данные, могут стать небезопасными (декодирование, htmlspecialcharsback и т.д.)
- Небезопасные данные не должны попадать в контролируемые функции (вывод, системные функции, запрос к СУБД и т.д.)
- За небезопасные данные принимаются только данные, полученные из http-запроса, т.е. не учитываются случаи, когда они могут прийти, например, из СУБД или хранится в файле, что разумеется снижает полноту анализа.
- При статическом анализе достаточно сложно рулить ветвлением логики и, как следствие, в отчет попадают опасные участки кода, которые на практике не станут уязвимостями.
//Скрипт add_posts.php $text = addslashes(htmlspecialchars($_POST['text'])); $name = addslashes(htmlspecialchars($_POST['name'])); mysql_query("INSERT INTO posts (name, text) VALUES ('".$name."','".$text."')"); //Скрипт view_posts.php $result = mysql_query("SELECT name, text FROM posts"); while ($row = mysql_fetch_assoc($result)) { echo 'Имя:'.$row['name'].'<br />Сообщение:'.$row['text'].'<br />'; |
Второе ограничение, увы можно решить лишь частично. Приведу пример:
if (in_array($_GET['my_var'],explode(" ",COption::GetOptionString('my_module','vars')))) echo $_GET['my_var']; |
if(!check_bitrix_sessid()) { //чёт там происходит die(); } if (!in_array($_GET['var'],$some_vars)) exit('Не допустимый аргумент:'.$_GET['var']); |
Заключение
Идей у нас в запасе еще достаточно много, поэтому тест будет активно развиваться и совершенствоваться. Главное стоит понять - статические анализаторы реально ищут не уязвимости, а потенциальные ошибки, которые могут стать (а могут и не стать) уязвимостями, решить уязвимо ли это место в состоянии только разработчик. Так же не стоит забывать о том, что любые средства по анализу кода никогда не заменят Code Review, «думанье головой» и периодический аудит безопасности.
Если у вас есть какие либо вопросы, спрашивайте пожалуйста.
Фото:
Рекомендую также анализировать конструкции вида
правда такая тактика адекватна не для крупных проектов а для мелких (каких большенство) .
я сам лично занимаюсь тестированиями на проникновение серваков и вот список того, что стоило бы добавить в тест:
- нахождение конфига апача и если он найден то попытка открыть его на чтение (логично так как есть на других сайтах практически всегда папка аплоадов с правами 777 куда можно шел залить, а зная пути к сайтам очень легко сделать чекер)
- автоматический брут по файлу /etc/passwd с попыткой перебора на логин=пароль и реверс (говорит о том что хостер пренебрегает элементарными правилами генерации паролей и отсутствует нормальный валидатор клиентский)
- поиск файлов логов и конфигов (часто, вы даже не представляете на сколько часто, быдло админы пишет в лог фал не только GET но и !!внимание!! POST запросы, думаю не надо объяснять чем это черевато)
- проверка пути сохранения логов (редко, но бывает логи пишут в корень сайта, думаю тоже не надо объяснять чем это грозит)
- проверка версии ядра системы uname -a (ядро должно быть обновлено если не до последней, то хотябы до версии полугодовой давности, по опыту есть хостеры, и много, которые вообще держат ядро 2-3 летней давности)
все эти пункты взяты из печального опыта.
пример: на днях проводил анализ для клиента его хостинг площадки (от peterhost.ru) запустил свой стандартный тестер.. 6 ftp логинов были с логином=паролю, вот тебе и безопасность. от банальных ошибок глупых пользователей не спасают. и это я не говорю о куче других найденных дыр, по понятным причинам оглашать их тут не буду.
Код действительно не хороший, но он же закомментирован...
Тест ругался на следующий кусок кода (не знаю кто и зачем это делал):