Наконец, в случае ошибки противник получает слишком много информации. Воспользовавшись ей, он сможет получить представление о структуре запроса и, быть может, даже узнать имена объектов базы. Более подробную информацию и рекомендации см. в грехе 6.
Где искать ошибку
Любое приложение, обладающее перечисленными ниже характеристиками, подвержено риску внедрения SQL:
□ принимает данные от пользователя;
□ не проверяет корректность входных данных;
□ использует введенные пользователем данные для запроса к базе;
□ применяет конкатенацию или замену подстроки для построения SQL–запроса либо пользуется командой SQL exec (или ей подобной).
Выявление ошибки на этапе анализа кода
Во время анализа кода на предмет возможности внедрения SQL прежде всего ищите места, где выполняются запросы к базе данных. Ясно, что программам, не обращающимся к базе данных, эта напасть не угрожает. Мы обычно ищем следующие конструкции:
Выяснив, что в программе есть обращения к базе данных[1], нужно определить, где выполняются запросы и насколько можно доверять данным, участвующим в запросе. Самое простое – найти все места, где выполняются предложения SQL, и посмотреть, производится ли конкатенация или подстановка небезопасных данных, взятых, например, из строки Web–запроса, из Web–формы или аргумента SOAP. Вообще, любых поступающих от пользователя данных!
Тестирование
Надо признать, что реальной альтернативы добросовестному анализу кода на предмет внедрения SQL не существует. Но иногда у вас может не быть доступа к коду, или вы просто не имеет опыта чтения чужих программ. Тогда дополните анализ кода тестированием.
Прежде всего определите все точки входа в приложение, где формируются SQL–запросы. Затем создайте тестовую программу–клиент, которая будет посылать в эти точки частично некорректные данные. Например, если тестируется Web–приложение, которое строит запрос на основе одного или нескольких полей формы, попробуйте вставить в них произвольные ключевые слова языка SQL. Следующий пример на Perl показывает, как это можно сделать.
#!/usr/bin/perl
use strict;
use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use LWP::UserAgent;
srand time;
# Приостановить исполнение, если найдена ошибка
my $pause = 1;
# Тестируемый URL
my $url = 'http://mywebserver.xyzzy123.com/cgi-bin/post.cgi';
# Максимально допустимый размер HTTP-ответа
my $max_response = 1000;
# Допустимые города
my @cities = qw(Auckland Seattle London Portland Manchester Redmond
Brisbane Ndola);
while (1) {
my $city = randomSQL($cities[rand @cities]);
my $zip = randomSQL(10000 + int(rand 89999));
print «Пробую [$city] и [zip]\n»;
my $ua = LWP::UserAgent->new();
my $req = POST $url,
[ City => $city,
ZipCode => $zip,
];
# Послать запрос, получить ответ и поискать в нем признаки ошибки
my $res = $ua->request($req);
$_