19 смертных грехов, угрожающих безопасности программ
Шрифт:
XSS–атака организована следующим образом:
1) противник находит сайт, в котором есть одна или несколько XSS–ошибок, например в результате эхо–копирования сервером строки запроса;
2) противник подготавливает специальную строку запроса, включающую некоторую HTML–разметку и сценарий, например на языке JavaScript;
3) противник намечает жертву и убеждает ее щелкнуть по ссылке, содержащей злонамеренную строку запроса. Это может быть ссылка на какой–то другой Web–странице или в письме, отформатированном в виде HTML;
4) жертва щелкает по ссылке, и ее браузер отправляет уязвимому серверу GET–запрос, содержащий злонамеренную строку;
5) уязвимый сервер отправляет эту строку назад браузеру жертвы, и браузер
Поскольку сценарий исполняется на компьютере жертвы, он может получить доступ к хранящимся на нем кукам, которые относятся к домену уязвимого сервера. Кроме того, сценарий может манипулировать объектной моделью документа (Document Object Model – DOM) и изменить в ней произвольный элемент, например переадресовать все ссылки на порносайты. Теперь, щелкнув по любой ссылке, жертва окажется в некоей точке киберпространства, куда вовсе не собиралась попадать.
Примечание. XSS–ошибка возможна и тогда, когда выходная информация невидима, вполне достаточно любого копирования входных данных. Например, Web–сервер мог бы передать входные данные в виде аргумента корректному JavaScript–сценарию на странице или использовать их как часть имени графического файла в теге <IMG>.
Опасайтесь таких Web–приложений, как блоги (онлайновые дневники) или страницы обратной связи, поскольку они зачастую принимают от пользователя произвольный HTML–код, а затем выводят его на страницу для всеобщего обозрения. Если приложение написано без учета безопасности, это может стать причиной XSS–атаки.
Рассмотрим примеры.
Греховное ISAPI–расширение или фильтр на C/C++
Ниже приведен фрагмент ISAPI–расширения, которое читает строку запроса, добавляет в начало слово «Hello,» и возвращает результат браузеру. В этом коде есть и другая ошибка с куда более серьезными последствиями, чем XSS–атака. Сможете ли вы ее найти? Взгляните на обращение к функции sprintf. В ней может произойти переполнение буфера (грех 1). Если результирующая строка окажется длиннее 2048 байтов, то буфер szTemp переполнится.DWORD WINAPI HttpExtensionProc (EXTENSION_CONTROL_BLOCK *lpEcb){
char szTemp [2048];
if (*lpEcb->lpszQueryString)
sprintf(szTemp,"Hello, %s", lpEcb->lpszQueryString);
dwSize = strlen(szTemp);
lpEcb->WriteClient(lpEcb->ConnId, szTemp, &dwSize, 0);
}
Греховность ASP
Эти примеры почти не требуют комментариев. Отметим лишь, что <%= (во втором фрагменте) – это то же самое, что Response.Write.
<% Response.Write(Request.QueryString(«Name»)) %>
Или
<img src=\'<%= Request.QueryString(«Name») %>\'>
Греховность форм ASP. NET
В этом примере ASP.NET трактует Web–страницу как форму, из элементов которой можно считывать данные (и записывать тоже), как если бы это была обычная форма Windows. В таком случае найти XSS–ошибку может оказаться не так просто, поскольку запрос и ответ неявно разбираются и формируются ASP.NET во время выполнения.
private void btnSubmit_Click(object sender, System.EventArgs e) {
if (IsValid) {
Application.Lock;
Application[txtName.Text] = txtValue.Text;
Application.UnLock;
lblName.Text = "Hello, " + txtName.Text;
}
}
Греховность JSP
Эти примеры
<% out.println(request.getParameter(«Name»)) %>
Или
<%= request.getParameter («Name») %>
Греховность PHP
Приведенный ниже код читает из строки запроса значение в переменную name, а затем копирует его в ответ:
<?php
$name=$_GET[\'name\'];
if (isset($name)) {
echo "Hello $name";
}
?>
Греховность Perl–модуля CGI.pm
Этот код почти не отличается от примера РНР выше.
#!/usr/bin/perl
use CGI;
use strict;
my $cgi = new CGI;
print CGI::header;
my $name = $cgi->param(\'name\');
print "Hello, $name";
Греховность mod–perl
При использовании mod–perl для вывода HTML–разметки нужно написать чуть больше текста. Но если не считать кода, формирующего заголовки, то это практически то же самое, что приведенные выше примеры на РНР и Perl–CGI.
#!/usr/bin/perl
use Apache::Util;
use Apache::Request;
use strict;
my $apr = Apache::Request->new(Apache->request);
my $name = $apr->param(\'name\');
$apr->content_type(\'text/html\');
$apr->send_http_header;
$apr->print("Hello ");
$apr->print($name);
Где искать ошибку
Любое приложение, обладающее перечисленными ниже признаками, уязвимо для атаки с кросс–сайтовым сценарием:
□ Web–приложение принимает данные из строки запроса, заголовка или формы;
□ приложение не проверяет корректность данных;
□ приложение отправляет принятые данные назад браузеру.
Выявление ошибки на этапе анализа кода
При анализе кода на предмет наличия XSS–ошибок обращайте внимание на места, где используется тот или иной объект запроса, а прочитанные из него данные копируются в объект ответа. Автор этой главы обычно ищет такие конструкции:
Выяснив, где производятся ввод и вывод, проверьте, контролируется ли корректность входных данных. Если нет, возможна XSS–ошибка.
Примечание. Данные могут не копироваться непосредственно из объекта запроса в объект ответа, возможно промежуточное сохранение в базе данных; обращайте внимание и на это тоже.
Хотелось бы отметить еще один важный момент. Многие полагают, что обращение к методу Response.Write и его аналогам – это единственный источник XSS–ошибок. На самом деле обнаружилось, что конструкции Response.Redirect и Response.SetCookie могут приводить к таким же последствиям; это получило название атаки с расщеплением HTTP–ответа. Вывод таков: любое копирование входных данных в выходные без проверки корректности – это ошибка, угрожающая безопасности. В разделе «Другие ресурсы» приведены ссылки на дополнительные материалы, относящиеся к уязвимостям из–за расщепления HTTP–ответа.