Die Anwendung ist anfällig für SQL-Injection, wenn der Benutzer eine Abfrage direkt in eine SQL-Anweisung eingibt, wie im folgenden Beispiel:
<code><span>$unsafe_variable</span> = <span>$_POST</span>[<span>'user_input'</span>]; mysql_query(<span>"INSERT INTO table (column) VALUES ('"</span> . <span>$unsafe_variable</span> . <span>"')"</span>);</code>
Dies liegt daran, dass der Benutzer „Ähnlich“ wie „VALUE“ eingeben kann "); DROP TABLE table; -, sodass die Abfrage lautet:
<code><span><span>INSERT</span><span>INTO</span><span>table</span> (<span>column</span>) <span>VALUES</span>(<span>'VALUE'</span>);</span><span><span>DROP</span><span>TABLE</span><span>table</span>;</span>'</code>
Wie sollen wir diese Situation verhindern? Schauen wir uns Theos Antwort an
Verwenden Sie vorbereitete Anweisungen und parametrisierte Abfragen. SQL-Anweisungen mit beliebigen Parametern werden an den Datenbankserver gesendet und geparst! Es ist für einen Angreifer unmöglich, SQL böswillig einzuschleusen!
Um dieses Ziel zu erreichen, gibt es grundsätzlich zwei Möglichkeiten:
1. Verwenden Sie PDO (PHP-Datenobjekte)
<code><span>$stmt</span> = <span>$pdo</span>->prepare(<span>'SELECT * FROM employees WHERE name = :name'</span>); <span>$stmt</span>->execute(<span>array</span>(<span>':name'</span> => <span>$name</span>)); <span>foreach</span> (<span>$stmt</span><span>as</span><span>$row</span>) { <span>// do something with $row</span> }</code>
2. Verwenden Sie mysqli
<code><span>$stmt</span><span>=</span><span>$dbConnection</span><span>-></span>prepare(<span>'SELECT * FROM employees WHERE name = ?'</span>); <span>$stmt</span><span>-></span>bind_param(<span>'s'</span>, <span>$name</span>); <span>$stmt</span><span>-></span>execute(); <span>$result</span><span>=</span><span>$stmt</span><span>-></span>get_result(); <span>while</span> (<span>$row</span><span>=</span><span>$result</span><span>-></span>fetch_assoc()) { <span>// do something with $row</span> }</code>
PDO( PHP Daten Objekt )
Beachten Sie, dass bei Verwendung von PDO für den Zugriff auf die MySQL-Datenbank standardmäßig nicht die eigentlichen vorbereiteten Anweisungen verwendet werden! Um dieses Problem zu beheben, müssen Sie die Emulation vorbereiteter Anweisungen deaktivieren. Ein Beispiel für die Verwendung von PDO zum Erstellen einer Verbindung ist wie folgt:
<code><span>$dbConnection</span><span>=</span><span>new</span> PDO(<span>'mysql:dbname=dbtest;host=127.0.0.1;charset=utf8'</span>, <span>'user'</span>, <span>'pass'</span>); <span>$dbConnection</span><span>-></span>setAttribute(PDO<span>::ATTR_EMULATE_PREPARES</span>, <span>false</span>); <span>$dbConnection</span><span>-></span>setAttribute(PDO<span>::ATTR_ERRMODE</span>, PDO<span>::ERRMODE_<strong>Exception</strong></span>);</code>
Im obigen Beispiel ist der Fehlermodus ERRMODE nicht unbedingt erforderlich, es wird jedoch empfohlen, ihn hinzuzufügen. Diese Methode stoppt das Skript nicht, wenn ein schwerwiegender Fehler auftritt. Und geben Sie dem Entwickler die Möglichkeit, etwaige Fehler abzufangen (wenn eine PDOException-Ausnahme ausgelöst wird).
Die setAttribute()-Zeile ist obligatorisch. Sie weist PDO an, emulierte vorbereitete Anweisungen zu deaktivieren und echte vorbereitete Anweisungen zu verwenden. Dadurch wird sichergestellt, dass Anweisungen und Werte nicht von PHP analysiert werden, bevor sie an den MySQL-Datenbankserver gesendet werden (ein Angreifer hat keine Möglichkeit, bösartiges SQL einzuschleusen
).
Natürlich können Sie den Zeichensatzparameter in den Konstruktoroptionen festlegen. Beachten Sie insbesondere, dass „alte“ PHP-Versionen (5.3.6) den Zeichensatzparameter im DSN ignorieren.
Erklärung
Was passiert, wenn die von Ihnen übergebene vorbereitete SQL-Anweisung vom Datenbankserver analysiert und kompiliert wird? Teilen Sie der Datenbank-Engine mit, was Sie filtern möchten, indem Sie Zeichen angeben (wie „?“ oder „:name“ im obigen Beispiel). Rufen Sie dann „execute“ auf, um die vorbereitete Anweisung in Kombination mit dem von Ihnen angegebenen Parameterwert auszuführen
Das Wichtigste hierbei ist, dass der Parameterwert mit einer vorkompilierten Anweisung und nicht mit einem SQL-String kombiniert wird. Die SQL-Injection funktioniert, indem sie fälschlicherweise ein SQL-Skript erstellt, das einen bösartigen String enthält, und ihn daher durch Senden eines tatsächlichen Werts an die Datenbank sendet Durch separate SQL-Parameter verringern Sie das Risiko. Wenn Sie vorbereitete Anweisungen verwenden, werden alle von Ihnen gesendeten Parameter nur als Zeichenfolgen behandelt (obwohl die Datenbank-Engine möglicherweise einige Parameteroptimierungen durchführt, die im obigen Beispiel natürlich als Zahl enden können). Wenn die Variable $name beispielsweise „sarah“;DELETE * FROM Mitarbeiter enthält, ist das Ergebnis nur die Suchzeichenfolge „'sarah';DELETE * FROM Mitarbeiter“, 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, diese nur einmal analysiert und kompiliert wird, was zu einem gewissen Geschwindigkeitsgewinn führt.
Oh, und da Sie gefragt haben, wie die Einfügung erfolgt, finden Sie hier ein Beispiel (mit PDO):
<code><span>$preparedStatement</span><span>=</span><span>$db</span><span>-></span>prepare(<span>'INSERT INTO table (column) VALUES (:column)'</span>); <span>$preparedStatement</span><span>-></span>execute(<span>array</span>(<span>':column'</span><span>=></span><span>$unsafeValue</span>));</code>
http://www.jb51.net/article/36042.htmDas Obige stellt die Methode (2) zur Verhinderung der SQL-Injection in PHP vor, einschließlich der relevanten Inhalte. Ich hoffe, dass es für Freunde hilfreich ist, die sich für PHP-Tutorials interessieren.