Щодо багатьох корисних відповідей, я сподіваюся додати певної цінності цій темі.
SQL-ін'єкція - це атака, яку можна здійснити за допомогою вводу користувача (входи, заповнені користувачем, а потім використані всередині запитів). Шаблони введення SQL - це правильний синтаксис запитів, хоча ми можемо це назвати: погані запити з поганих причин, і ми припускаємо, що може виявитися недобросовісна людина, яка намагається отримати секретну інформацію (минаючи контроль доступу), яка впливає на три принципи безпеки (конфіденційність) , цілісність та доступність).
Тепер наша суть полягає в тому, щоб запобігти загрозам безпеці, таким як атаки на ін'єкцію SQL, запитання (як запобігти атаці ін'єкції SQL за допомогою PHP) бути більш реалістичним: фільтрація даних або очищення вхідних даних є випадком, коли використовується введені користувачем дані всередині такий запит, використовуючи PHP або будь-яку іншу мову програмування, не є випадком, або, як рекомендують більшість людей використовувати сучасні технології, такі як підготовлена заява чи будь-які інші інструменти, що підтримують на даний момент запобігання ін'єкцій SQL, вважають, що ці інструменти вже недоступні? Як убезпечити свою заявку?
Мій підхід проти введення SQL полягає в: очищенні даних, що вводяться користувачем, перед тим, як надсилати їх до бази даних (перед тим, як використовувати їх у будь-якому запиті).
Фільтрація даних для (перетворення небезпечних даних у безпечні дані)
Врахуйте, що PDO та MySQLi недоступні. Як убезпечити свою заявку? Ви змушуєте мене їх використовувати? Що щодо інших мов, окрім PHP? Я вважаю за краще надавати загальні ідеї, оскільки їх можна використовувати для ширших кордонів, а не лише для конкретної мови.
- Користувач SQL (обмеження привілею користувача): найпоширеніші операції SQL - це (SELECT, UPDATE, INSERT), то чому б надавати привілею UPDATE користувачеві, який цього не потребує? Наприклад, для входу в систему та сторінки пошуку використовуються лише SELECT, чому тоді користувачі DB на цих сторінках з високими привілеями?
ПРАВИЛА: не створюйте одного користувача бази даних для всіх привілеїв. Для всіх операцій SQL ви можете створити схему типу (deluser, selectuser, updateuser) як імена користувачів для зручного використання.
Дивіться принцип найменшої пільги .
Фільтрація даних: перед тим, як створити будь-який запит користувача, його слід перевірити та відфільтрувати. Для програмістів важливо визначити деякі властивості для кожної змінної введення користувача:
тип даних, шаблон даних та довжина даних . Поле, яке є числом між (x і y), повинно бути точно підтверджене за допомогою точного правила, а для поля, що є рядком (текстом): шаблон є випадком, наприклад, ім'я користувача повинно містити лише деякі символи, давайте скажіть [a-zA-Z0-9_-.]. Довжина змінюється між (x і n), де x і n (цілі числа, x <= n).
Правило: створення точних фільтрів та правил перевірки - найкраща практика для мене.
Використовуйте інші інструменти: Тут я також погоджуся з вами, що підготовлений оператор (параметризований запит) та збережені процедури. Недоліками в тому, що ці способи вимагають передових навичок, яких не існує для більшості користувачів. Основна ідея тут полягає в тому, щоб розрізняти запит SQL і дані, які використовуються всередині. Обидва підходи можна використовувати навіть із небезпечними даними, оскільки введені тут дані даних нічого не додають до початкового запиту, наприклад (будь-який або x = x).
Для отримання додаткової інформації, будь ласка, прочитайте чит-лист для запобігання ін'єкцій OWASP SQL .
Тепер, якщо ви є досвідченим користувачем, почніть використовувати цю захист так, як вам подобається, але для початківців, якщо вони не можуть швидко реалізувати збережену процедуру та підготовлену заяву, краще відфільтрувати вхідні дані настільки, наскільки вони можуть.
Нарешті, розглянемо, що користувач надсилає цей текст нижче, а не вводить своє ім’я користувача:
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
Цей вхід можна перевірити на ранньому етапі без будь-яких підготовлених операторів та збережених процедур, але бути на захищеній стороні, використовуючи їх, починається після фільтрації та перевірки даних користувачів.
Останній пункт - виявлення несподіваної поведінки, яка вимагає більше зусиль і складності; не рекомендується для звичайних веб-додатків.
Несподівана поведінка у наведеному вище введенні користувача - SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA та root. Після виявлення цих слів ви можете уникнути введення.
ОНОВЛЕННЯ 1:
Користувач прокоментував, що ця публікація марна, гаразд! Ось що надав OWASP.ORG :
Основні засоби захисту:
Варіант №1: Використання підготовлених заяв (параметризовані запити)
Варіант №2: Використання збережених процедур
Варіант №3: Уникнення всього введеного користувачем вводу
Додаткові засоби захисту:
Також виконувати: Найменший привілей
Також виконувати: Білий список Введення перевірки
Як ви знаєте, претензія на статтю повинна підтримуватися вагомим аргументом, принаймні однією посиланням! В іншому випадку це розглядається як напад і погана претензія!
Оновлення 2:
З посібника PHP, PHP: Підготовлені заяви - Посібник :
Утеча та ін'єкція SQL
Обмежені змінні будуть автоматично виведені сервером. Сервер вставляє свої уникнуті значення у відповідних місцях у шаблон заяви перед виконанням. Серверу необхідно надати підказку щодо типу зв'язаної змінної, щоб створити відповідне перетворення. Для отримання додаткової інформації див. Функцію mysqli_stmt_bind_param ().
Автоматичне вимкнення значень на сервері іноді вважається функцією захисту для запобігання введення SQL. Такий же ступінь безпеки може бути досягнутий і з не підготовленими висловлюваннями, якщо введені значення будуть правильними.
Оновлення 3:
Я створив тестові випадки, щоб знати, як PDO та MySQLi надсилають запит на сервер MySQL при використанні підготовленого оператора:
PDO:
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
Журнал запитів:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi:
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
Журнал запитів:
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
Зрозуміло, що підготовлена заява також уникає даних, нічого іншого.
Як також було зазначено у вищезазначеному твердженні,
Автоматичне вимкнення значень на сервері іноді вважається функцією захисту для запобігання введення SQL. Такий же ступінь безпеки може бути досягнутий і з не підготовленими висловлюваннями, якщо введені значення будуть правильними
Таким чином, це доводить, що перевірка даних, така як intval()
хороша ідея для цілих значень, перш ніж надсилати будь-який запит. Крім того, запобігання зловмисним даним користувачів перед надсиланням запиту є правильним та коректним підходом .
Будь ласка, дивіться це питання для більш детальної інформації: PDO надсилає необроблений запит на MySQL, тоді як Mysqli надсилає підготовлений запит, обидва дають однаковий результат
Список літератури:
- SQL Injection Cheat Sheet
- Інжекція SQL
- Інформаційна безпека
- Принципи безпеки
- Перевірка даних