Чтение онлайн

ЖАНРЫ

19 смертных грехов, угрожающих безопасности программ

Виега Джон

Шрифт:

"user id=sa;password=pAs$w0rd;");

sql.Open;

string sqlstring="SELECT ccnum" +

" FROM cust WHERE id=%ID%";

String sqlstring2 = sqlstring.Replace("%ID", id);

SqlCommand cmd = new SqlCommand(sqlstring2,sql);

try {

ccnum = (string)cmd.ExecuteScalar;

} catch (SqlException se) {

Status = sqlstring + " failed\n\r";

foreach (SqlError e in se.Errors) {

Status += e.Message + "\n\r";

}

} catch (SqlException e) {

// Ой!

}

Греховность PHP

Вот та же классическая ошибка, но в программе на языке РНР, часто применяемом для доступа к базам данных.

...

<?php

$db = mysql_connect("localhost","root","$$sshhh...!");

mysql_select_db("Shipping",$db);

$id = $HTTP_GET_VARS["id"];

$qry = "SELECT ccnum FROM cust WHERE id = %$id%";

$result = mysql_query($qry,$db);

if ($result) {

echo mysql_result($result,0,"ccnum");

} else {

echo "No result! " . mysql_error;

}

?>

Греховность Perl/CGI

И

снова тот же дефект, но на этот раз в программе на достопочтенном Perl:

...

#!/usr/bin/perl

use DBI;

use CGI;

print CGI::header;

$cgi = new CGI;

$id = $cgi->param(\'id\');

$dbh = DBI->connect(\'DBI:mysql:Shipping:localhost\',

\'root\',

\'$3cre+\')

or print "Ошибка connect : $DBI::errstr";

$sql = "SELECT ccnum FROM cust WHERE id = " . $id;

$sth = $dbh->prepare($sql)

or print "Ошибка prepare : $DBI::errstr";

$sth->execute

or print "Ошибка execute : $DBI::errstr";

# Вывести данные

while (@row = $sth->fetchrow_array ) {

print "@row<br>";

}

$dbh->disconnect; print "</body></html>";

exit;

Греховность Java

Еще один распространенный язык, Java. Подвержен внедрению SQL по той же схеме.

...

import java.*;

import java.sql.*;

...

public static boolean doQuery(String Id) {

Connection con = null;

try

{

Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");

con = DriverManager.getConnection("jdbc:microsoft:sqlserver: " +

"//localhost:1433", "sa", "$3cre+");

Statement st = con.createStatement;

ResultSet rs = st.executeQuery("SELECT ccnum FROM cust WHERE id=" +

Id);

while (rx.next) {

// Полюбоваться на результаты запроса

}

rs.close;

st.close;

}

catch (SQLException e)

{

// Ой!

return false;

}

catch (ClassNotFoundException e)

{

// Не найден класс

return false;

}

finally

{

try

{

con.close;

} catch(SQLException e) {}

}

return true;

}

Греховность SQL

Подобный код встречается не так часто, но автор пару раз наталкивался на него в промышленных системах. Показанная ниже хранимая процедура просто принимает строку в качестве параметра и исполняет ее!

...

CREATE PROCEDURE dbo.doQuery(@query nchar(128))

AS

exec(@query)

RETURN

А вот следующий код распространен куда шире и не менее опасен:

...

CREATE PROCEDURE dbo.doQuery(@id nchar(128))

AS

DECLARE @query nchar(256)

SELECT @query = \'select ccnum from cust where id = \'\'\' + @id + \'\'\'\'

EXEC @query

RETURN

Здесь

опасная конкатенация строк выполняется внутри процедуры. То есть вы по–прежнему совершаете постыдный грех, даже если процедура вызвана из корректного кода на языке высокого уровня.

Стоит поискать и другие операторы конкатенации, имеющиеся в SQL, а именно «+» и «||», а также функции CONCAT и CONCATENATE.

Во всех этих примерах противник контролирует переменную Id. Важно всегда представлять себе, что именно контролирует атакующий, это поможет понять, есть реальная ошибка или нет. В данном случае противник может задать любое значение переменной Id, участвующей в запросе, и тем самым управлять видом строки запроса. Последствия могут оказаться катастрофическими.

Классическая атака состоит в том, чтобы видоизменить SQL–запрос, добавив лишние части и закомментарив «ненужные». Например, если противник контролирует переменную Id, то может задать в качестве ее значения строку 1 or 2>1 – – , тогда запрос примет такой вид:

...

SELECT ccnum FROM cust WHERE id=1 or 2>1 – –

Условие 2>1 истинно для всех строк таблицы, поэтому запрос возвращает все строки из таблицы cust, другими словами, номера всех кредитных карточек. Можно было бы воспользоваться классической атакой «1 = 1», но сетевые администраторы часто включают поиск такой строки в системы обнаружения вторжений (IDS), поэтому мы применили условие «2>1», которое столь же эффективно, но «проходит под лучом радара».

Оператор комментария – – убирает из поля зрения сервера все последующие символы запроса, которые могла бы добавить программа. В одних базах данных для комментирования применяются символы —, в других – #. Проверьте, что воспринимает в качестве комментария ваша база.

Различных вариантов атак слишком много, чтобы перечислять их здесь, дополнительный материал вы найдете в разделе «Другие ресурсы».

Родственные грехи

Во всех приведенных выше примерах демонстрируются и другие грехи:

□ соединение от имени учетной записи с высоким уровнем доступа;

□ включение пароля в текст программы;

□ сообщение противнику излишне подробной информации в случае ошибки.

Рассмотрим их по порядку. Везде соединение устанавливается от имени административного или высокопривилегированного пользователя, хотя достаточно было бы пользователя, имеющего доступ только к одной базе данных. Это означает, что противник потенциально сможет манипулировать и другой информацией, а то и всем сервером. Короче говоря, соединение с базой данных от имени пользователя с высоким уровнем доступа – скорее всего, ошибка и нарушение принципа наименьших привилегий.

«Зашивание» паролей в код – почти всегда порочная идея. Подробнее см. грех 11 и 12 и предлагаемые там «лекарства».

Наконец, в случае ошибки противник получает слишком много информации. Воспользовавшись ей, он сможет получить представление о структуре запроса и, быть может, даже узнать имена объектов базы. Более подробную информацию и рекомендации см. в грехе 6.

Где искать ошибку

Любое приложение, обладающее перечисленными ниже характеристиками, подвержено риску внедрения SQL:

□ принимает данные от пользователя;

□ не проверяет корректность входных данных;

□ использует введенные пользователем данные для запроса к базе;

□ применяет конкатенацию или замену подстроки для построения SQL–запроса либо пользуется командой SQL exec (или ей подобной).

Поделиться с друзьями: