Procedury przechowywane nie magicznie zapobiegają iniekcji SQL, ale znacznie ułatwiają zapobieganie. Wszystko co musisz zrobić, to coś takiego (przykład 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]
Otóż to! Problem pojawia się tylko podczas tworzenia zapytania poprzez konkatenację ciągów (tj. Dynamiczny SQL), a nawet w takich przypadkach możesz być w stanie powiązać! (Zależy od bazy danych.)
Jak uniknąć wstrzykiwania SQL w zapytaniu dynamicznym:
Krok 1) Zadaj sobie pytanie, czy naprawdę potrzebujesz dynamicznego zapytania. Jeśli sklejasz ciągi znaków, aby ustawić dane wejściowe, prawdopodobnie robisz to źle. (Istnieją wyjątki od tej reguły - jeden wyjątek dotyczy raportowania zapytań w niektórych bazach danych, możesz mieć problemy z wydajnością, jeśli nie zmusisz go do kompilacji nowego zapytania przy każdym wykonaniu. Ale zbadaj ten problem, zanim w niego wejdziesz. )
Krok 2) Zbadaj właściwy sposób ustawienia zmiennej dla określonego RDBMS. Na przykład Oracle pozwala wykonać następujące czynności (cytowanie z ich dokumentów):
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!
Tutaj nadal nie łączysz danych wejściowych. Jesteś bezpiecznie wiążący! Brawo!
Jeśli twoja baza danych nie obsługuje czegoś takiego jak powyższe (mam nadzieję, że żadna z nich nie jest jeszcze taka zła, ale nie byłbym zaskoczony) - lub jeśli nadal naprawdę musisz połączyć swoje dane wejściowe (jak w przypadku „czasami” zgłaszania zapytań jako Wskazałem powyżej), musisz użyć właściwej funkcji ucieczki. Nie pisz tego sam. Na przykład postgres udostępnia funkcję quote_literal (). Więc biegniesz:
sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);
W ten sposób, jeśli in_name jest czymś przebiegłym, np. „[Snip] lub 1 = 1” (część „lub 1 = 1” oznacza zaznaczenie wszystkich wierszy, pozwalając użytkownikowi zobaczyć pensje, których nie powinien!), To quote_literal zapisuje tyłek przez utworzenie wynikowego ciągu:
SELECT salary FROM employees WHERE name = '[snip] or 1=1'
Nie zostaną znalezione żadne wyniki (chyba że masz pracowników o naprawdę dziwnych nazwiskach).
To jest sedno tego! Teraz pozwólcie, że zostawię wam link do klasycznego postu guru Oracle, Toma Kyte'a na temat SQL Injection, aby doprowadzić do sedna sprawy: Linky