SQL-Injection в Oracle - это фантастика если у нас есть oci_bind_by_name

01.12.2007

Если вы используете правильные приемы, то даже по собственной забывчивости не возможно написать код, который будет иметь уязвимость типа SQL-Injection. А все потому, что оракл велик и могуч и давно о таких вещах подумал, и пока MySQL чешется где-то в девятнадцатом веке, в деревне Вилларибо уже вовсю программируют и не боятся хакеров.

Хотя стоит отметить, что обнаруженная уязвимость такого рода мало что вам дает, если у вас нет исходников. И даже если они есть – не всегда можно сделать что-то ужасное. Тут уж как повезет, но это мое личное мнение, не хакер я :-)

Так вот – вся суть кроется в функции oci_bind_by_name. Примеры ее использования можно найти в документации, кратко я приведу такой ниже:

$conn = oci_connect("AAA", "BBB");
$sqlex = oci_parse($conn, "SELECT * FROM table WHERE id=:id");
oci_bind_by_name($sqlex, ":id", $id, -1);
//.......

Итак. Мы соединились с ораклом и запускаем запрос на обработку, посылая туда вместо строки с числом, содержащимся в переменной $id, некий эквивалент (макроподстановку, плейсхолдер) :ID, о котором потом говорим ораклу, что мол туда надо подставить переменную $ID. Спрашивается, а зачем делать два шага, если мы все давно уже привыкли со времен MySQL писать вот так:

$query = "SELECT * FROM table WHERE id='$id'"

Ну во-первых, по заверениям надежных источников, такого рода запросы будут работать быстрее, потому что однажды разобрав запрос оракл больше не тратит время на его обработку и просто исполняет, всего лишь подставляя на заданные места, вроде :ID переданные далее значения. Сам запрос хранится в скомпилированном виде в памяти оракла. Для часто исполняемых запросов это самой удобное свойство.

И во-вторых (и видимо это самое главное) – это в сто раз безопаснее, чем все время помнить два правила предотвращения SQL-Injection – переменные в кавычках и не забывать про addslashes. Oracle сам, безо всяких подсказок, поймет что нужно будет сделать с данными.

И в третьих, хочу обратить внимание на очень-очень-очень тонкий момент. О котором мало где сказано, но найдя который, я очень долго мучился и не понимал почему у меня ничего не работает. Суть можно будет понять, рассмотрев следующий пример:

//.......
$var = "value1";
oci_bind_by_name($sqlex, ":param1", $var, -1);
$var = "value2";
oci_bind_by_name($sqlex, ":param2", $var, -1);
//.......

Если мы делаем запрос типа :

SELECT * FROM x WHERE param1 = :value1 AND param2 = :value2
То в результате, даже если предположить что там есть строчки с такими параметрами мы не выберем ничего (хотя например, ручная выборка в каком-нибудь клиенте с подстановленными значениями результаты выдает, а вот вариант с вызовом oci_bind_by_name не проходит).

А все кроется вот в одной замечательной строчке из мануала: “Binds the PHP variable $variable to the Oracle placeholder $ph_name”. Т.е. Oracle вместе с PHP привязывают не значение переменной $variable, а ее саму, можно даже сказать, ссылку на эту переменную. И сама подстановка происходит не во время вызова oci_bind_by_name, а непосредственно во время исполнения запроса и в это же время из переменной достается ее значение и вставляется в запрос. Таким образом, для того, что бы пример “заработал” надо переписать его так:

//.......
$var_xxx = "value1";
oci_bind_by_name($sqlex, ":param1", $var_xxx, -1);
$var_zzz = "value2";
oci_bind_by_name($sqlex, ":param2", $var_zzz, -1);
//.......

Т.е. мы просто даем привызываемым переменным разные имена, и они точно не перепутаются, когда oracle во время исполнения запроса будет брать из них данные. Хотя есть один странный момент, который лично я пояснить не могу – если мы делаем такие подстановки внутри какой-либо функции, то выйдя из нее мы не потеряем эти подставленные переменные, хотя область видимости определенно поменялась и их мы уже можем не иметь в принципе. Но PHP как-то сам понимает, что переменные раньше были и подставляет их.

Из-за чего возник такой тонкий момент я думаю понятно – ведь переменные могут использоваться не только для “ввода” значений, но и для “вывода”, и тут, если две подстановки указывают на одну переменную, может произойти казус.


Комментирование этой статьи закрыто

Комментарии [1]

  1. Мар 5, 19:58 , Артём Курапов

    И с MySQL для этого есть php.net/pdo

Комментирование этой статьи закрыто

Кто я


Возраст: 23
Профессия: заяц


Категории


Полезные ссылки


Стишок

Зайчик-зайчик, скок-поскок!
Н-нна тебе дробину в бок!
Не с капустой же мы будем
Жрать на Новый год пирог...

eu-shestakov.livejournal.com