Wir alle wissen, dass SQL-Injection grundsätzlich verhindert werden kann, solange PDO vernünftig und korrekt verwendet wird. Dieser Artikel beantwortet hauptsächlich die folgenden zwei Fragen:
Warum verwenden? PDO stattdessen Nicht mysql_connect?
Warum kann PDO die Injektion verhindern?
Worauf sollten Sie bei der Verwendung von PDO besonders achten, um eine Injektion zu verhindern?
1. Warum sollten Sie der Verwendung von PDO Vorrang einräumen?
Das PHP-Handbuch sagt ganz klar:
Vorbereitete Anweisungen und gespeicherte Prozeduren
Viele der ausgereifteren Datenbanken unterstützen das Konzept vorbereiteter Anweisungen. Was sind sie? Vorlage für die SQL, die eine Anwendung ausführen möchte, die mithilfe von variablen Parametern angepasst werden kann
bieten zwei große Vorteile:
Die Abfrage muss nur einmal analysiert (oder vorbereitet) werden, kann aber mehrmals mit denselben oder unterschiedlichen Parametern ausgeführt werden. Wenn die Abfrage vorbereitet ist, analysiert, kompiliert und optimiert die Datenbank ihren Plan zur Ausführung der Abfrage
Dieser Vorgang kann so viel Zeit in Anspruch nehmen, dass er eine Anwendung merklich verlangsamt, wenn dieselbe Abfrage viele Male mit unterschiedlichen Parametern wiederholt werden muss. Durch die Verwendung einer vorbereiteten Anweisung vermeidet die Anwendung die Wiederholung der Analyse/Kompilierung/Optimierung
Dies bedeutet, dass vorbereitete Anweisungen weniger Ressourcen verbrauchen und daher schneller ausgeführt werden.
Die Parameter für vorbereitete Anweisungen müssen nicht automatisch in Anführungszeichen gesetzt werden eine Anwendung ausschließlich vorbereitete Anweisungen verwendet,der Entwickler kann sicher sein, dass keine SQL-Injection erfolgt(allerdings
Wenn andere Teile der Abfrage mit Eingaben ohne Escapezeichen erstellt werden, ist SQL-Injection immer noch möglich).
Selbst bei Verwendung der Prepare-Methode von PDO besteht der Hauptzweck darin,die Leistung derselben SQL-Vorlagenabfrage zu verbessern und SQL-Injection verhindern
Gleichzeitig wird die Warnmeldung im PHP-Handbuch ausgegeben
|
bedeutet, dass in PHP 5.3.6 und früheren Versionen die Zeichensatzdefinition im DSN nicht unterstützt wird, sondern verwendet werden sollte.
Ich habe einige Programme gesehen und versuche immer noch, Addslashes zu verwenden Um die Injektion zu verhindern, weiß jeder, dass dies tatsächlich mehr Probleme mit sich bringt. Weitere Informationen finden Sie unter http://www.lorui.com/addslashes-mysql_escape_string-mysql_real_eascape_string.html
Es gibt auch einige Methoden: vorher Ausführen der Datenbankabfrage, Bereinigen von Schlüsselwörtern wie „select“, „union“ usw. in SQL. Dieser Ansatz ist offensichtlich ein völlig falscher Umgang damit. Wenn der eingereichte Text tatsächlich die Studentenvereinigung enthält, wird der ursprüngliche Inhalt manipuliert, wodurch unschuldige Menschen wahllos getötet werden, und ist nicht ratsam.
2. Warum kann PDO SQL-Injection verhindern? Bitte schauen Sie sich zuerst den folgenden PHP-Code an:
$pdo = new PDO(" mysql: host=192.168.0.1;dbname=test;charset=utf8","root");
$st = $pdo->prepare("select * from info where id = ? and name = ?");
$id = 21;
$name = 'zhangsan ';
$st->bindParam(1,$id);
$st-> bindParam( 2,$name);
$st->execute();
$st->fetchAll();
?>
Die Umgebung ist wie folgt:
PHP 5.4.7
MySQL-Protokoll Version 10
MySQL Server 5.5.27
Um das gründlich zu verstehen Details zur Kommunikation zwischen PHP und MySQL-Server. Ich habe Wireshark speziell zum Erfassen von Paketen für Forschungszwecke verwendet. Nach der Installation von Wireshak haben wir die Filterbedingung auf tcp.port==3306 gesetzt, wie unten gezeigt:
Auf diese Weise werden nur die Kommunikationsdaten mit dem MySQL 3306-Port angezeigt, um unnötige Störungen zu vermeiden.
Es ist wichtig zu beachten, dass Wireshak auf dem Wincap-Treiber basiert und das Abhören der lokalen Loopback-Schnittstelle nicht unterstützt (d. h. die Verwendung von PHP zum Herstellen einer Verbindung mit der lokalen MySQL-Methode ist nicht möglich). gehört), stellen Sie bitte zum Testen eine Verbindung zu einer anderen Maschine (virtuelle Maschine mit Bridge-Netzwerk ist ebenfalls verfügbar) mit MySQL her.
Führen Sie dann unser PHP-Programm aus. Die Abhörergebnisse sind wie folgt. Wir haben festgestellt, dass PHP SQL einfach direkt an MySQL Server sendet:
Tatsächlich unterscheidet sich dies von der Art und Weise, wie wir normalerweise mysql_real_escape_string verwenden, um die Zeichenfolge zu maskieren, und Dann gibt es keinen Unterschied beim Spleißen in SQL-Anweisungen (es wird in diesem Fall nur durch den lokalen PDO-Treiber maskiert). Das heißt, mysql_real_escape_string wird in PHP lokal aufgerufen Abfrage, mit dem lokalen Einzelbyte-Zeichensatz, und wenn wir Multibyte-codierte Variablen übergeben, kann es immer noch zu SQL-Injection-Schwachstellen kommen (eines der Probleme in Versionen vor PHP 5.3.6, was erklärt, warum dies bei der Verwendung von PDO der Fall ist empfohlen Der Grund für das Upgrade auf PHP 5.3.6+ und die Angabe des Zeichensatzes in der DSN-Zeichenfolge
Für Versionen vor PHP 5.3.6 kann der folgende Code immer noch SQL-Injection-Probleme verursachen:
$pdo->query('SET NAMES GBK');
$var = chr(0x27) . ODER 1=1 /*";
$query = "SELECT * FROM info WHERE name = ?";
$stmt = $ pdo->prepare($query);
$stmt->execute(array($var));
Der Grund ist die gleiche. Die obige Analyse ist konsistent.
Die richtige Escape-Anweisung sollte darin bestehen, den Zeichensatz für den MySQL-Server anzugeben und die Variable an den MySQL-Server zu senden, um die Zeichen-Escape-Funktion abzuschließen >Wie kann man also die lokale PHP-Escape-Funktion deaktivieren und MySQL Server die Escape-Funktion überlassen? 🎜> gibt an, ob PHP zur lokalen Simulation verwendet werden soll. Den Ergebnissen der Paketerfassung zufolge, die wir gerade erfasst haben, werden in PHP 5.3.6+ standardmäßig immer noch lokale Variablen verwendet SQL und an den MySQL-Server gesendet, setzen wir diesen Wert auf „false“ und probieren den Effekt aus, z. B. den folgenden Code:
$pdo = new PDO("mysql:host=192.168.0.1;dbname=test;","root");$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false) ;
$st = $pdo->prepare("select * from info where id =? and name = ?");
$id = 21;
$name = 'zhangsan';
$st->bindParam(1,$id);
$st->bindParam(2,$name);
$st->execute();
$st->fetchAll();
?>
Die rote Linie ist der Inhalt, den wir gerade hinzugefügt haben Programm, das Wireshark zum Erfassen und Analysieren des Pakets verwendet, lautet das Ergebnis wie folgt:
Hast du es gesehen? Darin liegt der Zauber. Es ist ersichtlich, dass PHP die SQL-Vorlage und die Variablen dieses Mal zweimal an MySQL sendet und MySQL das Escapen der Variablen abschließt. Da die Variablen und die SQL-Vorlage zweimal gesendet werden, gibt es keine SQL-Injection ist ein Problem, aber Sie müssen das Zeichensatzattribut im DSN angeben, wie zum Beispiel:
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root');
Auf diese Weise kann das Problem der SQL-Injection grundsätzlich beseitigt werden. Wenn Sie sich darüber nicht ganz im Klaren sind, können Sie eine E-Mail an zhangxugg@163.com senden, , um es gemeinsam zu besprechen.
3. Vorsichtsmaßnahmen für die Verwendung von PDO
Nachdem wir die oben genannten Punkte kennen, können wir mehrere Vorsichtsmaßnahmen für die Verwendung von PDO zur Verhinderung von SQL-Injection zusammenfassen:
1. PHP wird auf 5.3.6+ aktualisiert. Für Produktionsumgebungen wird dringend empfohlen, auf PHP 5.4+ zu aktualisieren Sicherheitslücke bei Hash-Kollisionen.
2. Wenn Sie PHP 5.3.6+ verwenden, geben Sie bitte das Zeichensatzattribut im DSN von PDO an 3. Wenn Sie PHP 5.3.6 und frühere Versionen verwenden, setzen Sie den Parameter PDO::ATTR_EMULATE_PREPARES auf false (das heißt, die Variablenverarbeitung wird von MySQL 5.3.6 und höheren Versionen bereits behoben). ob lokale Simulation verwendet wird. Entweder Prepare oder Prepare des MySQL-Servers aufrufen. Die Angabe eines Zeichensatzes in einem DSN ist ungültig und die Ausführung von Satznamen
4 Wenn Sie PHP 5.3.6 und frühere Versionen verwenden, geben Sie bitte den Wert von emulatePrepare in der Datenbankkonfigurationsdatei auf false an, da das Yii-Framework den Wert von ATTR_EMULATE_PREPARES nicht standardmäßig festlegt. Es gibt also eine Frage: Wenn im DSN ein Zeichensatz angegeben ist, muss ich dann trotzdem die Satznamen
Ja, Sie können es nicht speichern.
Namen festlegen
B. Sagen Sie dem MySQL-Server, welche Kodierung das vom Client benötigte Ergebnis hat
Mit anderen Worten: Wenn die Datentabelle den GBK-Zeichensatz verwendet und das PHP-Programm die UTF-8-Codierung verwendet, können wir vor der Ausführung der Abfrage die Namenssätze utf8 ausführen und dies dem MySQL-Server mitteilen Um es richtig zu kodieren, muss der Code nicht im Programm konvertiert werden. Auf diese Weise senden wir die Abfrage in UTF-8-Kodierung an den MySQL-Server, und die erhaltenen Ergebnisse liegen ebenfalls in UTF-8-Kodierung vor. Dadurch wird das Problem der Konvertierungskodierung im Programm beseitigt. Es besteht kein Zweifel, dass dadurch kein verstümmelter Code entsteht.
Welche Rolle spielt die Angabe des Zeichensatzes im DSN? Es teilt dem PDO lediglich mit, dass der lokale Treiber beim Escapen den angegebenen Zeichensatz verwendet (der wird nicht festgelegt). MySQL-Server-Kommunikationszeichensatz) Um den MySQL-Server-Kommunikationszeichensatz festzulegen, müssen Sie auch den Befehl „Set Names
Wenn das Bild fehlt, können Sie eine E-Mail an zhangxugg@163.com senden, um eine PDF-Version anzufordern.
Ich kann wirklich nicht verstehen, warum einige neue Projekte kein PDO verwenden, sondern die traditionelle Funktionsbibliothek mysql_XXX verwenden? Wenn PDO richtig verwendet wird, kann die SQL-Injection grundsätzlich vermieden werden. Ich empfehle dringend, dass die technischen Leiter und das technische Forschungs- und Entwicklungspersonal jedes Unternehmens auf dieses Problem achten und PDO so weit wie möglich verwenden, um den Projektfortschritt und die Sicherheitsqualität zu beschleunigen .
Versuchen Sie nicht, Ihre eigene SQL-Injection-Filter-Funktionsbibliothek zu schreiben (dies ist umständlich und kann leicht zu unbekannten Schwachstellen führen).
Das Obige stellt die Analyse des Anti-Injection-Prinzips von PDO und die Vorsichtsmaßnahmen für die Verwendung von PDO vor, einschließlich des Inhalts. Ich hoffe, dass es für Freunde hilfreich sein wird, die sich für PHP-Tutorials interessieren.