0
$sql = 'INSERT INTO `sell`.`themes` (`name`, `preview`, `them`, `price`, `create_at`) VALUES (?, ?, ?, ?, NOW())';
$pdo->prepare($sql)
->execute(array($n['name'], $n['preview'], $n['them'], $n['price']));

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

вот скрин из PMA

скрин

  • 2
    Да, нормально, любые данные в БД кладутся как есть. Было бы плохо, если бы вы положили в БД одно, а она потом вернула вам другое – Mike Aug 22 '17 at 07:59
  • @Mike но насколько я понимаю, таким образом можно провести sql inj атаку – user254893 Aug 22 '17 at 08:11
  • @user254893 нельзя. Сейчас я попробую расписать подробно в ответе – andreymal Aug 22 '17 at 08:12
  • @user254893 Нет, SQL атака была бы если бы вместо ? подставили переменную, кавычка сломала бы запрос. А так кавычка как есть сядет в базу, вы точно так же как есть ее прочитаете. На запрос она никак повлиять не может. И кстати если бы вставляли в БД insert ... ('abc\'') т.е. нормально экранированные данные, то в БД бы значение лежало уже без обратной косой. Экранирование же нужно только на этапе компиляции запроса – Mike Aug 22 '17 at 08:21

2 Answers2

3

Вы, видимо, не до конца понимаете, где и зачем нужно экранирование. Давайте разберём весь путь ваших данных от INSERT до вывода на экран в вашем браузере.

Отправка SQL-запроса

База данных должна уметь хранить произвольные данные, в том числе любые символы в любых строках. Но вот незадача — кавычки это спецсимволы в SQL. Если мы, возьмём, например, такую строку:

хорошие данные"), ("я хакер азаза"); --

и попытаемся её добавить через примерно такой запрос:

INSERT INTO mytable ("сюда подставляем строку")

то получится такой SQL-код:

INSERT INTO mytable ("хорошие данные"), ("я хакер азаза"); -- ")

Да, это SQL-инъекция. Вместо одной исходной строки база данных запишет две: хорошие данные и я хакер азаза.

Но ведь запрещать кавычки для предотвращения инъекции это неудобно, мы же наверно хотим сохранить строку хорошие данные"), ("я хакер азаза"); -- в базе данных как есть, чтобы пользователь её мог потом прочитать в точно таком же виде мог прочитать? (В конце концов, если бы все запрещали кавычки, я бы не смог написать этот ответ, в нём же много кавычек :)

К счастью, есть экранирование. Кавычки экранируются заменой " на \" (если в строке изначально есть обратный слэш \, то он тоже экранируется заменой на \\). С экранированием получается такой код:

INSERT INTO mytable ("хорошие данные\"), (\"я хакер азаза\"); -- ")

Так вот, PDO делает экранирование автоматически. Если всё сконфигурировано правильно, SQL-инъекция в коде из вашего вопроса невозможна.

Но это не значит, что экранированные кавычки так и сохранятся! Когда база данных парсит этот SQL-запрос, она, как бы корректнее выразиться, в общем автоматически убирает экранирование со строки. Экранирование нужно только для того, чтобы при разборе SQL-запроса база данных не попутала кавычку внутри строки с кавычкой, означающей окончание строки. После разбора база данных уже ничто ни с чем не попутает и всё экранирование можно безопасно убрать, и строка хорошие данные"), ("я хакер азаза"); -- в итоге сохраняется как есть. Здесь всё безопасно, база данных сама позаботится об этом, вам важно лишь экранировать строку перед подстановкой в SQL-запрос (повторюсь, PDO это делает автоматически, код из вопроса безопасен).

PMA забирает строку из базы данных

Перед отображением содержимого вам PMA делает запрос вроде SELECT * FROM mytable и в ответе получает нашу строку со всеми кавычками, сохранёнными в предыдущем шаге (как устроен протокол передачи строки от базы данных в PMA, я не знаю, но там тоже всё безопасно). Потом PMA должен запихнуть эту строку в HTML-код с красивой табличкой и передать его вам, чтобы браузер эту табличку нарисовал.

Но здесь уже становится возможно XSS. Это когда в строке оказывается что-то вроде <script>alert("XSS!")</script> — если запихнуть это в HTML-код как есть, то браузер это воспримет не как текст, а как HTML-тег, обозначающий скрипт, и выполнит любой код внутри него (а этот любой код сможет, например, передать злоумышленнику ваши логин и пароль от текущего сайта). Поэтому перед выводом PMA тоже всё экранирует с помощью HTML-сущностей.

Из строки

хорошие данные"), ("я хакер азаза"); --

получается

хорошие данные&quot;), (&quot;я хакер азаза&quot;); --

а из строки

<script>alert("XSS!")</script>

получается

&lt;script&gt;alert(&quot;XSS!&quot;)&lt;/script&gt;

Если в исходной строке есть символ &, то он экранируется как &amp;. Если там уже есть &amp;, то с экранированием получается &amp;amp; ну и так далее :)

Чтение HTML-кода браузером

Сервер (PMA) отвечает браузеру HTML-кодом, в котором все спецсимволы в ваших строках вот так вот экранированы. Когда браузер читает это всё, он теперь воспринимает это не как теги, а как обычный текст, и опасности появления XSS нет. Но перед выводом на экран тоже убирает всё экранирование — заменяет &quot; обратно на " и так далее.

Поэтому вы в итоге видите не fhfh\" OR 1 и не fhfh\&quot; OR 1, а fhfh" OR 1 — ровно такую строку, какую вы изначально и хотели отправить в базу данных.

andreymal
  • 13,178
  • P.S. Если вы откроете исходный HTML-код этой страницы, то увидите, что все спецсимволы в моём ответе экранированы :) https://i.imgur.com/8UNnACT.png (правда, кавычки не экранированы там, где их можно не экранировать, но, например, внутри значений атрибутов их экранировать нужно) – andreymal Aug 22 '17 at 08:43
  • Спасибо за развернутый ответ! – user254893 Aug 22 '17 at 08:43
-2
$sql = "INSERT INTO 'sell'.'themes' ('name', 'preview', 'them', 'price', 'create_at') VALUES (?, ?, ?, ?, NOW())"; 
$pdo->prepare($sql) ->execute(array($n['name'], $n['preview'], $n['them'], $n['price']));

Категорически НЕЛЬЗЯ без ручного екранирования вставлять так кавычки, только так.

$foo = "fuiyg 'ookjgi' lifuo"; - так можно

$foo = 'fjokt "hkooy" ogupy "jkjf" gju'; и так можно

$foo = 'lkgoo 'dgoov' kifg 'fik' jgu'; - так, и $foo = "fynnfr "fgjiy" dhj "fhji" dgj"; - нельзя

Kyberi
  • 45
  • А какое отношение имеет ваш ответ по экранированию кавычек в языке php к вопросу по БД ? У ТС нет в тексте констант с кавычками – Mike Aug 22 '17 at 08:01
  • Вы хотите сказать что значение $sql в вапросе правильно присвоено??? – Kyberi Aug 22 '17 at 08:03
  • Да, абсолютно правильно. текст SQL в обычных апострофах, имена колонок внутри запроса в обратных апострофах – Mike Aug 22 '17 at 08:07
  • Я виноват, с телефона недосмотрел что кавычки разние, но ето все равно исправит проблему человека. – Kyberi Aug 22 '17 at 08:16
  • Не исправит, потому что никакой проблемы нет. кавычки содержатся у него в тексте внутри вставляемых переменных. в БД они ложатся как есть, что абсолютно правильно. – Mike Aug 22 '17 at 08:19
  • Исправит, так как обратные кавычки никак не обрабатываются а просто выставляются как обычный текст, а в данной ситуации он хотел заполнить таблицу, обратние кавычки не обработались и вставились как есть, если вставит как в моем ответе все пройдет успешно – Kyberi Aug 22 '17 at 08:23
  • Нет, обратные кавычки в БД не вставлялись. Обратные апострофы в тексте MySQL обозначают, что внутри них имена колонок, а не текст. текст в MySQL заключается в обычные апострофы или двойные кавычки. В БД сели не эти кавычки, а содержащиеся внутри переменных $n['name'] – Mike Aug 22 '17 at 08:25
  • Понятно, спасибо – Kyberi Aug 22 '17 at 08:28
  • @Mike, я правильно понимаю что вставляемые переменный можно не контролировать в плане кавычек? даже в такой ситуации - $n['name'] = $_POST['name']; – user254893 Aug 22 '17 at 08:29
  • @user254893 я правильно понимаю что вставляемые переменный можно не контролировать в плане кавычек? - по сути да, но надо чуть-чуть знать некоторые нюансы и всё будет хорошо. смотри (читай) вопрос Защищают ли подготовленные выражения/переменные полностью от SQL инъекций? – Алексей Шиманский Aug 22 '17 at 08:30
  • @user254893 Да, используя плейсхолдеры ? и передавая значения при execute никакой контроль не требуется – Mike Aug 22 '17 at 08:30
  • @Mike; @АлексейШиманский Спасибо – user254893 Aug 22 '17 at 08:45