In Anbetracht der vielen nützlichen Antworten hoffe ich, einen Beitrag zu diesem Thema leisten zu können.
SQL-Injection ist ein Angriff, der durch Benutzereingaben (Eingaben, die von einem Benutzer eingegeben und dann in Abfragen verwendet werden) durchgeführt werden kann. Bei den SQL-Injection-Mustern handelt es sich um eine korrekte Abfragesyntax, die wir als schlechte Abfragen aus schlechten Gründen bezeichnen können. Wir gehen davon aus, dass eine böse Person versuchen könnte, geheime Informationen zu erhalten (unter Umgehung der Zugriffskontrolle), die die drei Grundsätze der Sicherheit (Vertraulichkeit, Integrität und Verfügbarkeit) beeinträchtigen.
Nun, unser Punkt ist es, Sicherheitsbedrohungen wie SQL-Injection-Attacken zu verhindern, die Frage zu stellen (wie ein SQL-Injection-Angriff mit PHP zu verhindern), realistischer sein, Datenfilterung oder Clearing-Eingabedaten ist der Fall, wenn mit Benutzer-Eingabe-Daten innerhalb einer solchen Abfrage, mit PHP oder einer anderen Programmiersprache ist nicht der Fall, oder wie von mehr Menschen empfohlen, um moderne Technologie wie Prepared Statement oder andere Tools, die derzeit Unterstützung SQL-Injection-Prävention zu verwenden, bedenken Sie, dass diese Werkzeuge nicht mehr verfügbar? Wie sichern Sie Ihre Anwendung?
Mein Ansatz gegen SQL-Injektion ist: Löschen von Benutzereingabedaten, bevor sie an die Datenbank gesendet werden (bevor sie in einer Abfrage verwendet werden).
Datenfilterung für (Umwandlung unsicherer Daten in sichere Daten)
Bedenken Sie, dass PDO y MySQLi sind nicht verfügbar. Wie können Sie Ihre Anwendung absichern? Zwingen Sie mich, sie zu verwenden? Was ist mit anderen Sprachen als PHP? Ich ziehe es vor, allgemeine Ideen zu liefern, da sie für einen breiteren Rahmen verwendet werden können, nicht nur für eine bestimmte Sprache.
- SQL-Benutzer (Einschränkung der Benutzerrechte): Die häufigsten SQL-Operationen sind (SELECT, UPDATE, INSERT), warum also einem Benutzer das UPDATE-Recht geben, der es nicht benötigt? Zum Beispiel, Anmelde- und Suchseiten nur SELECT verwenden, warum dann auf diesen Seiten DB-Benutzer mit hohen Rechten verwenden?
REGEL: Erstellen Sie nicht einen Datenbankbenutzer für alle Berechtigungen. Für alle SQL-Operationen können Sie Ihr Schema wie (deluser, selectuser, updateuser) als Benutzernamen zur einfachen Verwendung erstellen.
Ver Grundsatz des geringsten Rechtsanspruchs .
-
Datenfilterung: Bevor eine Abfrage erstellt wird, sollten die Benutzereingaben validiert und gefiltert werden. Für Programmierer ist es wichtig, einige Eigenschaften für jede Benutzereingabevariable zu definieren: Datentyp, Datenmuster und Datenlänge . Ein Feld, das eine Zahl zwischen (x und y) ist, muss exakt nach der Exakt-Regel validiert werden, und für ein Feld, das eine Zeichenkette (Text) ist: Muster ist der Fall, zum Beispiel, ein Benutzername darf nur einige Zeichen enthalten, sagen wir [a-zA-Z0-9_-.]. Die Länge variiert zwischen (x und n), wobei x und n (ganze Zahlen, x <=n). Regel: Die Erstellung exakter Filter und Validierungsregeln ist für mich die beste Vorgehensweise.
-
Verwenden Sie andere Werkzeuge: Hier stimme ich Ihnen auch zu, dass eine vorbereitete Anweisung (parametrisierte Abfrage) und gespeicherte Prozeduren. Der Nachteil dabei ist, dass diese Methoden fortgeschrittene Kenntnisse erfordern, die bei den meisten Benutzern nicht vorhanden sind. Der Grundgedanke dabei ist, zwischen der SQL-Abfrage und den Daten, die darin verwendet werden, zu unterscheiden. Beide Ansätze können auch mit unsicheren Daten verwendet werden, da die vom Benutzer eingegebenen Daten nichts zur ursprünglichen Abfrage hinzufügen, wie z. B. (any oder x=x).
Für weitere Informationen lesen Sie bitte OWASP Spickzettel zur Vermeidung von SQL-Injektionen .
Nun, wenn Sie ein fortgeschrittener Benutzer sind, beginnen Sie mit dieser Verteidigung, wie Sie wollen, aber für Anfänger, wenn sie nicht schnell eine gespeicherte Prozedur zu implementieren und die Anweisung vorbereitet, ist es besser, Eingabedaten so viel sie können zu filtern.
Nehmen wir schließlich an, dass ein Benutzer den folgenden Text sendet, anstatt seinen Benutzernamen einzugeben:
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
Diese Eingaben können frühzeitig ohne vorbereitete Anweisungen und gespeicherte Prozeduren überprüft werden, aber um auf der sicheren Seite zu sein, sollten diese erst nach der Filterung und Validierung der Benutzerdaten verwendet werden.
Der letzte Punkt ist die Erkennung von unerwartetem Verhalten, die mehr Aufwand und Komplexität erfordert; sie ist für normale Webanwendungen nicht zu empfehlen.
Unerwartetes Verhalten in der obigen Benutzereingabe ist SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA und Root. Sobald diese Wörter erkannt werden, können Sie die Eingabe vermeiden.
UPDATE 1:
Ein Benutzer kommentierte, dass dieser Beitrag nutzlos ist, OK! Hier ist was OWASP.ORG bietet :
Primäre Verteidigungsmaßnahmen:
Option 1: Verwendung von vorbereiteten Anweisungen (parametrisierte Abfragen)
Option Nr. 2: Verwendung von gespeicherten Prozeduren
Option Nr. 3: Alle vom Benutzer eingegebenen Daten werden unterdrückt
Zusätzliche Verteidigungsmaßnahmen:
Auch durchsetzen: Least Privilege
Auch durchführen: White List Eingabeüberprüfung
Wie Sie vielleicht wissen, sollte die Behauptung eines Artikels durch ein stichhaltiges Argument untermauert werden, zumindest durch eine Referenz! Andernfalls wird es als Angriff und schlechte Behauptung gewertet!
Update 2:
Aus dem PHP-Handbuch, PHP: Vorbereitete Anweisungen - Manual :
Escaping und SQL-Injektion
Gebundene Variablen werden vom Server automatisch escaped. Der Server fügt ihre escapeten Werte an den entsprechenden Stellen in der Anweisungsvorlage vor der Ausführung ein. Es muss ein Hinweis an den Server ein Hinweis auf den Typ der gebundenen Variablen gegeben werden, um eine entsprechende Konvertierung zu erzeugen. Siehe die Funktion mysqli_stmt_bind_param() für weitere Informationen.
Das automatische Escaping von Werten innerhalb des Servers ist manchmal ein Sicherheitsmerkmal, um SQL-Injection zu verhindern. Das gleiche Grad an Sicherheit kann mit nicht vorbereiteten Anweisungen erreicht werden, wenn Eingabewerte korrekt escaped werden.
Update 3:
Ich habe Testfälle erstellt, um herauszufinden, wie PDO und MySQLi die Abfrage an den MySQL-Server senden, wenn ein Prepared Statement verwendet wird:
PDO:
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
Abfrage-Log:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi:
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
Abfrage-Log:
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
Es ist klar, dass eine vorbereitete Anweisung auch die Daten auslässt, nichts anderes.
Wie auch in der obigen Erklärung erwähnt,
Das automatische Escaping von Werten innerhalb des Servers wird manchmal als Sicherheitsmerkmal angesehen, um SQL-Injection zu verhindern. Das gleiche Maß an Sicherheit kann mit nicht vorbereiteten Anweisungen erreicht werden, wenn Eingabewerte korrekt escaped werden
Dies beweist, dass die Validierung von Daten wie intval()
ist eine gute Idee für ganzzahlige Werte, bevor eine Abfrage gesendet wird. Darüber hinaus ist das Verhindern von bösartigen Benutzerdaten vor dem Senden der Abfrage ein korrekter und gültiger Ansatz .
Weitere Einzelheiten finden Sie in dieser Frage: PDO sendet eine rohe Abfrage an MySQL, während Mysqli eine vorbereitete Abfrage sendet; beide liefern das gleiche Ergebnis
Referenzen:
- Spickzettel für SQL-Injection
- SQL-Einschleusung
- Informationssicherheit
- Sicherheitsprinzipien
- Validierung der Daten