Gespeicherte Prozeduren verhindern SQL-Injection nicht auf magische Weise, aber sie machen es viel einfacher, dies zu verhindern. Alles, was Sie tun müssen, ist etwas wie das Folgende (Postgres-Beispiel):
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]
Das ist es! Das Problem tritt nur beim Bilden einer Abfrage über Zeichenfolgenverkettung (dh dynamisches SQL) auf, und selbst in diesen Fällen können Sie möglicherweise eine Bindung herstellen! (Kommt auf die Datenbank an.)
So vermeiden Sie SQL-Injection in Ihrer dynamischen Abfrage:
Schritt 1) Fragen Sie sich, ob Sie wirklich eine dynamische Abfrage benötigen. Wenn Sie Strings zusammenhalten, nur um den Eingang zu setzen, dann machen Sie es wahrscheinlich falsch. (Es gibt Ausnahmen zu dieser Regel. Eine Ausnahme betrifft das Melden von Abfragen in einigen Datenbanken. Möglicherweise treten Leistungsprobleme auf, wenn Sie nicht zwingen, bei jeder Ausführung eine neue Abfrage zu kompilieren. Ermitteln Sie dieses Problem jedoch, bevor Sie sich damit befassen.) )
Schritt 2) Ermitteln Sie die richtige Methode zum Festlegen der Variablen für Ihr bestimmtes RDBMS. Zum Beispiel können Sie in Oracle Folgendes tun (aus ihren Dokumenten zitieren):
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!
Hier verketten Sie die Eingabe noch nicht. Sie sind sicher bindend! Hurra!
Wenn Ihre Datenbank so etwas nicht unterstützt (hoffentlich ist keine von ihnen immer noch so schlecht, aber ich würde mich nicht wundern) - oder wenn Sie Ihre Eingaben immer noch wirklich verketten müssen (wie im "manchmal" Fall, wenn Sie Abfragen melden, als Ich habe oben angedeutet), dann müssen Sie eine ordnungsgemäße Escape-Funktion verwenden. Schreib es nicht selbst. Beispielsweise bietet postgres die Funktion quote_literal (). Du würdest also laufen:
sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);
Auf diese Weise, wenn in_name etwas abwegiges wie '[snip] oder 1 = 1' ist (der Teil "oder 1 = 1" bedeutet, dass alle Zeilen ausgewählt werden, sodass der Benutzer die Gehälter sieht, die er nicht sehen sollte!), Speichert quote_literal Ihren Hintern durch Die resultierende Zeichenfolge erstellen:
SELECT salary FROM employees WHERE name = '[snip] or 1=1'
Es werden keine Ergebnisse gefunden (es sei denn, Sie haben Mitarbeiter mit wirklich verrückten Namen.)
Das ist der Kern davon! Lassen Sie mich nun einen Link zu einem klassischen Post von Oracle-Guru Tom Kyte zum Thema SQL-Injection hinterlassen, um den Punkt nach Hause zu bringen: Linky