Комментарии 24
способов предотвращения SQL-инъекций два:
• не использовать динамические запросы к базе;
• не использовать пользовательские данные.
Есть еще один — использовать хранимые процедуры и отделить данные от логики
Без динамических запросов иногда бывает довольно сложно обойтись. С процедурами тоже не всё гладко, но есть еще один способ – это использование Query Builder-ов. Идею я недавно описал в этой статье на Хабре (так же есть пример реализации для .Net)
Те программисты, которые собирают динамические запросы из непроверенных данных в (условно) PHP-коде, точно так же собирают динамические запросы из непроверенных данных в хранимых процедурах.
Хранимые процедуры сами по себе ни от чего не защищают. Вообще эта мантра ничем не лучше пресловутого "Escaping All User Supplied Input", поскольку должна сопровождаться длинным пояснительным текстом, что защищают только тогда, когда параметры процедуры подставляются в запрос в виде переменных, а не участвуют в ручной сборке запроса. Т.е.
INSERT INTO t (a,b,c,d) VALUES (@a, @b, @c, @d);
безопасно, а если там что-то вроде
SET @sql=CONCAT('SELECT * FROM t WHERE f=\'',@a,'\'');
То разумеется никакая процедура не поможет.
Отделение данных от логики — уже ближе, только называется подготовленными выражениями или параметризованными запросами обычно.
:str
называется плейсхолдером или параметром и используется в подготовленном выражении (prepared statement), о котором говорится выше. :str
здесь замещает актуальные данные в запросе и таким образом $_GET['name']
не может повлиять на запрос и вызвать ошибку или инъекцию. Это безопасно и как раз является рекомендуемым способом работы с динамическим SQL.
Только код в запросе какой-то очень уж замороченный. Я бы добавил проценты в РНР и сделал
$bindings = [
'str' => "%{$_GET['name']}%";
];
$query = 'SELECT id, name FROM animals WHERE name like lower(:str)';
так, мне кажется, получается читабельнее. Хотя дело вкуса.
Как я уже писал в другом комментарии, Bind variables работает только для данных. Если нужно сделать order by :column
, то такой запрос выдаст ошибку.
И в этом случае надо применять Option 3: Whitelist Input Validation. У Лары как раз с этим была проблема до недавнего времени — данные защищались, а имена полей вообще никак не проверялись, и пропускали инъекцию.
Статьи подобного содержания видел ещё в 2007 году. Не очень понимаю что автор хочет нового рассказать?
способов предотвращения SQL-инъекций два:
• не использовать динамические запросы к базе;
• не использовать пользовательские данные.
Учите матчасть:
Primary Defenses:
Option 1: Use of Prepared Statements (with Parameterized Queries)
Option 2: Use of Stored Procedures
Option 3: Whitelist Input Validation
Option 4: Escaping All User Supplied Input
Additional Defenses:
Also: Enforcing Least Privilege
Also: Performing Whitelist Input Validation as a Secondary Defense
cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
Вот примеры с PHP: www.php.net/manual/ru/security.database.sql-injection.php
— Но если я сегда запираю дверь на ключ, мне все еще нужно забивать ее гвоздями?
— Не ко всякой двери можно замок приделать.
П.3 нужен если работаем не с данными, а с другими частями запроса, например именами полей.
Остальное в этом списке — чушь собачья, особенно п.4, который сам по себе адъ и позор.
To do injection on Cookie you'll need to click on Header label under GET and POST, it'll be underlined and will display that the injection will be run on Header parameters instead of on GET parameters.
" where id=".intval($_GET['number'])
Самый надежный — фильтровать подозрительные строки еще до того, как они попадут в программу. Это можно делать через WAF web application firewall.
Вот еще одна жертва некачественных статей.
"фильтрация" — это не "самый надёжный способ" а просто адова ересь.
Скажи, ты смог бы свой комментарий здесь оставить, если бы "подозрительные строки" в нем были "отфильтрованы"?
Не говоря уже о том что все фильтры — это по определению черные списки, который никогда не гарантируют безопасность, в отличие от белых.
Не говоря уже о том, что есть инъекции второго порядка
Не говоря о том, что точек входа в программу может быть несколько, и все не зафильтруешь.
SQL-инъекции' union select null,null,null --