Verwenden Sie vorbereitete Anweisungen und parametrisierte Abfragen. Hierbei handelt es sich um SQL-Anweisungen, die getrennt von Parametern an den Datenbankserver gesendet und von diesem analysiert werden. Auf diese Weise kann ein Angreifer kein schädliches SQL einschleusen.
Sie haben grundsätzlich zwei Möglichkeiten, um dies zu erreichen:
Verwenden von PDO (für jeden unterstützten Datenbanktreiber):
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute([ 'name' => $name ]);
foreach ($stmt as $row) {
// Do something with $row
}
Verwenden von MySQLi (für MySQL):
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// Do something with $row
}
Wenn Sie in eine andere Datenbank als MySQL sich verbinden, gibt es einen Treiber spezifische zweite Option , die Sie sich beziehen können (zum Beispiel pg_prepare()
und pg_execute()
für PostgreSQL). PDO ist die universelle Option.
Richtiges Einrichten der Verbindung
Beachten Sie, dass beim PDO
Zugriff auf eine MySQL-Datenbank standardmäßig nicht wirklich vorbereitete Anweisungen verwendet werden . Um dies zu beheben, müssen Sie die Emulation vorbereiteter Anweisungen deaktivieren. Ein Beispiel für das Erstellen einer Verbindung mit PDO ist:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'password');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Im obigen Beispiel ist der Fehlermodus nicht unbedingt erforderlich, es wird jedoch empfohlen, ihn hinzuzufügen . Auf diese Weise hört das Skript nicht mit einem auf, Fatal Error
wenn etwas schief geht. Und es gibt dem Entwickler die Möglichkeit, catch
Fehler zu machen, die throw
n wie PDOException
s sind.
Was jedoch obligatorisch ist, ist die erste setAttribute()
Zeile, in der PDO angewiesen wird, emulierte vorbereitete Anweisungen zu deaktivieren und echte vorbereitete Anweisungen zu verwenden. Dadurch wird sichergestellt, dass die Anweisung und die Werte nicht von PHP analysiert werden, bevor sie an den MySQL-Server gesendet werden (sodass ein möglicher Angreifer keine Chance hat, schädliches SQL einzuschleusen).
Obwohl Sie die charset
in den Optionen des Konstruktors festlegen können , ist es wichtig zu beachten, dass "ältere" Versionen von PHP (vor 5.3.6) den Zeichensatzparameter im DSN stillschweigend ignorierten .
Erläuterung
Die SQL-Anweisung, an die Sie übergeben, prepare
wird vom Datenbankserver analysiert und kompiliert. Durch Angabe von Parametern (entweder ein ?
oder ein benannter Parameter wie :name
im obigen Beispiel) teilen Sie dem Datenbankmodul mit, nach was Sie filtern möchten. Wenn Sie dann aufrufen execute
, wird die vorbereitete Anweisung mit den von Ihnen angegebenen Parameterwerten kombiniert.
Wichtig hierbei ist, dass die Parameterwerte mit der kompilierten Anweisung kombiniert werden, nicht mit einer SQL-Zeichenfolge. Bei der SQL-Injection wird das Skript dazu verleitet, beim Erstellen von SQL zum Senden an die Datenbank schädliche Zeichenfolgen einzuschließen. Indem Sie das eigentliche SQL getrennt von den Parametern senden, begrenzen Sie das Risiko, dass Sie etwas erhalten, das Sie nicht beabsichtigt haben.
Alle Parameter, die Sie bei Verwendung einer vorbereiteten Anweisung senden, werden nur als Zeichenfolgen behandelt (obwohl das Datenbankmodul möglicherweise einige Optimierungen vornimmt, sodass Parameter natürlich auch als Zahlen enden können). Wenn die $name
Variable im obigen Beispiel 'Sarah'; DELETE FROM employees
das Ergebnis enthält, wäre dies einfach eine Suche nach der Zeichenfolge "'Sarah'; DELETE FROM employees"
, und Sie erhalten keine leere Tabelle .
Ein weiterer Vorteil der Verwendung vorbereiteter Anweisungen besteht darin, dass wenn Sie dieselbe Anweisung mehrmals in derselben Sitzung ausführen, sie nur einmal analysiert und kompiliert wird, wodurch Sie einige Geschwindigkeitsgewinne erzielen.
Oh, und da Sie gefragt haben, wie es für eine Einfügung gemacht werden soll, ist hier ein Beispiel (mit PDO):
$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$preparedStatement->execute([ 'column' => $unsafeValue ]);
Können vorbereitete Anweisungen für dynamische Abfragen verwendet werden?
Während Sie weiterhin vorbereitete Anweisungen für die Abfrageparameter verwenden können, kann die Struktur der dynamischen Abfrage selbst nicht parametrisiert werden und bestimmte Abfragefunktionen können nicht parametrisiert werden.
Für diese speziellen Szenarien verwenden Sie am besten einen Whitelist-Filter, der die möglichen Werte einschränkt.
// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
$dir = 'ASC';
}
Wenn Sie eine neuere Version von PHP verwenden, ist die
mysql_real_escape_string
unten beschriebene Option nicht mehr verfügbar (obwohl diesmysqli::escape_string
ein modernes Äquivalent ist). Heutzutage ist diemysql_real_escape_string
Option nur für Legacy-Code in einer alten Version von PHP sinnvoll.Sie haben zwei Möglichkeiten - das Ausblenden der Sonderzeichen in Ihrer
unsafe_variable
oder die Verwendung einer parametrisierten Abfrage. Beides würde Sie vor SQL-Injection schützen. Die parametrisierte Abfrage wird als die bessere Vorgehensweise angesehen, erfordert jedoch den Wechsel zu einer neueren MySQL-Erweiterung in PHP, bevor Sie sie verwenden können.Wir werden zuerst die untere Aufprallschnur abdecken, die einer entweicht.
Siehe auch die Details der
mysql_real_escape_string
Funktion.Um die parametrisierte Abfrage zu verwenden, müssen Sie MySQLi anstelle der MySQL- Funktionen verwenden. Um Ihr Beispiel neu zu schreiben, benötigen wir Folgendes.
Die Schlüsselfunktion, die Sie dort nachlesen möchten, wäre
mysqli::prepare
.Wie andere vorgeschlagen haben, ist es möglicherweise nützlich / einfacher, eine Abstraktionsebene mit etwas wie PDO zu verstärken .
Bitte beachten Sie, dass der Fall, nach dem Sie gefragt haben, ziemlich einfach ist und dass komplexere Fälle komplexere Ansätze erfordern können. Bestimmtes:
mysql_real_escape_string
. In diesem Fall ist es besser, wenn Sie die Benutzereingaben über eine Whitelist weiterleiten, um sicherzustellen, dass nur "sichere" Werte zugelassen werden.mysql_real_escape_string
Ansatz wählen, leiden Sie unter dem von Polynomial in den Kommentaren unten beschriebenen Problem . Dieser Fall ist schwieriger, da Ganzzahlen nicht in Anführungszeichen gesetzt werden. Sie können also damit umgehen, indem Sie überprüfen, ob die Benutzereingabe nur Ziffern enthält.quelle
mysql_real_escape_string
ist genug oder muss ich auch parametrisiert verwenden?htmlentities
mysql_real_escape_string()
Vollständigkeit halber, bin aber kein Fan davon, zuerst den fehleranfälligsten Ansatz aufzulisten. Der Leser könnte sich schnell das erste Beispiel schnappen. Gut, dass es jetzt veraltet ist :)mysql_*
Funktionen sind veraltet. Sie wurden durch ähnlichemysqli_*
Funktionen ersetzt, wie zmysqli_real_escape_string
.Jede Antwort hier deckt nur einen Teil des Problems ab. Tatsächlich gibt es vier verschiedene Abfrageteile, die wir dynamisch zu SQL hinzufügen können:
Und vorbereitete Aussagen decken nur zwei davon ab.
Manchmal müssen wir unsere Abfrage jedoch noch dynamischer gestalten und auch Operatoren oder Bezeichner hinzufügen. Wir brauchen also verschiedene Schutztechniken.
Im Allgemeinen basiert ein solcher Schutzansatz auf einer Whitelist .
In diesem Fall sollte jeder dynamische Parameter in Ihrem Skript fest codiert und aus diesem Satz ausgewählt werden. Zum Beispiel, um eine dynamische Bestellung durchzuführen:
Um den Prozess zu vereinfachen, habe ich eine Whitelist-Hilfsfunktion geschrieben , die alle Aufgaben in einer Zeile erledigt:
Es gibt noch einen anderen Weg, um Identifikatoren zu sichern - das Entkommen, aber ich bleibe lieber bei der Whitelist als einem robusteren und expliziteren Ansatz. Solange Sie jedoch eine Kennung in Anführungszeichen haben, können Sie das Anführungszeichen aus Sicherheitsgründen umgehen. Beispielsweise müssen Sie für MySQL standardmäßig das Anführungszeichen verdoppeln, um es zu umgehen . Für andere DBMS-Escape-Regeln wären die Regeln anders.
Dennoch gibt es ein Problem mit SQL - Syntax Schlüsselwort (wie
AND
,DESC
und so weiter ), aber Whitelisting scheint den einzigen Ansatz in diesem Fall.Eine allgemeine Empfehlung kann also wie folgt formuliert werden
Aktualisieren
Obwohl es eine allgemeine Übereinstimmung über die Best Practices für den SQL-Injection-Schutz gibt, gibt es immer noch viele schlechte Praktiken. Und einige von ihnen sind zu tief in den Köpfen der PHP-Benutzer verwurzelt. Zum Beispiel gibt es auf dieser Seite (obwohl für die meisten Besucher unsichtbar) mehr als 80 gelöschte Antworten, die alle von der Community aufgrund schlechter Qualität oder der Förderung schlechter und veralteter Praktiken entfernt wurden. Schlimmer noch, einige der schlechten Antworten werden nicht gelöscht, sondern gedeihen.
Zum Beispiel gibt es (1) (2) immer noch (3) viele (4) Antworten (5) , einschließlich der am zweithäufigsten bewerteten Antwort, die darauf hindeutet, dass Sie manuell Zeichenfolgen entfernen - ein veralteter Ansatz, der sich als unsicher erwiesen hat.
Oder es gibt eine etwas bessere Antwort, die nur eine andere Methode zur Formatierung von Zeichenfolgen vorschlägt und diese sogar als ultimatives Allheilmittel bezeichnet. Während es natürlich nicht ist. Diese Methode ist nicht besser als die normale Formatierung von Zeichenfolgen, behält jedoch alle Nachteile bei: Sie gilt nur für Zeichenfolgen und ist wie jede andere manuelle Formatierung im Wesentlichen eine optionale, nicht obligatorische Maßnahme, die für menschliches Versagen jeglicher Art anfällig ist.
Ich denke, dass dies alles auf einen sehr alten Aberglauben zurückzuführen ist, der von Behörden wie OWASP oder dem PHP-Handbuch unterstützt wird und die Gleichheit zwischen "Entkommen" und Schutz vor SQL-Injektionen proklamiert.
Unabhängig davon, was das PHP-Handbuch seit Ewigkeiten sagt,
*_escape_string
macht es Daten auf keinen Fall sicher und war nie dazu gedacht. Manuelles Escape ist nicht nur für andere SQL-Teile als Zeichenfolgen nutzlos, sondern auch falsch, da es manuell und nicht automatisiert ist.Und OWASP macht es noch schlimmer, indem es betont, dass Benutzereingaben vermieden werden, was ein völliger Unsinn ist: Im Zusammenhang mit dem Injektionsschutz sollte es keine solchen Worte geben. Jede Variable ist potenziell gefährlich - unabhängig von der Quelle! Mit anderen Worten - jede Variable muss richtig formatiert sein, um in eine Abfrage eingefügt zu werden - unabhängig von der Quelle. Auf das Ziel kommt es an. In dem Moment, in dem ein Entwickler beginnt, die Schafe von den Ziegen zu trennen (er überlegt, ob eine bestimmte Variable "sicher" ist oder nicht), unternimmt er seinen ersten Schritt in Richtung Katastrophe. Ganz zu schweigen davon, dass selbst der Wortlaut darauf hindeutet, dass die Masse am Einstiegspunkt entweicht und der Funktion der magischen Anführungszeichen ähnelt - bereits verachtet, veraltet und entfernt.
Also, im Gegensatz zu, was auch immer „Flucht“, Prepared Statements ist die Maßnahme , dass in der Tat von SQL - Injection schützt (wenn zutreffend).
quelle
Ich würde empfehlen, PDO (PHP Data Objects) zu verwenden, um parametrisierte SQL-Abfragen auszuführen.
Dies schützt nicht nur vor SQL-Injection, sondern beschleunigt auch Abfragen.
Und von PDO mit nicht
mysql_
,mysqli_
undpgsql_
Funktionen, machen Sie Ihre Anwendung ein wenig mehr aus der Datenbank abstrahiert, in seltenen Vorkommen , dass Sie Switch - Datenbank - Anbieter haben.quelle
Verwenden
PDO
und vorbereitete Abfragen.(
$conn
ist einPDO
Objekt)quelle
Wie Sie sehen können, schlagen die Leute vor, dass Sie höchstens vorbereitete Aussagen verwenden. Es ist nicht falsch, aber wenn Ihre Abfrage nur einmal pro Prozess ausgeführt wird, würde dies zu einer leichten Leistungsminderung führen.
Ich war mit diesem Problem konfrontiert, aber ich glaube, ich habe es auf sehr raffinierte Weise gelöst - wie Hacker es verwenden, um die Verwendung von Anführungszeichen zu vermeiden. Ich habe dies in Verbindung mit emulierten vorbereiteten Aussagen verwendet. Ich benutze es, um alle Arten von möglichen SQL-Injection-Angriffen zu verhindern .
Mein Ansatz:
Wenn Sie erwarten, dass die Eingabe eine Ganzzahl ist, stellen Sie sicher, dass sie wirklich eine Ganzzahl ist. In einer variablen Sprache wie PHP ist dies sehr wichtig. Sie können zum Beispiel diese sehr einfache, aber leistungsstarke Lösung verwenden:
sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);
Wenn Sie etwas anderes von Integer Hex erwarten . Wenn Sie es verhexen, entziehen Sie sich perfekt allen Eingaben. In C / C ++ gibt es eine Funktion namens
mysql_hex_string()
, in PHP können Sie verwendenbin2hex()
.Machen Sie sich keine Sorgen, dass die maskierte Zeichenfolge die doppelte Größe ihrer ursprünglichen Länge hat, denn selbst wenn Sie sie verwenden
mysql_real_escape_string
, muss PHP dieselbe Kapazität zuweisen((2*input_length)+1)
, die dieselbe ist.Diese Hex-Methode wird häufig verwendet, wenn Sie Binärdaten übertragen. Ich sehe jedoch keinen Grund, sie nicht für alle Daten zu verwenden, um SQL-Injection-Angriffe zu verhindern. Beachten Sie, dass Sie Daten mit
0x
der MySQL-Funktion voranstellen oderUNHEX
stattdessen verwenden müssen.So zum Beispiel die Abfrage:
Wird werden:
oder
Hex ist die perfekte Flucht. Keine Möglichkeit zu injizieren.
Unterschied zwischen UNHEX-Funktion und 0x-Präfix
Es gab einige Diskussionen in Kommentaren, deshalb möchte ich es endlich klarstellen. Diese beiden Ansätze sind sehr ähnlich, unterscheiden sich jedoch in einigen Punkten geringfügig:
Das Präfix ** 0x ** kann nur für Datenspalten wie char, varchar, text, block, binary usw. verwendet werden .
Außerdem ist die Verwendung etwas kompliziert, wenn Sie eine leere Zeichenfolge einfügen möchten. Sie müssen es vollständig ersetzen, sonst
''
wird eine Fehlermeldung angezeigt.UNHEX () funktioniert für jede Spalte. Sie müssen sich keine Sorgen um die leere Zeichenfolge machen.
Hex-Methoden werden häufig als Angriffe verwendet
Beachten Sie, dass diese Hex-Methode häufig als SQL-Injection-Angriff verwendet wird, bei dem Ganzzahlen wie Zeichenfolgen sind und nur mit maskiert werden
mysql_real_escape_string
. Dann können Sie die Verwendung von Anführungszeichen vermeiden.Zum Beispiel, wenn Sie einfach so etwas tun:
Ein Angriff kann Sie sehr leicht injizieren . Betrachten Sie den folgenden injizierten Code, der von Ihrem Skript zurückgegeben wird:
und jetzt einfach die Tabellenstruktur extrahieren:
Und dann wählen Sie einfach die gewünschten Daten aus. Ist es nicht cool?
Wenn der Codierer einer injizierbaren Stelle sie jedoch verhexen würde, wäre keine Injektion möglich, da die Abfrage folgendermaßen aussehen würde:
SELECT ... WHERE id = UNHEX('2d312075...3635')
quelle
+
sondern mitCONCAT
. Und zur Leistung: Ich glaube nicht, dass dies die Leistung beeinträchtigt, da MySQL Daten analysieren muss und es keine Rolle spielt, ob der Ursprung ein String oder ein Hex ist'root'
oder du kannst ihn0x726f6f74
hexen , ABER wenn du eine Zahl willst und sie als String schickst, wirst du wahrscheinlich '42' schreiben, nicht CHAR (42) ) ... '42' in hex wäre0x3432
nicht0x42
SELECT title FROM article WHERE id = UNHEX(' . bin2hex($_GET["id"]) . ')
Injektionsprävention - mysql_real_escape_string ()
PHP hat eine speziell entwickelte Funktion, um diese Angriffe zu verhindern. Alles, was Sie tun müssen, ist den Mund voll einer Funktion zu verwenden
mysql_real_escape_string
.mysql_real_escape_string
Nimmt eine Zeichenfolge, die in einer MySQL-Abfrage verwendet werden soll, und gibt dieselbe Zeichenfolge zurück, wobei alle SQL-Injection-Versuche sicher entkommen sind. Grundsätzlich werden die problematischen Anführungszeichen ('), die ein Benutzer möglicherweise eingibt, durch ein MySQL-sicheres Ersatzzeichen ersetzt, ein maskiertes Anführungszeichen \'.HINWEIS: Sie müssen mit der Datenbank verbunden sein, um diese Funktion nutzen zu können!
// Verbindung zu MySQL herstellen
Weitere Informationen finden Sie unter MySQL - SQL Injection Prevention .
quelle
mysql_real_escape_string
Zweck besteht darin, die korrekte SQL-Abfrage für jede Eingabedatenzeichenfolge zu erstellen. Prävention SQL-Injektion ist der Nebeneffekt dieser Funktion.mysql_real_escape_string()
ist nicht unfehlbar .mysql_real_escape_string
ist jetzt veraltet, daher ist es keine praktikable Option mehr. Es wird in Zukunft aus PHP entfernt. Es ist am besten, sich den Empfehlungen der PHP- oder MySQL-Leute zuzuwenden.Sie könnten so etwas Grundlegendes tun:
Dies wird nicht jedes Problem lösen, aber es ist ein sehr gutes Sprungbrett. Ich habe offensichtliche Punkte wie die Überprüfung der Existenz, des Formats (Zahlen, Buchstaben usw.) der Variablen ausgelassen.
quelle
$q = "SELECT col FROM tbl WHERE x = $safe_var";
zum Beispiel. Die Einstellung$safe_var
auf1 UNION SELECT password FROM users
funktioniert in diesem Fall aufgrund fehlender Anführungszeichen. Es ist auch möglich, Zeichenfolgen mitCONCAT
und in die Abfrage einzufügenCHR
.mysql_real_escape_string()
ist nicht unfehlbar .mysql_real_escape_string
ist jetzt veraltet, daher ist es keine praktikable Option mehr. Es wird in Zukunft aus PHP entfernt. Es ist am besten, sich den Empfehlungen der PHP- oder MySQL-Leute zuzuwenden.Was auch immer Sie letztendlich verwenden, stellen Sie sicher, dass Sie überprüfen, ob Ihre Eingabe noch nicht durch
magic_quotes
einen anderen gut gemeinten Müll beschädigt wurde, und führen Sie ihn gegebenenfalls durchstripslashes
oder was auch immer, um ihn zu bereinigen.quelle
Parametrisierte Abfrage- UND Eingabevalidierung ist der richtige Weg. Es gibt viele Szenarien, in denen SQL-Injection auftreten kann, obwohl
mysql_real_escape_string()
dies verwendet wurde.Diese Beispiele sind anfällig für SQL-Injection:
oder
In beiden Fällen können Sie
'
die Kapselung nicht schützen.Quelle : Die unerwartete SQL-Injektion (wenn das Entkommen nicht ausreicht)
quelle
Meiner Meinung nach ist der beste Weg, um SQL-Injection in Ihrer PHP-Anwendung (oder einer anderen Webanwendung) generell zu verhindern, über die Architektur Ihrer Anwendung nachzudenken. Wenn der einzige Weg zum Schutz vor SQL-Injection darin besteht, eine spezielle Methode oder Funktion zu verwenden, die jedes Mal, wenn Sie mit der Datenbank sprechen, das Richtige tut, machen Sie es falsch. Auf diese Weise ist es nur eine Frage der Zeit, bis Sie vergessen, Ihre Abfrage irgendwann in Ihrem Code korrekt zu formatieren.
Die Übernahme des MVC-Musters und eines Frameworks wie CakePHP oder CodeIgniter ist wahrscheinlich der richtige Weg: In solchen Frameworks wurden allgemeine Aufgaben wie das Erstellen sicherer Datenbankabfragen gelöst und zentral implementiert. Sie helfen Ihnen dabei, Ihre Webanwendung sinnvoll zu organisieren, und lassen Sie mehr über das Laden und Speichern von Objekten nachdenken als über das sichere Erstellen einzelner SQL-Abfragen.
quelle
Ich bevorzuge gespeicherte Prozeduren ( MySQL unterstützt seit 5.0 gespeicherte Prozeduren ) aus Sicherheitsgründen - die Vorteile sind:
Die Nachteile sind -
quelle
Es gibt viele Möglichkeiten, SQL-Injektionen und andere SQL-Hacks zu verhindern. Sie können es leicht im Internet finden (Google-Suche). Natürlich ist PDO eine der guten Lösungen. Ich möchte Ihnen jedoch eine gute Verhinderung von Links durch SQL-Injection vorschlagen.
Was ist SQL Injection und wie kann dies verhindert werden?
PHP-Handbuch für SQL-Injection
Microsoft-Erklärung zur SQL-Injektion und -Prävention in PHP
Und einige andere wie das Verhindern der SQL-Injektion mit MySQL und PHP .
Nun, warum tun Sie Sie benötigen , um Ihre Abfrage von SQL - Injection zu verhindern?
Ich möchte Sie wissen lassen: Warum versuchen wir anhand eines kurzen Beispiels unten, die SQL-Injection zu verhindern:
Abfrage für Übereinstimmung der Anmeldungsauthentifizierung:
Nun, wenn jemand (ein Hacker) setzt
und Passwort alles ....
Die Abfrage wird nur bis zu:
Der andere Teil wird verworfen. Also, was wird passieren? Ein nicht autorisierter Benutzer (Hacker) kann sich als Administrator anmelden, ohne sein Kennwort zu haben. Jetzt kann er / sie alles tun, was der Administrator / die E-Mail-Person tun kann. Es ist sehr gefährlich, wenn die SQL-Injection nicht verhindert wird.
quelle
Ich denke, wenn jemand PHP und MySQL oder einen anderen Datenbankserver verwenden möchte:
(int)$foo
. Lesen Sie mehr über Art von Variablen in PHP hier . Wenn Sie Bibliotheken wie PDO oder MySQLi verwenden, verwenden Sie immer PDO :: quote () und mysqli_real_escape_string () .Beispiele für Bibliotheken:
---- gU
--- MySQLi
PS :
PDO gewinnt diesen Kampf mit Leichtigkeit. Durch die Unterstützung von zwölf verschiedenen Datenbanktreibern und benannten Parametern können wir den geringen Leistungsverlust ignorieren und uns an die API gewöhnen. Aus Sicherheitsgründen sind beide sicher, solange der Entwickler sie so verwendet, wie sie verwendet werden sollen
Während sowohl PDO als auch MySQLi recht schnell sind, schneidet MySQLi in Benchmarks unwesentlich schneller ab - ~ 2,5% für nicht vorbereitete Anweisungen und ~ 6,5% für vorbereitete.
Und bitte testen Sie jede Abfrage in Ihrer Datenbank - dies ist ein besserer Weg, um eine Injektion zu verhindern.
quelle
Wenn möglich, geben Sie die Typen Ihrer Parameter ein. Aber es funktioniert nur mit einfachen Typen wie int, bool und float.
quelle
Wenn Sie Cache-Engines wie Redis oder Memcached nutzen möchten, ist DALMP möglicherweise die richtige Wahl. Es verwendet reines MySQLi . Überprüfen Sie Folgendes : DALMP Database Abstraction Layer für MySQL mit PHP.
Sie können Ihre Argumente auch vorbereiten, bevor Sie Ihre Abfrage vorbereiten, sodass Sie dynamische Abfragen erstellen und am Ende eine vollständig vorbereitete Anweisungsabfrage haben können. DALMP Database Abstraction Layer für MySQL mit PHP.
quelle
Für diejenigen, die sich nicht sicher sind, wie sie PDO verwenden sollen (aus den
mysql_
Funktionen), habe ich einen sehr, sehr einfachen PDO-Wrapper erstellt , der eine einzelne Datei ist. Es zeigt, wie einfach es ist, alle gängigen Aufgaben zu erledigen, die Anwendungen ausführen müssen. Funktioniert mit PostgreSQL, MySQL und SQLite.Im Grunde genommen, lesen Sie es , während Sie das Handbuch zu lesen , um zu sehen , wie die PDO - Funktionen im realen Leben Gebrauch zu setzen , um es einfach zu speichern und abzurufen Werte im Format Sie mögen.
quelle
Mit dieser PHP-Funktion können
mysql_escape_string()
Sie schnell eine gute Prävention erzielen.Zum Beispiel:
mysql_escape_string
- Entgeht eine Zeichenfolge zur Verwendung in einer mysql_queryFür mehr Prävention können Sie am Ende hinzufügen ...
Endlich bekommen Sie:
quelle
Einige Richtlinien zum Escapezeichen von Sonderzeichen in SQL-Anweisungen.
Verwenden Sie MySQL nicht . Diese Erweiterung ist veraltet. Verwenden Sie stattdessen MySQLi oder PDO .
MySQLi
Zum manuellen Escapezeichen von Sonderzeichen in einer Zeichenfolge können Sie die Funktion mysqli_real_escape_string verwenden. Die Funktion funktioniert nur dann ordnungsgemäß, wenn der richtige Zeichensatz mit mysqli_set_charset festgelegt wurde .
Beispiel:
Verwenden Sie zum automatischen Escapezeichen von Werten mit vorbereiteten Anweisungen mysqli_prepare und mysqli_stmt_bind_param, wobei Typen für die entsprechenden Bindevariablen für eine geeignete Konvertierung angegeben werden müssen:
Beispiel:
Unabhängig davon, ob Sie vorbereitete Anweisungen verwenden oder
mysqli_real_escape_string
, müssen Sie immer die Art der Eingabedaten kennen, mit denen Sie arbeiten.Wenn Sie also eine vorbereitete Anweisung verwenden, müssen Sie die Typen der Variablen für die
mysqli_stmt_bind_param
Funktion angeben .Und die Verwendung von
mysqli_real_escape_string
dient dazu, wie der Name schon sagt, Sonderzeichen in einer Zeichenfolge zu maskieren, sodass Ganzzahlen nicht sicher sind. Mit dieser Funktion soll verhindert werden, dass die Zeichenfolgen in SQL-Anweisungen unterbrochen werden und die Datenbank dadurch beschädigt wird.mysqli_real_escape_string
ist eine nützliche Funktion bei richtiger Verwendung, insbesondere in Kombination mitsprintf
.Beispiel:
quelle
Die einfache Alternative zu diesem Problem könnte gelöst werden, indem entsprechende Berechtigungen in der Datenbank selbst erteilt werden. Beispiel: Wenn Sie eine MySQL-Datenbank verwenden, geben Sie die Datenbank über das Terminal oder die bereitgestellte Benutzeroberfläche ein und folgen Sie einfach diesem Befehl:
Dadurch wird der Benutzer darauf beschränkt, sich nur auf die angegebenen Abfragen zu beschränken. Entfernen Sie die Löschberechtigung, damit die Daten niemals aus der von der PHP-Seite ausgelösten Abfrage gelöscht werden. Als zweites müssen Sie die Berechtigungen leeren, damit MySQL die Berechtigungen und Aktualisierungen aktualisiert.
Weitere Informationen zu Flush .
Um die aktuellen Berechtigungen für den Benutzer anzuzeigen, wird die folgende Abfrage ausgelöst.
Erfahren Sie mehr über GRANT .
quelle
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.
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:
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 :
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 :
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:
Abfrageprotokoll:
MySQLi:
Abfrageprotokoll:
Es ist klar, dass eine vorbereitete Anweisung auch den Daten entgeht, sonst nichts.
Wie auch in der obigen Aussage erwähnt,
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:
quelle
Ich verwende drei verschiedene Methoden, um zu verhindern, dass meine Webanwendung für SQL-Injection anfällig ist.
mysql_real_escape_string()
, die eine vordefinierte Funktion ist PHP , und dieser Code add umgekehrten Schrägstrichen auf die folgenden Figuren:\x00
,\n
,\r
,\
,'
,"
und\x1a
. Übergeben Sie die Eingabewerte als Parameter, um die Wahrscheinlichkeit einer SQL-Injection zu minimieren.Ich hoffe, dies wird dir helfen.
Betrachten Sie die folgende Abfrage:
$iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";
mysql_real_escape_string () schützt hier nicht. Wenn Sie in Ihrer Abfrage einfache Anführungszeichen ('') für Ihre Variablen verwenden, schützt dies Sie davor. Hier ist eine Lösung dafür:
$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";
Diese Frage hat einige gute Antworten darauf.
Ich schlage vor, PDO ist die beste Option.
Bearbeiten:
mysql_real_escape_string()
ist ab PHP 5.5.0 veraltet. Verwenden Sie entweder mysqli oder PDO.Eine Alternative zu mysql_real_escape_string () ist
Beispiel:
quelle
Eine einfache Möglichkeit wäre die Verwendung eines PHP-Frameworks wie CodeIgniter oder Laravel, das über integrierte Funktionen wie Filterung und aktive Aufzeichnung verfügt, sodass Sie sich nicht um diese Nuancen kümmern müssen.
quelle
Warnung: Der in dieser Antwort beschriebene Ansatz gilt nur für sehr spezifische Szenarien und ist nicht sicher, da SQL-Injection-Angriffe nicht nur auf der Injection-Fähigkeit beruhen
X=Y
.Wenn die Angreifer versuchen, sich über die PHP-
$_GET
Variable oder mit der Abfragezeichenfolge der URL in das Formular zu hacken , können Sie sie abfangen, wenn sie nicht sicher sind.Denn
1=1
,2=2
,1=2
,2=1
,1+1=2
, etc ... sind die häufigsten Fragen zu einer SQL - Datenbank eines Angreifers. Vielleicht wird es auch von vielen Hacking-Anwendungen verwendet.Sie müssen jedoch darauf achten, dass Sie keine sichere Abfrage von Ihrer Site aus neu schreiben. Der obige Code gibt Ihnen einen Tipp, wie Sie diese hacking-spezifische dynamische Abfragezeichenfolge in eine Seite umschreiben oder umleiten können (dies hängt von Ihnen ab) , auf der die IP-Adresse des Angreifers oder AUCH IHRE COOKIES, der Verlauf, der Browser oder andere vertrauliche Informationen gespeichert werden Informationen, damit Sie später mit ihnen umgehen können, indem Sie ihr Konto sperren oder die Behörden kontaktieren.
quelle
1-1=0
los? :)([0-9\-]+)=([0-9]+)
.Es gibt so viele Antworten für PHP und MySQL , aber hier ist Code für PHP und Oracle, um die SQL-Injection sowie die regelmäßige Verwendung von oci8-Treibern zu verhindern:
quelle
Eine gute Idee ist es, einen objektrelationalen Mapper wie Idiorm zu verwenden :
Es erspart Ihnen nicht nur SQL-Injektionen, sondern auch Syntaxfehler! Es werden auch Modellkollektionen mit Methodenverkettung unterstützt, um Aktionen auf mehrere Ergebnisse gleichzeitig und mehrere Verbindungen zu filtern oder anzuwenden.
quelle
Die Verwendung von PDO und MYSQLi ist eine gute Methode , um SQL-Injektionen zu verhindern. Wenn Sie jedoch wirklich mit MySQL-Funktionen und -Abfragen arbeiten möchten, ist die Verwendung besser
mysql_real_escape_string
Es gibt mehr Möglichkeiten, dies zu verhindern: wie Identifizieren - Wenn die Eingabe eine Zeichenfolge, eine Zahl, ein Zeichen oder ein Array ist, gibt es so viele integrierte Funktionen, um dies zu erkennen. Es ist auch besser, diese Funktionen zum Überprüfen der Eingabedaten zu verwenden.
is_string
is_numeric
Und es ist viel besser, diese Funktionen zu verwenden, um Eingabedaten zu überprüfen
mysql_real_escape_string
.quelle
mysql_real_escape_string()
ist nicht unfehlbar .mysql_real_escape_string
ist jetzt veraltet, daher ist es keine praktikable Option mehr. Es wird in Zukunft aus PHP entfernt. Es ist am besten, sich den Empfehlungen der PHP- oder MySQL-Leute zuzuwenden.Ich habe diese kleine Funktion vor einigen Jahren geschrieben:
Dies ermöglicht das Ausführen von Anweisungen in einem einzeiligen C # -ish String.Format wie:
Es entweicht unter Berücksichtigung des Variablentyps. Wenn Sie versuchen, Tabellen- und Spaltennamen zu parametrisieren, schlägt dies fehl, da jede Zeichenfolge in Anführungszeichen gesetzt wird, was eine ungültige Syntax darstellt.
SICHERHEITS-UPDATE: In der vorherigen
str_replace
Version wurden Injektionen durch Hinzufügen von {#} Token zu Benutzerdaten zugelassen. Diesepreg_replace_callback
Version verursacht keine Probleme, wenn der Ersatz diese Token enthält.quelle