In Bezug auf viele nützliche Antworten hoffe ich, diesem Thread einen Mehrwert zu verleihen.
SQL Injection ist ein Angriff, der über Benutzereingaben erfolgen kann (Eingaben, die von einem Benutzer ausgefüllt und dann in Abfragen verwendet werden). Die SQL-Injection-Muster sind die korrekte Abfragesyntax, obwohl wir sie als schlechte Abfragen aus schlechten Gründen bezeichnen können, und wir gehen davon aus, dass es möglicherweise eine schlechte Person gibt, die versucht, geheime Informationen (unter Umgehung der Zugriffskontrolle) abzurufen, die die drei Sicherheitsprinzipien (Vertraulichkeit) beeinflussen , Integrität und Verfügbarkeit).
Jetzt geht es darum, Sicherheitsbedrohungen wie SQL-Injection-Angriffe zu verhindern, die Frage (wie man einen SQL-Injection-Angriff mit PHP verhindert) realistischer zu gestalten, Daten zu filtern oder Eingabedaten zu löschen, wenn Benutzereingabedaten im Inneren verwendet werden Eine solche Abfrage mit PHP oder einer anderen Programmiersprache ist nicht der Fall. Wie von mehr Personen empfohlen, moderne Technologien wie vorbereitete Anweisungen oder andere Tools zu verwenden, die derzeit die SQL-Injection-Prävention unterstützen, sind diese Tools nicht mehr verfügbar? Wie sichern Sie Ihre Bewerbung?
Mein Ansatz gegen SQL-Injection ist: Löschen von Benutzereingabedaten vor dem Senden an die Datenbank (bevor sie in einer Abfrage verwendet werden).
Datenfilterung für (Konvertieren unsicherer Daten in sichere Daten)
Beachten Sie, dass PDO und MySQLi nicht verfügbar sind. Wie können Sie Ihre Bewerbung sichern? Zwingst du mich, sie zu benutzen? Was ist mit anderen Sprachen als PHP? Ich ziehe es vor, allgemeine Ideen zu liefern, da diese für eine breitere Grenze verwendet werden können, nicht nur für eine bestimmte Sprache.
- SQL-Benutzer (Einschränkung der Benutzerberechtigung): Die häufigsten SQL-Vorgänge sind (SELECT, UPDATE, INSERT). Warum sollte die UPDATE-Berechtigung dann einem Benutzer erteilt werden, der sie nicht benötigt? Zum Beispiel, Login und Suchseiten verwenden nur SELECT, dann, warum die Verwendung DB Benutzer auf diesen Seiten mit hohen Privilegien?
REGEL: Erstellen Sie nicht einen Datenbankbenutzer für alle Berechtigungen. Für alle SQL-Vorgänge können Sie Ihr Schema wie (deluser, selectuser, updateuser) als Benutzernamen für eine einfache Verwendung erstellen.
Siehe Prinzip des geringsten Privilegs .
Datenfilterung: Bevor eine Abfragebenutzereingabe erstellt wird, sollte diese 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 anhand der genauen Regel genau validiert werden. Für ein Feld, das eine Zeichenfolge (Text) ist: Muster ist der Fall. Beispielsweise darf ein Benutzername nur einige Zeichen enthalten sagen Sie [a-zA-Z0-9_-.]. Die Länge variiert zwischen (x und n), wobei x und n (ganze Zahlen, x <= n).
Regel: Das Erstellen exakter Filter und Validierungsregeln sind für mich Best Practices.
Verwenden Sie andere Tools: Hier werde ich Ihnen auch zustimmen, dass eine vorbereitete Anweisung (parametrisierte Abfrage) und gespeicherte Prozeduren. Die Nachteile hierbei sind, dass diese Methoden fortgeschrittene Fähigkeiten erfordern, die für die meisten Benutzer nicht vorhanden sind. Die Grundidee besteht darin, zwischen der SQL-Abfrage und den darin verwendeten Daten zu unterscheiden. Beide Ansätze können auch bei unsicheren Daten verwendet werden, da die hier eingegebenen Benutzereingaben der ursprünglichen Abfrage nichts hinzufügen, z. B. (any oder x = x).
Weitere Informationen finden Sie im OWASP SQL Injection Prevention Cheat Sheet .
Wenn Sie ein fortgeschrittener Benutzer sind, können Sie diese Verteidigung nach Belieben verwenden. Für Anfänger ist es jedoch besser, Eingabedaten so weit wie möglich zu filtern, wenn sie eine gespeicherte Prozedur nicht schnell implementieren und die Anweisung vorbereiten können.
Nehmen wir zum Schluss an, dass ein Benutzer diesen Text unten 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 Eingabe kann frühzeitig ohne vorbereitete Anweisung und gespeicherte Prozeduren überprüft werden. Um jedoch auf der sicheren Seite zu sein, beginnt die Verwendung nach der Filterung und Validierung der Benutzerdaten.
Der letzte Punkt ist das Erkennen unerwarteten Verhaltens, das mehr Aufwand und Komplexität erfordert. Es wird nicht für normale Webanwendungen empfohlen.
Unerwartetes Verhalten in der obigen Benutzereingabe ist SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA und root. Sobald diese Wörter erkannt wurden, können Sie die Eingabe vermeiden.
UPDATE 1:
Ein Benutzer hat kommentiert, dass dieser Beitrag nutzlos ist, OK! Hier ist , was OWASP.ORG zur Verfügung gestellt :
Primäre Verteidigung:
Option 1: Verwendung vorbereiteter Anweisungen (parametrisierte Abfragen)
Option 2: Verwendung gespeicherter Prozeduren
Option 3: Entkommen aller vom Benutzer bereitgestellten Eingaben
Zusätzliche Verteidigung:
Auch erzwingen: Geringste Berechtigung
Führen Sie auch eine Überprüfung der Eingabe auf der weißen Liste durch
Wie Sie vielleicht wissen, sollte die Behauptung eines Artikels durch ein gültiges Argument gestützt werden, mindestens durch eine Referenz! Ansonsten ist es ein Angriff und eine schlechte Behauptung!
Update 2:
Aus dem PHP-Handbuch, PHP: Prepared Statements - Manual :
Escaping und SQL-Injection
Gebundene Variablen werden vom Server automatisch maskiert. Der Server fügt die Escape-Werte vor der Ausführung an den entsprechenden Stellen in die Anweisungsvorlage ein. Dem Server muss ein Hinweis für den Typ der gebundenen Variablen bereitgestellt werden, um eine geeignete Konvertierung zu erstellen. Weitere Informationen finden Sie in der Funktion mysqli_stmt_bind_param ().
Das automatische Escapezeichen von Werten innerhalb des Servers wird manchmal als Sicherheitsfunktion angesehen, um eine SQL-Injection zu verhindern. Das gleiche Maß an Sicherheit kann mit nicht vorbereiteten Anweisungen erreicht werden, wenn Eingabewerte korrekt maskiert werden.
Update 3:
Ich habe Testfälle erstellt, um zu wissen, wie PDO und MySQLi die Abfrage an den MySQL-Server senden, wenn eine vorbereitete Anweisung verwendet wird:
GU:
$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));
Abfrageprotokoll:
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();
Abfrageprotokoll:
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 den Daten entgeht, sonst nichts.
Wie auch in der obigen Aussage erwähnt,
Das automatische Escapezeichen von Werten innerhalb des Servers wird manchmal als Sicherheitsfunktion angesehen, um eine SQL-Injection zu verhindern. Das gleiche Maß an Sicherheit kann mit nicht vorbereiteten Anweisungen erreicht werden, wenn die Eingabewerte korrekt maskiert werden
Dies beweist daher, dass eine Datenüberprüfung, wie sie beispielsweise intval()
für ganzzahlige Werte geeignet ist, vor dem Senden einer Abfrage eine gute Idee ist. Darüber hinaus ist das Verhindern böswilliger Benutzerdaten vor dem Senden der Abfrage ein korrekter und gültiger Ansatz .
Weitere Informationen finden Sie in dieser Frage: PDO sendet eine Rohabfrage an MySQL, während Mysqli eine vorbereitete Abfrage sendet. Beide führen zum gleichen Ergebnis
Verweise:
- SQL Injection Cheat Sheet
- SQL-Injektion
- Informationssicherheit
- Sicherheitsgrundsätze
- Datenvalidierung