
SQL-Injektion
Es ist an der Zeit, SQL-Injection zu analysieren. Lange Zeit war sie unangefochtener Spitzenreiter der OWASP-Top-10-Liste, und zwar über Jahre hinweg. Trotz ihres Alters (mehr als 20 Jahre) und obwohl sie leicht vom ersten Platz der Liste zurückgefallen ist, bleibt sie eine unglaublich beliebte und gefährliche Schwachstelle.
Da es sich um eine Sicherheitslücke im Web handelt, ist die SQL-Injection (SQLi) nach wie vor eine der von Angreifern am häufigsten verwendeten Hacking-Techniken, da sie ihnen ermöglicht, eine Datenbank zu manipulieren und wichtige Informationen daraus zu extrahieren. Noch alarmierender ist die Tatsache, dass ein Angreifer zum Administrator des Datenbankservers werden und wirklich verheerende Dinge anrichten kann, wie z. B. Datenbanken zerstören, Transaktionen manipulieren, Daten offenlegen und das System für weitere Probleme anfällig machen.
Werfen wir einen kurzen Blick darauf, wie das geschieht.
SQL (oder strukturierte Abfragesprache) ist die Sprache, die zur Kommunikation mit relationalen Datenbanken verwendet wird. Es handelt sich um die Abfragesprache, die von Entwicklern, Datenbankadministratoren und Anwendungen verwendet wird, um die riesigen Datenmengen zu verwalten, die täglich generiert werden.
Innerhalb einer Anwendung gibt es zwei Kontexte: einen für die Daten und einen für den Code. Der Code-Kontext gibt den Computern vor, was sie ausführen sollen, und trennt ihn von den zu verarbeitenden Daten. Eine SQL-Injection tritt auf, wenn ein Angreifer Daten eingibt, die vom SQL-Interpreter fälschlicherweise als Code behandelt werden, wodurch er wertvolle Informationen aus der Anwendung sammeln kann.
Auswirkungen eines SQL-Injection-Angriffs
Eine SQL-Injection kann für jede Webanwendung äußerst schädlich sein und war die bevorzugte Technik hinter vielen hochkarätigen Sicherheitsverletzungen, da sie Angreifern unbefugten Zugriff auf kritische Daten verschafft. Sie können eine Vielzahl von Informationen einsehen, von Benutzernamen und Passwörtern bis hin zu Kreditkartendaten und persönlichen Identifikationsnummern.
Nachdem sie Zugriff auf diese Daten erhalten haben, können die Angreifer sich die Konten aneignen, Passwörter zurücksetzen, umfangreiche Online-Einkäufe tätigen oder andere (weitaus schlimmere) Betrugsdelikte begehen.
Aber das Beunruhigendste an SQLi ist vielleicht, dass ein Angreifer, wenn er nicht entdeckt wird, über lange Zeiträume hinweg eine Hintertür im System offen halten kann. Wie Sie sich vorstellen können, würde dies dazu führen, dass es während der gesamten Zeit, in der die Hintertür offen bleibt, immer wieder zu Datenlecks kommt. Das ist wirklich beängstigend.
Sehen wir uns einige Beispiele an, um besser zu verstehen, wie dies in der Praxis aussieht.
Beispiele für SQLi
SQLi umfasst verschiedene Schwachstellentechniken, die unterschiedliche Situationen angehen können. Im Folgenden sind nur einige der häufigsten Beispiele für SQLi aufgeführt:
Arten von SQLi
Gut, sehen wir uns nun die drei verschiedenen Arten von SQLi an.
SQLi im Band
Dies ist eine der häufigsten, einfachsten und effizientesten Arten von SQL-Injection-Angriffen. Bei dieser Art von Angriff wird derselbe Kommunikationskanal verwendet, um den Angriff durchzuführen und das Ergebnis oder die Ergebnisse abzurufen.
Los siguientes son los dos tipos de ataques SQLi en banda:
- SQLi basierend auf der Vereinigung – Der Angriff basierend auf der Vereinigung nutzt den Vereinigungsoperator, um zwei oder mehr SQL-Abfragen, wie beispielsweise SELECT-Anweisungen, zu kombinieren, um die gewünschten Informationen zu erhalten und eine HTTP-GET-Antwort zu generieren.
- SQLi basierend auf Fehlern – Der Angreifer nutzt Fehlermeldungen der Datenbank, um deren Struktur zu verstehen. Bei diesem Angriff kann der Angreifer gefälschte Anfragen senden oder Aktionen ausführen, damit der Server Fehlermeldungen anzeigt und er Informationen aus der Datenbank erhalten kann. Daher ist es wichtig, dass Entwickler vermeiden, Fehler oder Protokollmeldungen in der Live-Umgebung zu senden. Stattdessen sollten diese mit eingeschränktem Zugriff gespeichert werden.
SQLi-Inferenz
Inferenzielle oder blinde SQLi-Angriffe sind komplizierter und ihre Ausnutzung kann länger dauern. Darüber hinaus erhält der Angreifer nicht sofort die Ergebnisse des Angriffs, was ihn zu einem blinden Angriff macht.
Der Angreifer sendet die Nutzdaten mittels HTTP-Anfragen an den Datenbankserver, um die Datenbank des Benutzers neu zu strukturieren, und beobachtet anschließend die Antwort und das Verhalten der Anwendung, um festzustellen, ob der Angriff erfolgreich war oder nicht.
Dies sind zwei Arten von SQLi-Inferenzangriffen:
- Blind SQLi basierend auf Booleschen Werten – Bei diesem Angriff wird eine Abfrage an die Datenbank gesendet, um das Boolesche Ergebnis (wahr oder falsch) zu erhalten, und der Angreifer beobachtet die HTTP-Antwort, um das Boolesche Ergebnis vorherzusagen.
- Zeitbasiertes Blind SQLi – Bei diesem Angriff sendet der Angreifer eine Abfrage an die Datenbank, die einige Sekunden warten soll, bevor sie die Antwort sendet, und bewertet die Ergebnisse der Abfrage anhand der Antwortzeit der HTTP-Anfrage.
SQLi außerhalb des Bandes
Dies ist eine seltenere Art von SQLi-Angriff, die von den aktivierten Funktionen des Datenbankservers abhängt. Sie tritt in Fällen auf, in denen der Angreifer die anderen Angriffstypen nicht wirklich nutzen kann.
Zum Beispiel, wenn er nicht denselben Kommunikationskanal für den Inbandangriff verwenden kann oder wenn die HTTP-Antwort nicht klar genug ist, um die Ergebnisse der Abfrage berechnen zu können.
Außerdem ist sie nicht so verbreitet, da sie in hohem Maße von der Fähigkeit des Datenbankservers abhängt, HTTP- oder DNS-Anfragen auszuführen, um die erforderlichen Daten an den Angreifer zu senden.
Wie man sich gegen SQLi verteidigt
Glücklicherweise hat die Tatsache, dass SQL-Injection so alt und so verbreitet ist, auch eine positive Seite: Es gibt Möglichkeiten, dies zu verhindern. Der Einsatz solcher Präventionstechniken ist nicht nur eine gute Programmierpraxis, sondern stärkt auch die Sicherheit einer Organisation gegenüber SQLi.
Es gibt verschiedene Möglichkeiten, Datenbankserver vor solchen Angriffen zu schützen, beispielsweise durch Eingabevalidierung, den Einsatz einer Webanwendungsfirewall (WAF), den Schutz von Datenbanken, den Einsatz von Geräten oder Sicherheitssystemen von Drittanbietern und das Schreiben von fehlerfreien SQL-Abfragen.
Sehen wir uns ein Beispiel dafür an, wie SQL-Injections in Python mithilfe einer der oben genannten Sicherheitsmaßnahmen verhindert werden können.
Beispiel für Python
In diesem Beispiel verwendet der Angreifer eine blinde SQL-Injection auf Basis von Booleschen Werten, um wichtige Informationen aus dem System zu erhalten.
Python: anfällig
Nehmen wir an, es gibt eine Tabelle namens „sample_data” in der Datenbank. Diese Tabelle speichert die Benutzernamen und Passwörter der Benutzer der Anwendung.
Lassen Sie nun den Benutzer mit den folgenden Befehlen nach einem Wert in dieser Datenbanktabelle suchen:
importar mysql.connector
db = mysql.connector.connect
Práctica #Bad. ¡Evita esto! Esto es solo para aprender.
(host="localhost», user="newuser», passwd="pass», db="sample»)
cur = db.cursor ()
name = raw_input ('Ingresar nombre: ')
cur.execute («SELECT * FROM sample_data WHERE Name = '%s';»% name) para la fila de cur.fetchall (): print (row)
db.cerrar ()
SQL-Injektion
Wenn der Benutzer hier einen Namen in die Suche eingibt, zum Beispiel Alicia, gibt es kein Problem mit dem Ergebnis.
Wenn der Benutzer jedoch etwas wie „Alicia“ eingibt, hat „DROP TABLE sample_data“ erhebliche Auswirkungen auf die Datenbank.
Python: Remediation
Der SQL-Befehl muss durch den folgenden ersetzt werden, um den Angriff zu verhindern:
cur.execute („SELECCIONE * DE sample_data DONDE Nombre = %s;“, (nombre,))
Jetzt behandelt das System die Eingabe des Benutzers als Zeichenfolge, selbst wenn der Benutzer versucht, SQL-Abfragen einzufügen, und behandelt die Eingabe des Benutzers ausschließlich als Wert des Namens.
Diese einfache Änderung kann böswillige Aktivitäten bei zukünftigen Abfragen verhindern und das System vor Angriffen durch Benutzer schützen.
Beispiel für Java
Für dieses Beispiel verwenden wir auch eine Datenbanktabelle namens „sample_data“, in der die Benutzerdaten der Anwendung gespeichert sind.
Eine einfache Anmeldeseite nimmt einen Benutzernamen und ein Passwort entgegen, und die Java-Datei, bei der es sich um ein Servlet (LogInServlet) handelt, validiert diese in der Datenbank, um den Anmeldevorgang zu ermöglichen.
Java: Beispiel für eine Sicherheitslücke
Durch die Verwendung der Tabelle „sample_data” aus der Datenbank ermöglicht das System den Benutzern, sich mit ihren Anmeldedaten anzumelden.
Es gibt eine Abfrage in der Datei LogInServlet, um den Anmeldevorgang zu ermöglichen, nämlich:
//Mal ejemplo. No utilice la concatenación de cadenas.
String query = «seleccione * de sample_data donde username='» + username + «'y password ='» + password + «'»;
Conexión conn = nula;
Sentencia stmt = nulo;
prueba {
conn = DriverManager.getConnection («jdbc:mysql: //127.0.0. 1:3306 /user», «raíz», «raíz»);
stmt = conn.createStatement ();
ResultSet rs = stmt.ExecuteQuery (consulta);
si (rs.next ()) {
//Inicio de sesión exitoso si se encuentra una coincidencia
éxito = verdadero;
}
} catch (Excepción e) {
por ejemplo, printStackTrace ();
} finalmente {
prueba {
stmt.close ();
conn.close ();
} catch (Excepción e) {}
}
si (éxito) {
response.sendRedirect (» home.html «);
} otra cosa {
response.sendRedirect (» login.html? error = 1 pulgada);
}
}
A continuación se presenta la consulta para el inicio de sesión del usuario:
Wählen Sie * aus sample_data, wo username='Benutzername' und password='Passwort'
SQL-Injektion
Das System funktioniert einwandfrei, wenn die Eingabe gültig ist. Nehmen wir beispielsweise an, der Benutzername lautet erneut „Alicia“ und das Passwort „geheim“.
Das System gibt die Daten des Benutzers mit diesen Anmeldedaten zurück. Ein Angreifer kann jedoch die Anfrage des Benutzers mithilfe von Postman und cURL manipulieren, um SQL-Injection durchzuführen.
Beispielsweise kann der Hacker einen fiktiven Benutzernamen (Alicia) und das Passwort „or“ = „1“ senden.
In diesem Fall stimmen der Benutzername und das Passwort nicht überein, aber die Bedingung „1“ = „1“ ist immer wahr, sodass die Anmeldung erfolgreich durchgeführt wird.
Java: Prävention
Zur Vorbeugung müssen wir den Code „LogInvalidation” ändern und PreparedStatement anstelle von Statement für die Ausführung von Abfragen verwenden. Diese Änderung verhindert die Verkettung von Benutzername und Passwort in der Abfrage und behandelt diese als Konfigurationsdaten, um SQL-Injection zu verhindern.
Nachfolgend finden Sie den geänderten Code für LogInvalidation:
Consulta de cadena = «seleccione * de sample_data donde username=? y contraseña =?» ;
Conexión conn = nula;
PreparedStatement stmt = nulo;
prueba {
conn = DriverManager.getConnection («jdbc:mysql: //127.0.0. 1:3306 /user», «raíz», «raíz»);
stmt = conn.prepareStatement (consulta);
stmt.setString (1, nombre de usuario);
stmt.setString (2, contraseña);
ResultSet rs = stmt.executeQuery ();
si (rs.next ()) {
éxito = verdadero;
}
rs.close ();
} catch (Excepción e) {
por ejemplo, printStackTrace ();
} finalmente {
prueba {
stmt.close ();
conn.close ();
} catch (Excepción e) {
}
}
In diesem Fall kümmern sich PreparedStatement, die Setter und die zugrunde liegende JDBC-API um die Benutzereingabe und verhindern SQL-Injection.

Beispiele
Jetzt sehen wir uns noch einige Beispiele in verschiedenen Sprachen an, um besser zu verstehen, wie das in der Praxis aussieht.
C# - Unsicher
Dieses Beispiel ist aufgrund der Verwendung von `FromRawSql` unsicher. Diese Methode verknüpft die Parameter nicht und versucht auch nicht, sie zu escapen. Daher sollte diese Methode unter allen Umständen vermieden werden.
var blogs = contexto.Publicaciones
.fromRawSQL («SELECCIONA * DE LAS PUBLICACIONES EN LAS QUE ESTADO = {0} Y autor = {1}», estado, autor)
.toList ();
C# – Sicher
Dieses Beispiel ist dank `FromSqlInterpolated` sicher, das die interpolierten Werte übernimmt und parametrisiert.
Obwohl dies im Allgemeinen sicher ist, besteht die Gefahr, dass es sehr ähnlich wie „FromRawSql“ ist, was nicht sicher ist.
var blogs = contexto.Publicaciones
.fromSqlInterpolated ($"SELECT * FROM POSTS WHERE state = {state} AND author = {author}»)
.toList ();
Java – Secure: Hibernate – Abfrage mit Namen + Native Abfrage
Hibernate bietet zwei Methoden zum sicheren Erstellen von Abfragen: „Native Abfrage“ und „Benannte Abfrage“. Beide ermöglichen die Angabe von Speicherorten für Parameter.
@NamedNativeQuery (
nombre = «find_post_by_state_and_author»,
consulta =
«SELECCIONAR *" +
«DE Post» +
«WHERE state =:state» +
«Y autor =:autor»,
Clase de resultado = Post.class)
java
Listar <Post>publicaciones = session.createNativeQuery (
«SELECCIONAR *" +
«DE Post» +
«WHERE state =:state» +
«Y autor =:autor»)
.addEntity (Post.class)
.setParameter («estado», estado)
.setParameter («autor», autor)
.lista ();
Java: sicher: jplq
Wenn Sie ein Attribut „Query“ in einer jplq-Repository-Schnittstelle notieren, können diese mehrere Formen annehmen und werden parametrisiert.
@Query («SELECCIONA p DE LA PUBLICACIÓN p DONDE u.state =? 1 y u.author =? 2 pulgadas)
Publicar Buscar publicación por estado y autor (estado de cadena, autor int);
@Query („SELECCIONA p DE LA PUBLICACIÓN P DONDE u.state =:state y u.author =:author”)
User findPostByStateAndAuthor (@Param („state”) String state, @Param („author”) int author);
Javascript – Sicher: pg
Bei Verwendung der Bibliothek `pg` ermöglicht die Methode `query` die Parametrisierung, indem sie über ihren zweiten Parameter Parameterwerte bereitstellt.
const {posts} = await db.query ('SELECCIONA * DE LA PUBLICACIÓN DONDE estado = $1 Y autor = $2', [estado, autor])
Javascript – Sicher: Sequelize
Die Bibliothek „sequelize“ bietet eine Möglichkeit, eine Abfrage über ihr zweites Argument zu parametrisieren, das die Konfiguration der Abfrage übernimmt. Dazu gehört eine Liste von Werten, die entweder über den Namen oder den Index als Parameter mit der Abfrage verknüpft werden können.