7

SQL-инъекция, обхватывающая mysql_real_escape_string()

2

Подскажите, возможна ли уязвимость для SQL-инъекции даже с использованием функции mysql_real_escape_string()?

Рассмотрим следующую ситуацию. SQL-код формируется в PHP так:

$login = mysql_real_escape_string(GetFromPost('login'));
$password = mysql_real_escape_string(GetFromPost('password'));

$sql = "SELECT * FROM table WHERE login='$login' AND password='$password'";

Я слышал много раз, что такой код все еще опасен и его можно взломать, даже при использовании функции mysql_real_escape_string(). Но я не могу представить себе никакого возможного способа эксплуатации этой уязвимости.

Классические инъекции, такие как:

aaa' OR 1=1 --

не работают.

Знаете ли вы о каких-либо возможных инъекциях, которые могли бы обойти приведенный выше PHP-код?

2 ответ(ов)

4

Используемый вами код может вызывать опасения по поводу уязвимости SQL-инъекций, несмотря на то, что вы используете mysql_real_escape_string(). Давайте разберемся, почему это так.

Когда вы используете mysql_real_escape_string(), вы, конечно, экранируете специальные символы, чтобы защитить себя от инъекций, но это не сработает, если вы передаете строку, содержащую SQL-команды, как в вашем примере:

$iId = mysql_real_escape_string("1 OR 1=1");    
$sSql = "SELECT * FROM table WHERE id = $iId";

В данном случае, результатом работы mysql_real_escape_string() будет строка, которая не изменит суть SQL-запроса, поскольку часть OR 1=1 всё равно будет интерпретироваться как часть SQL-запроса. Поэтому данная защита не является достаточной.

Ключевой момент заключается в том, что использование одинарных кавычек (' ') вокруг переменных в SQL-запросе может обеспечить защиту от этого. Например, если вы обернете идентификатор в одинарные кавычки:

$iId = mysql_real_escape_string("1 OR 1=1");    
$sSql = "SELECT * FROM table WHERE id = '$iId'";

Таким образом, id будет обрабатываться как строка, и условие OR 1=1 не сработает.

Также вы можете использовать приведение типов для предотвращения инъекций, как в следующем примере:

$iId = (int)"1 OR 1=1";
$sSql = "SELECT * FROM table WHERE id = $iId";

Такой подход является более безопасным, так как преобразование строкового значения, содержащего SQL-код, в целое число (интегер) автоматически удалит все нечисловые символы. В результате в приведённом коде 1 OR 1=1 будет преобразовано в 1, и злоумышленник не сможет провести SQL-инъекцию.

Рекомендуется использовать параметры в подготовленных выражениях (prepared statements), если это возможно, для обеспечения максимальной безопасности при работе с базами данных.

0

На самом деле, ничего нельзя использовать для обхода этого, кроме символа % как подстановочного знака. Это может быть опасно, если вы используете оператор LIKE, так как злоумышленник может ввести просто % в качестве логина, если вы это не отфильтровали, и затем ему останется только перебрать пароль любого из ваших пользователей.

Часто рекомендуют использовать подготовленные запросы, чтобы сделать это на 100% безопасно, так как данные не могут вмешиваться в саму SQL-запрос таким образом.

Однако для таких простых запросов, вероятно, будет более эффективно использовать что-то вроде $login = preg_replace('/[^a-zA-Z0-9_]/', '', $login);, чтобы фильтровать вводимые данные.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь