
Главной нашей целью при решении данной задачи стало - дать удобный, точный и понятный инструмент для разработчика (да-да, именно для разработчика), который мог бы подсказать узкие места в безопасности его кода. Два основных тезиса были перед глазами на всей стадии разработки:
- Разработчик не пентестер, у него зачастую нет необходимой сноровки, необходимого образа мышления и опыта в данной области, поэтому ему порой достаточно сложно определить критичность потенциального огреха (тем более, если проект достается по «наследству»)
- «Точность обнаружения важнее полноты анализа» - люди склонны уставать и ускорятся, листая «километровые» отчеты в поисках заветной ошибки, а клиенты при виде длинного списка будут считать разработчика не благонадежным (коим он разумеется не является:) )
Этим постом хочу немного приоткрыть завесу и рассказать об этом тесте, найти и опробовать который вы сможете не раньше версии 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 логинов были с логином=паролю, вот тебе и безопасность. от банальных ошибок глупых пользователей не спасают. и это я не говорю о куче других найденных дыр, по понятным причинам оглашать их тут не буду.
Код действительно не хороший, но он же закомментирован...
Тест ругался на следующий кусок кода (не знаю кто и зачем это делал):
<? /*$con = mysql_connect("localhost","user","password"); if (!$con) { die('Could not connect: ' . mysql_error()); } mysql_select_db('prezik_db'); $sql = 'SEL ECT * FROM `b_catalog_currency`'; $result = mysql_query($sql); if (!$result) { echo "Could not successfully run query ($sql) fr om DB: " . mysql_error(); exit; } while ($row = mysql_fetch_assoc($result)) { print_r($row); } mysql_close($con); die('asd');*/ require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php"); $APPLICATION->SetTitle("Интернет-магазин \"Мебель\""); ?> ....