Збережені процедури не магічно запобігають ін'єкції SQL, але вони набагато полегшують його запобігання. Все, що вам потрібно зробити, - це щось на зразок наступного (приклад Postgres):
CREATE OR REPLACE FUNCTION my_func (
IN in_user_id INT
)
[snip]
SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]
Це воно! Проблема виникає лише при формуванні запиту за допомогою конкатенації рядків (тобто динамічного SQL), і навіть у тих випадках ви можете бути в змозі зв’язати! (Залежить від бази даних.)
Як уникнути ін'єкції SQL у своєму динамічному запиті:
Крок 1) Запитайте себе, чи дійсно вам потрібен динамічний запит. Якщо ви склеюєте рядки разом, щоб встановити вхід, то ви, ймовірно, робите це неправильно. (З цього правила є винятки - один виняток стосується звітування про запити в деяких базах даних, у вас можуть виникнути проблеми з ефективністю, якщо ви не змушуєте його складати новий запит при кожному виконанні. Але вивчіть цю проблему, перш ніж перейти до цього. )
Крок 2) Дослідження правильного способу встановлення змінної для конкретного RDBMS. Наприклад, Oracle дозволяє зробити наступне (цитуючи їх документи):
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!
Тут ви все ще не об'єднуєте вхід. Ви надійно зобов’язуєтесь! Ура!
Якщо ваша база даних не підтримує щось подібне до вищезгаданого (сподіваємось, жоден з них все ще не такий поганий, але я не здивуюсь) - або якщо ви все-таки дійсно повинні об'єднати свої дані (як, наприклад, у випадку "інколи" звітності про запити як Я натякав на вище), тоді ви повинні використовувати належну функцію втечі. Не пишіть це самі. Наприклад, postgres забезпечує функцію quo_literal (). Отже, ви біжите:
sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);
Таким чином, якщо in_name є чимось хитрим, як-от "[snip] або 1 = 1" (частина "або 1 = 1" означає виділити всі рядки, що дозволяє користувачеві бачити зарплату, якої він не повинен!), А потім quo_literal зберігає ваш зад Створення отриманого рядка:
SELECT salary FROM employees WHERE name = '[snip] or 1=1'
Результатів не буде знайдено (якщо тільки у вас є співробітники з дійсно дивними іменами.)
У цьому суть! Тепер дозвольте залишити вас посиланням на класичну публікацію гуру Oracle Тома Кейта на тему SQL Injection, щоб перенести справу додому: Linky