заменить все кавычки на кавычки с обратной косой чертой - этого достаточно? - PullRequest
5 голосов
/ 03 марта 2011

Я использую replaceAll для замены одинарных кавычек на "\\\\'" по предложению коллеги, но я почти уверен, что этого недостаточно для предотвращения всех SQL-инъекций.

Я немного погуглил и нашелthis: http://wiki.postgresql.org/wiki/8.1.4_et._al._Security_Release_Technical_Info

Это объясняет это для PostgreSQL, но разве замена не работает для всех менеджеров SQL?(Например, MySQL, например?)

Кроме того, я думаю, что я понимаю, как объяснение, которое я связал, работает для одиночной обратной косой черты, но распространяется ли это на мою ситуацию, когда я использую четыре обратной косой черты?

Обратите внимание, что я не очень знаком с базами данных и с тем, как они анализируют ввод, но это мой шанс узнать больше!Любое понимание будет оценено.

Редактировать: Я получил несколько действительно полезных и полезных ответов.Мой следующий вопрос: какой вклад сломает мою реализацию?То есть, если вы дадите мне ввод, а я добавлю все одинарные кавычки четырьмя обратными слешами, какой тип ввода вы дадите мне, чтобы ввести код SQL?Хотя я убежден, что мой подход наивен и ошибочен, возможно, некоторые примеры лучше научат меня, как легко вводить SQL против моего «предотвращения».

Ответы [ 3 ]

2 голосов
/ 03 марта 2011

Нет, потому что как насчет обратной косой черты? например, если вы превратите ' в \', тогда \' станет \\', что является одиночной кавычкой без экранирования и обратной косой чертой в виде буквенного символа. Для mysql существует mysql_real_escape_string(), который должен существовать для каждой платформы, потому что он находится в привязках библиотеки MySQL.

Но есть и другая проблема. И это если у вас нет кавычек вокруг сегмента данных. В PHP это выглядит так: $query="select * from user where id=".$_GET[id];

Эксплуатация PoC для этого очень проста: http://localhost/vuln.php?id=sleep(10)

Даже если вы сделаете mysql_real_escape_string($_GET[id]), он все еще уязвим для sqli, потому что злоумышленнику не нужно разбить кавычек, чтобы выполнить sql. Лучшее решение - параметризованные запросы.

2 голосов
/ 03 марта 2011

Нет.

Этого недостаточно, и это не тот путь.И я могу сказать это, даже не зная ничего о ваших данных, вашем SQL или даже о вашем приложении.Вы никогда не должны включать какие-либо пользовательские данные непосредственно в ваш SQL.Вместо этого вы должны использовать параметризованные операторы .

Кроме того, если вы задаете этот вопрос, вы не должны сначала писать свой собственный SQL вручную.Вместо этого используйте хороший ORM .Спрашивать, будет ли ваше собственное регулярное выражение защищать ваше приложение от SQL-инъекций, все равно, что спрашивать, безопасна ли ваша домашняя подпрограмма выделения памяти, написанная вами на языке ассемблера, от переполнения буфера - на что я бы сказал: если вы спрашиваетеэтот вопрос, то вы должны в первую очередь использовать безопасный для памяти язык.

1 голос
/ 03 марта 2011

Простой случай внедрения SQL работает следующим образом (в псевдокоде):

name = form_params["name"]
year = 2011
sql = "INSERT INTO Students (name, year) " + 
      "VALUES ('" + name + "', " + year + ");"
database_handle.query(sql)

year предоставлен вами, программистом, поэтому он не испорчен и может быть встроен в запрос влюбым подходящим способом;в этом случае - как число без кавычек.

Но name предоставляется пользователем и может быть любым.Приходит Таблицы Бобби и вводит это значение:

name = "Robert'); DROP TABLE Students; -- "

И запрос становится

INSERT INTO Students (name, year) VALUES ('Robert');
DROP TABLE Students; -- ', 2011);

Эта подстановка превратила один ваш запрос в два.

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

Обратите внимание, как данные внезапно стали кодом - типичный признак проблемы безопасности.

Что предлагает предложенная замена, так этоthis:

name = form_params["name"].regex_replace("'", "\\\\'")

Как это работает, сбивает с толку, поэтому мой предыдущий комментарий.Строковый литерал "\\\\'" представляет строку \\'.Функция regex_replace интерпретирует это как строку \'.Затем база данных видит

... VALUES ('Robert\'); DROP TABLE Students; -- ', 2011);

и правильно интерпретирует это как довольно необычное имя.

Среди других проблем этот подход очень хрупок.Если строки, которые вы используете на своем языке, не заменяют \\ на \, если ваша функция подстановки строк не интерпретирует \\ как \ (если это не функция регулярного выражения или вместо нее используется $1\1 для обратных ссылок) вы можете получить четное количество слешей, таких как

... VALUES ('Robert\\'); DROP TABLE Students; -- ', 2011);

и no SQL-инъекция будет предотвращена.

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

  • экранирование с учетом базы данных, которое обеспечивает точное экранирование любых данных, поскольку клиентская библиотека соответствует серверу и знает, какую кодировку символов использует база данных.вы запрашиваете:

    sql = "... '" + database_handle.escape(name) + "' ..."

  • внеполосное представление данных (обычно с подготовленными отчетами), поэтому данные даже не совпадаютстрока как код:

    sql = "... VALUES (:n, :y);"
    database_handle.query(sql, n = name, y = year)

...