Verhindern gespeicherte Prozeduren die SQL-Injektion?


83

Stimmt es, dass gespeicherte Prozeduren SQL-Injection-Angriffe auf PostgreSQL-Datenbanken verhindern? Ich habe ein wenig nachgeforscht und festgestellt, dass SQL Server, Oracle und MySQL nicht gegen SQL Injection sicher sind, auch wenn wir nur gespeicherte Prozeduren verwenden. Dieses Problem existiert jedoch nicht in PostgreSQL.

Verhindert die Implementierung der gespeicherten Prozedur im PostgreSQL-Kern SQL-Injection-Angriffe oder handelt es sich um etwas anderes? Oder ist PostgreSQL auch für SQL-Injection anfällig, selbst wenn wir nur gespeicherte Prozeduren verwenden? Wenn ja, zeigen Sie mir bitte ein Beispiel (z. B. Buch, Website, Papier usw.).


4
Seltsamerweise sind die Hauptantworten hier meistens OT, die sich mit SQL Server befassen, während sich die Frage um Postgres dreht . Hier ist eine Antwort für Postgres: dba.stackexchange.com/questions/49699/… . Es gibt ein paar andere, versuchen Sie eine Suche: dba.stackexchange.com/…
Erwin Brandstetter

@ErwinBrandstetter Die ursprüngliche Frage wurde (vom OP) nicht mit postgres markiert und erwähnt - und erwähnt - mehrere andere DBMS. Ich denke, das ist der Grund für die verschiedenen Antworten, die sich auf andere DBMS konzentrieren. Ich schlage vor, Sie fügen eine weitere hinzu, die sich auf Postgres konzentriert.
Ypercubeᵀᴹ

@ ypercubeᵀᴹ: Ich werde hier eine Antwort hinzufügen, wenn ich Zeit finde. In der Zwischenzeit habe ich dba.stackexchange.com/questions/49699/… klarer und umfassender aktualisiert .
Erwin Brandstetter

Antworten:


71

Nein, gespeicherte Prozeduren verhindern die SQL-Injektion nicht. Hier ist ein aktuelles Beispiel (von einer Inhouse-App, die von jemandem erstellt wurde, an dem ich arbeite) einer gespeicherten Prozedur, die leider SQL-Injection zulässt:

Dieser SQL Server Code:

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO

ungefähr äquivalent zu postgres:

CREATE or replace FUNCTION public.sp_colunmName2 (
    columnName  varchar(30),
    type varchar(30), 
    searchText  varchar(30) ) RETURNS SETOF stations LANGUAGE plpgsql            
AS
$$
DECLARE SQLStatement VARCHAR(4000);
BEGIN
    SQLStatement = 'select * from Stations where ' 
            || columnName || ' ' || type || ' ' || ''''|| searchText || '''';
    RETURN QUERY EXECUTE  SQLStatement;
END
$$;

Die Idee des Entwicklers war es, ein vielseitiges Suchverfahren zu erstellen. Das Ergebnis ist jedoch, dass die WHERE-Klausel alles enthalten kann, was der Benutzer möchte, und so den Besuch von kleinen Bobby Tables ermöglicht .

Ob Sie SQL-Anweisungen oder gespeicherte Prozeduren verwenden, spielt keine Rolle. Entscheidend ist, ob Ihr SQL-Code Parameter oder verkettete Zeichenfolgen verwendet. Parameter verhindern SQL-Injection; Verkettete Zeichenfolgen ermöglichen die SQL-Injektion.


46

SQL-Injection-Angriffe sind Angriffe, bei denen nicht vertrauenswürdige Eingaben direkt an Abfragen angehängt werden, sodass der Benutzer beliebigen Code effektiv ausführen kann, wie in diesem kanonischen XKCD-Comic dargestellt.

So bekommen wir die Situation:

userInput = getFromHTML # "Robert ') Drop table students; -"

Query = "Wählen Sie * von Schülern mit studentName =" + userInput aus

Gespeicherte Prozeduren sind im Allgemeinen eine gute Abwehr gegen SQL-Injection-Angriffe, da die eingehenden Parameter niemals analysiert werden.

In einer gespeicherten Prozedur sehen in den meisten DBs (und Programmen, die vorkompilierten Abfragen zählen als gespeicherte Prozeduren) wie folgt aus:

 

Stored Procdure Foo erstellen (
Wählen Sie * von Schülern mit studentName =: 1
);

Wenn das Programm dann Zugriff wünscht, ruft es foo(userInput)das Ergebnis auf und ruft es glücklich ab.

Eine gespeicherte Prozedur ist keine magische Verteidigung gegen SQL-Injection, da Benutzer durchaus in der Lage sind, fehlerhafte gespeicherte Prozeduren zu schreiben . Vorkompilierte Abfragen, seien sie in der Datenbank oder im Programm gespeichert, sind jedoch viel schwieriger zu öffnen, wenn Sie verstehen, wie SQL-Injection funktioniert.

Sie können mehr über SQL-Injection lesen:


29

Ja, bis zu einem gewissen Grad.
Gespeicherte Prozeduren allein verhindern SQL Injection nicht.

Lassen Sie mich zuerst über SQL Injection von OWASP zitieren

Ein SQL-Injection-Angriff besteht aus dem Einfügen oder "Injizieren" einer SQL-Abfrage über die Eingabedaten vom Client in die Anwendung. Ein erfolgreicher SQL-Injection-Exploit kann vertrauliche Daten aus der Datenbank lesen, Datenbankdaten ändern (Einfügen / Aktualisieren / Löschen), Verwaltungsvorgänge in der Datenbank ausführen (z. B. das DBMS herunterfahren) und den Inhalt einer bestimmten Datei in der DBMS-Datei wiederherstellen System und in einigen Fällen Befehle an das Betriebssystem ausgeben. SQL-Injection-Attacken sind eine Art von Injection-Attacke, bei der SQL-Befehle in Datenebeneneingaben eingefügt werden, um die Ausführung vordefinierter SQL-Befehle zu bewirken.

Sie müssen Benutzereingaben bereinigen und SQL-Anweisungen nicht verketten, auch wenn Sie gespeicherte Prozeduren verwenden.

Jeff Attwood erklärte die Konsequenzen der Verkettung von SQL in " Gib mir parametrisiertes SQL oder gib mir den Tod "

Das Folgende ist der interessante Cartoon, der mir in den Sinn kommt, wenn ich SQL Injection höre. Alt-Text Ich glaube, Sie haben den Punkt verstanden :-)

Schauen Sie sich das SQL Injection Prevention Cheat Sheet an , die Methoden zur Vorbeugung werden genau erklärt ...


12

Die Verkettung von Zeichenfolgen ist die Ursache für SQL Injection. Dies wird durch Parametrierung vermieden.

Gespeicherte Prozeduren fügen eine zusätzliche Sicherheitsebene hinzu, indem sie beim Verketten ungültige Syntax erzwingen. Sie sind jedoch nicht "sicherer", wenn Sie beispielsweise dynamisches SQL verwenden.

Der obige Code wird also durch die Verkettung dieser Zeichenfolgen verursacht

  • exec sp_GetUser '
  • x' AND 1=(SELECT COUNT(*) FROM Client); --
  • ' , '
  • monkey
  • '

Dies führt zum Glück zu einer ungültigen Syntax

Parametrisierung würde es geben

exec sp_GetUser 'x'' AND 1=(SELECT COUNT(*) FROM Client); --' , 'monkey'

Das heisst

  • @UserName = x' AND 1=(SELECT COUNT(*) FROM Client); --
  • @Password = monkey

Im obigen Code erhalten Sie keine Zeilen, da ich davon ausgehe, dass Sie keinen Benutzer haben x' AND 1=(SELECT COUNT(*) FROM Client); --

Wenn der gespeicherte Prozess so aussah (mithilfe von verkettetem dynamischem SQL ), lässt Ihr parametrisierter gespeicherter Prozessaufruf weiterhin SQL Injection zu

...
SET @sql = 'SELECT userName from users where userName = ''' + 
               @UserName + 
               ''' and userPass = ''' +
               @Password +
               ''''
EXEC (@sql)
....

Wie gezeigt, ist die Verkettung von Zeichenfolgen der Hauptfeind für die SQL-Injektion

Gespeicherte Prozeduren fügen Kapselung, Transaktionsbehandlung, reduzierte Berechtigungen usw. hinzu, können jedoch weiterhin für die SQL-Injektion missbraucht werden.

Weitere Informationen zur Parametrisierung finden Sie unter Stapelüberlauf


10

„SQL - Injection - Angriffe passieren , wenn eine Benutzereingabe ist falsch codiert. In der Regel die Benutzereingabe einig Daten der Benutzer mit ihrer Abfrage, dh Werte in dem sendet $_GET, $_POST, $_COOKIE, $_REQUEST, oder $_SERVERArrays. Allerdings Benutzereingabe kann auch kommen aus einer Vielzahl von anderen Quellen wie Sockets, entfernte Websites, Dateien usw. Daher sollten Sie wirklich alles außer Konstanten (wie 'foobar') als Benutzereingabe behandeln . "

Ich habe mich in letzter Zeit eingehend mit diesem Thema befasst und möchte mit anderen sehr interessantes Material teilen, um diesen Beitrag für alle vollständiger und lehrreicher zu machen.



Von YouTube


Aus Wikipedia


Aus OWASP


Aus dem PHP-Handbuch


Von Microsoft und Oracle


Paketüberfluss


SQL-Injektionsscanner


2

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


Vergessen Sie nicht zu erwähnen quote_ident()- aber im Allgemeinen besteht die einfachste Möglichkeit, injektionssicheres dynamisches SQL zu schreiben, darin, format()die Platzhalter %Ifür Bezeichner und %Lfür Literale zu verwenden und zu verwenden . Auf diese Weise ist die SQL viel lesbarer als die entsprechende Version mit ||und quote_....()Funktionen
a_horse_with_no_name
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.