Frage

Wenn eine Benutzereingabe ohne Modifikation in eine SQL-Abfrage eingefügt wird, dann wird die Anwendung anfällig für SQL Injektion , wie in der folgendes Beispiel:

$unsafe_variable = $_POST['user_input']; 

mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");

Das ist, weil der Benutzer kann so etwas wie value'); DROP TABLE table;--, und die Abfrage wird:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')

Was getan werden kann, zu verhindern?

War es hilfreich?

Lösung

Verwenden Sie vorbereitete Anweisungen und parametrisierte Abfragen. Es handelt sich um SQL-Anweisungen, die getrennt von Parametern durch den Datenbankserver und analysiert gesendet werden. Auf diese Weise ist es unmöglich für einen Angreifer bösartigen SQL zu injizieren.

Sie haben grundsätzlich zwei Möglichkeiten, dies zu erreichen:

  1. Mit PDO (für jeden Datenbank-Treiber unterstützt werden):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    
    $stmt->execute(array('name' => $name));
    
    foreach ($stmt as $row) {
        // do something with $row
    }
    
  2. Mit 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 eine andere Datenbank als MySQL sie verbinden, gibt es eine Treiber spezifische zweite Option, die Sie (z pg_prepare() und pg_execute() für PostgreSQL) beziehen können. PDO ist die universelle Option.

Korrekt der Verbindungsaufbau

Beachten Sie, dass, wenn PDO mit einer MySQL-Datenbank zuzugreifen real Prepared Statements sind nicht standardmäßig verwendet, . Um dies zu beheben Sie die Emulation der vorbereiteten Anweisungen deaktivieren. Ein Beispiel eine Verbindung zu schaffen PDO verwendet, ist:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Im obigen Beispiel des Fehlermodus nicht unbedingt erforderlich ist, , aber es wird empfohlen, es hinzuzufügen . Auf diese Weise wird das Skript nicht mit einem Fatal Error zu stoppen, wenn etwas schief geht. Und es gibt dem Entwickler die Möglichkeit, einen Fehler catch (n), die als throws PDOExceptionn werden.

Was ist obligatorisch , jedoch ist die erste setAttribute() Linie, die PDO sagt vorbereitete Anweisungen emuliert zu deaktivieren und verwenden real Aussagen vorbereitet. Dies stellt sicher, dass die Aussage und die Werte werden nicht von PHP analysiert, bevor es mit dem MySQL-Server (was einem möglichen Angreifer keine Chance zu injizieren bösartige SQL) zu senden.

Obwohl Sie die charset in den Optionen des Konstruktor festlegen können, ist es wichtig, dass ‚ältere‘ zu beachten, PHP-Versionen (<5.3.6) still die Parameter charset im DSN ignoriert.

Erklärung

Was passiert, ist, dass die SQL-Anweisung Sie prepare passieren wird vom Datenbankserver analysiert und zusammengestellt. Durch die Angabe von Parametern (entweder eine ? oder einen benannten Parameter wie :name im Beispiel oben) können Sie die Datenbank-Engine sagen, wo Sie filtern möchten. Dann, wenn Sie execute aufrufen, wird die vorbereitete Anweisung mit den Parameterwerten kombiniert Sie angeben.

Das Wichtigste dabei ist, dass die Parameterwerte mit der kompilierten Anweisung kombiniert werden, nicht eine SQL-Zeichenfolge. SQL-Injection funktioniert, indem Sie das Skript in böswillige Strings austricksen, wenn es SQL erstellt, um die Datenbank zu senden. So durch die tatsächliche SQL getrennt von den Parametern zu senden, begrenzen Sie das Risiko von Ende mit etwas, das Sie nicht der Absicht. Alle Parameter, die Sie senden, wenn eine vorbereitete Anweisung wird nur als Zeichenfolgen behandelt werden (obwohl der Datenbank-Engine einige Optimierungen tun kann, um Parameter wie Zahlen können am Ende natürlich auch). In dem obigen Beispiel, wenn die $name Variable enthält 'Sarah'; DELETE FROM employees das Ergebnis einfach eine Suche nach dem Zeichenfolge "'Sarah'; DELETE FROM employees" sein würde, und Sie werden nicht mit $preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)'); $preparedStatement->execute(array('column' => $unsafeValue));

Können vorbereitete Anweisungen für dynamische Abfragen verwendet werden?

Während Sie noch vorbereitete Anweisungen für die Abfrageparameter verwenden können, um die Struktur der dynamischen Abfrage itself kann nicht parametrisiert und bestimmte Abfragefunktionen können nicht parametrisiert werden.

Für diese speziellen Szenarien, das Beste, was zu tun ist, einen Whitelist-Filter verwenden, die die möglichen Werte beschränkt.

// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}

Andere Tipps

  

Veraltete Warnung:   Dieser Beispielcode Antwort (wie der Beispielcode Frage) verwendet PHP MySQL Erweiterung, die in PHP 5.5.0 und entfernt vollständig in PHP 7.0.0 veraltet wurde.

     

Sicherheitswarnung : Diese Antwort ist mit Sicherheit am besten Praktiken nicht im Einklang. Flüchten ist unzureichend SQL-Injection vermeiden, verwenden Sie Prepared Statements statt. Verwenden Sie die Strategie umrissen unten auf eigene Gefahr. (Auch mysql_real_escape_string() wurde in PHP 7 entfernt.)

Wenn Sie eine aktuelle Version von PHP verwenden, die mysql_real_escape_string Option unten beschrieben wird nicht mehr verfügbar sein (obwohl mysqli::escape_string ein modernes Äquivalent). In diesen Tagen der mysql_real_escape_string Option würde nur Sinn für Legacy-Code auf einer alten Version von PHP machen.


Sie haben zwei Möglichkeiten, - die Sonderzeichen in Ihrem unsafe_variable entkommen, oder eine parametrisierte Abfrage verwenden. Beide würden Sie von SQL-Injection schützen. Die parametrisierte Abfrage wird die bessere Praxis angesehen, aber wird auf eine neuere MySQL-Erweiterung in PHP zu ändern müssen, bevor Sie es verwenden können.

Wir decken den unteren Schlag Zeichenfolge zu entkommen zuerst.

//Connect

$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);

mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

//Disconnect

Siehe auch die Details der mysql_real_escape_string Funktion.

Um die parametrisierte Abfrage zu verwenden, müssen Sie verwenden MySQLi statt der MySQL Funktionen. Um Ihr Beispiel zu umschreiben, würden wir so etwas wie die folgenden benötigen.

<?php
    $mysqli = new mysqli("server", "username", "password", "database_name");

    // TODO - Check that connection was successful.

    $unsafe_variable = $_POST["user-input"];

    $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");

    // TODO check that $stmt creation succeeded

    // "s" means the database expects a string
    $stmt->bind_param("s", $unsafe_variable);

    $stmt->execute();

    $stmt->close();

    $mysqli->close();
?>

Die Schlüsselfunktion wollen Sie auf lesen, es würde mysqli::prepare .

Auch, wie andere vorgeschlagen haben, finden Sie kann es sinnvoll / leichter eine Abstraktionsschicht mit etwas zu intensivieren wie PDO .

Bitte beachten Sie, dass der Fall, dass Sie gefragt ein ziemlich einfaches ist und dass komplexeren Fälle können komplexere Ansätze erfordern. Insbesondere gilt Folgendes:

  • Wenn Sie die Struktur des SQL basierend auf Benutzereingaben verändern wollen, werden parametrisierte Abfragen nicht helfen, und die erforderlichen Umschreibungen von mysql_real_escape_string nicht abgedeckt ist. In dieser Art von Fall würden Sie besser dran, die Eingabe des Benutzers, die durch eine weiße Liste sind nur ‚sichere‘ Werte durchgelassen zu gewährleisten.
  • Wenn Sie ganze Zahlen von Benutzereingaben in einem Zustand verwendet werden und den mysql_real_escape_string Ansatz nehmen, werden Sie von dem Problem von Polynomial beschrieben leiden in den Kommentaren unten. Dieser Fall ist schwieriger, weil ganze Zahlen nicht in Anführungszeichen gesetzt werden würde, so könnten Sie befassen sich mit durch die Validierung, dass die Benutzereingabe nur Ziffern enthält.
  • Es gibt wahrscheinlich auch andere Fälle, die ich bin mir nicht bewusst. Vielleicht finden Sie diese ist eine nützliche Ressource auf einige der subtileren Probleme auftreten können .

Jede Antwort hier nur ein Teil des Problems. In der Tat gibt es vier verschiedene Abfrage Teile, die wir hinzufügen können dynamisch: -

  • eine Zeichenfolge
  • eine Zahl
  • eine Kennung
  • eine Syntax Schlüsselwort.

Und vorbereitete Anweisungen decken nur zwei von ihnen.

Aber manchmal müssen wir unsere Abfrage noch dynamischer machen, das Hinzufügen Betreiber oder Kennungen sowie. So werden wir verschiedene Schutztechniken benötigen.

Im Allgemeinen wird ein solcher Schutz Ansatz basiert auf weiße Listen .

In diesem Fall wird jeder dynamischer Parameter soll aus diesem Satz in Ihrem Skript und ausgewählt fest einprogrammiert werden. Zum Beispiel dynamische Ordnung zu tun:

$orders  = array("name", "price", "qty"); // Field names
$key     = array_search($_GET['sort'], $orders)); // See if we have such a name
$orderby = $orders[$key]; // If not, first one will be set automatically. smart enuf :)
$query   = "SELECT * FROM `table` ORDER BY $orderby"; // Value is safe

Allerdings gibt es eine weitere Möglichkeit, Kennungen zu sichern - zu entkommen. Solange Sie eine Kennung angegeben haben, können Sie Backticks innerhalb entkommen, indem sie zu verdoppeln.

Als weiterer Schritt können wir eine wirklich geniale Idee mit einigen Platzhalter borgen (einen Proxy den tatsächlichen Wert in der Abfrage darzustellen) aus den vorbereiteten Anweisungen und einen Platzhalter eines anderen Typs erfinden -. Eine Kennung Platzhalter

Also, um die lange Geschichte kurz. Es ist ein Platzhalter , nicht vorbereitete Anweisung kann als Allheilmittel betrachtet werden

So kann eine allgemeine Empfehlung als formulieren Solange Sie dynamische Teile auf die Abfrage mit Platzhalter hinzufügen (und diese Platzhalter natürlich ebenfalls richtig verarbeitet), können Sie sicher sein, dass Ihre Abfrage sicher .

Dennoch gibt es ein Problem mit SQL-Syntax Schlüsselwort (wie AND, DESC und so weiter), aber White-Listing scheint den einzigen Ansatz in diesem Fall.

Update

Es gibt zwar eine allgemeine Einigung über die besten Praktiken in Bezug auf SQL-Injection-Schutz gibt es immer noch viele schlechte Praktiken als auch. Und einige von ihnen zu tief in den Köpfen der PHP-Benutzer verwurzelt. Zum Beispiel auf dieser Seite sehr gibt es (wenn auch unsichtbar für die meisten Besucher) Mehr als 80 gelöscht Antworten - alle von der Gemeinschaft aufgrund der schlechten Qualität entfernt oder schlecht und veraltete Praktiken zu fördern. Schlimmer noch, sind einige der schlechten Antworten nicht gelöscht, sondern Gedeihen.

Zum Beispiel dort (1) (2) sind noch (3) viele (4) Antworten (5) , einschließlich der second meisten upvoted Antwort manuelle Zeichenfolge Entkommen was darauf hindeutet, -. ein veralteter Ansatz, die nachweislich unsicher sein

Oder gibt es eine etwas bessere Antwort, die nur eine andere Methode der String-Formatierung schlägt und sogar bietet es als das ultimative Allheilmittel. Während natürlich ist es nicht. Diese Methode ist nicht besser als normale Zeichenfolge Formatierung, aber es hält alle ihre Nachteile: sie Strings ist nur anwendbar und, wie jede andere manuelle Formatierung, es ist im Wesentlichen optional, nicht obligatorische Maßnahme, anfällig für menschliche Fehler jeglicher Art.

Ich denke, dass all dies wegen eines sehr alten Aberglaube, unterstützt von solchen Behörden wie OWASP oder das PHP-Handbuch , die von SQL-Injections Gleichstellung von was auch immer "Flucht" und Schutz verkündet.

Unabhängig davon, was PHP-Handbuch, sagte für Alter, *_escape_string auf keinen Fall macht Daten sicher und nie gedacht worden ist. Abgesehen davon, dass für jeden SQL-pa nutzlosrt andere als Zeichenkette, manuelles Entkommen ist falsch, weil es Handbuch ist als gegenüber automatisierte.

Und OWASP macht es noch schlimmer, zu entkommen Betonung auf Benutzereingabe , die ein völliger Unsinn ist: Es sollte im Zusammenhang mit der Injektion Schutz keine solche Worte. Jede Variable ist potentiell gefährlich - unabhängig von der Quelle! Oder mit anderen Worten - hat jede Variable richtig formatiert werden, in eine Abfrage werden - unabhängig von der Quelle wieder. Es ist das Ziel, das zählt. In dem Moment, ein Entwickler beginnt die Schafe zu trennen von den Böcken (Denken, ob einige bestimmte Variable „sicher“ ist oder nicht), er / sie seine / ihre erste Schritt zur Katastrophe führt. Ganz zu schweigen davon, dass auch die Formulierung am Einspeisepunkt Masse legt nahe, Flucht, ähnlich das sehr Magic Quotes verfügen -. Bereits verachteter, veraltete und entfernt

So, im Gegensatz zu, was auch immer "Flucht", Prepared Statements ist die Maßnahme, die in die Tat von SQL-Injection schützt (wenn zutreffend).

Wenn Sie immer noch nicht überzeugt, hier sind ein Schritt-für-Schritt-Erklärung, die ich geschrieben habe, Per Anhalter zu SQL Injection Prävention , wo ich all diese Dinge im Detail erläutert und auch einen Abschnitt ganz gewidmet schlechte Praktiken und deren Veröffentlichung.

kompiliert

Ich würde empfehlen, PDO (PHP Data Objects) zu laufen parametrisierte SQL-Abfragen.

Nicht nur schützt diese vor SQL-Injection, es auch Abfragen beschleunigt.

Und von PDO mit eher als mysql_, mysqli_ und pgsql_ Funktionen, machen Sie Ihre Anwendung ein wenig mehr aus der Datenbank abstrahiert, in seltenen Vorkommen, dass Sie Datenbank-Anbieter wechseln.

Mit PDO und vorbereiteten Abfragen.

($conn ist ein PDO Objekt)

$stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':name', $name);
$stmt->execute();

Wie Sie sehen können, die Menschen vorschlagen, dass Sie am meisten vorbereitete Anweisungen verwenden. Es ist nicht falsch, aber wenn Ihre Abfrage ausgeführt wird nur einmal pro Prozess, würde es eine leichte Leistungseinbußen sein.

ich dieses Problem konfrontiert war, aber ich glaube, ich löste es in sehr anspruchsvoller Art und Weise - die Art und Weise Hacker mit Anführungszeichen zu vermeiden, verwenden. Ich habe diese in Verbindung mit emulierte vorbereiteten Anweisungen. Ich benutze es, zu verhindern, dass alle Arten von möglichen SQL-Injection-Angriffen.

Mein Ansatz:

  • Wenn Sie Eingabe erwarten integer zu sein, stellen Sie sicher, es ist wirklich integer. In einer Variablen-Typ Sprache wie PHP ist es dieses sehr wichtig. Sie können zum Beispiel verwenden diese sehr einfache, aber leistungsfähige Lösung: sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);

  • Wenn Sie etwas anderes aus integer erwarten verhexen es . Wenn Sie es verhexen, werden Sie perfekt alle Eingaben entkommen. In C / C ++ gibt es eine Funktion namens mysql_hex_string() , in PHP können Sie verwenden bin2hex() .

    Sie befürchten nicht, dass der maskierte String eine 2x Größe seiner ursprünglichen Länge haben, denn selbst wenn Sie mysql_real_escape_string verwenden, PHP gleiche Kapazität ((2*input_length)+1) zuzuweisen hat, die gleich ist.

  • Diese hex Methode oft verwendet, wenn Sie binäre Daten übertragen, aber ich sehe keinen Grund, warum es nicht auf alle Daten verwenden, um SQL-Injection-Angriffe zu verhindern. Beachten Sie, dass Sie Daten mit 0x vorangestellt haben oder verwenden Sie die MySQL-Funktion UNHEX statt.

So zum Beispiel der Abfrage:

SELECT password FROM users WHERE name = 'root'

Wird werden:

SELECT password FROM users WHERE name = 0x726f6f74

oder

SELECT password FROM users WHERE name = UNHEX('726f6f74')

Hex ist die perfekte Flucht. Kein Weg zu injizieren.

Differenz zwischen UNHEX Funktion und 0x Präfix

Es gab einige Diskussionen in den Kommentaren, so will ich endlich um deutlich machen. Diese beiden Ansätze sind sehr ähnlich, aber sie sind ein wenig anders in gewisser Weise:

Der ** 0x ** Präfix kann nur für Datenspalten wie char, varchar, text, block, binär, etc. verwendet werden .
Auch ist die Verwendung ein wenig kompliziert, wenn Sie im Begriff sind, eine leere Zeichenfolge einzufügen. Sie werden völlig es haben mit '' zu ersetzen, oder Sie eine Fehlermeldung erhalten.

UNHEX () arbeitet auf jeder Säule; Sie müssen nicht über die leere Zeichenfolge kümmern.


Hex Methoden werden oft als Attacken

Beachten Sie, dass diese Hex-Methode oft als SQL-Injection-Angriff verwendet wird, wo ganze Zahlen sind wie Strings und entkam nur mit mysql_real_escape_string. Dann können Sie die Verwendung von Zitaten vermeiden.

Zum Beispiel, wenn Sie nur so etwas tun:

"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])

ein Angriff können Sie injizieren sehr leicht . Betrachten Sie die folgende injizierte Code aus Ihrem Skript zurückgegeben:

  

SELECT ... WHERE id = -1 union all select table_name aus INFORMATION_SCHEMA.TABLES

und jetzt nur noch Tabellenstruktur extrahieren:

  

SELECT ... WHERE id = -1 union all select Spalten von information_schema.column wo table_name = 0x61727469636c65

Und dann wählen Sie einfach alle Daten, diejenigen wollen. Ist es nicht cool?

Aber wenn der Codierer einer injizierbaren Website es verhexen würde, wäre keine Injektion möglich, da die Abfrage würde wie folgt aussehen: SELECT ... WHERE id = UNHEX('2d312075...3635')

  

Veraltete Warnung:   Dieser Beispielcode Antwort (wie der Beispielcode Frage) verwendet PHP MySQL Erweiterung, die in PHP 5.5.0 und entfernt vollständig in PHP 7.0.0 veraltet wurde.

     

Sicherheitswarnung : Diese Antwort ist mit Sicherheit am besten Praktiken nicht im Einklang. Flüchten ist unzureichend SQL-Injection vermeiden, verwenden Sie Prepared Statements statt. Verwenden Sie die Strategie umrissen unten auf eigene Gefahr. (Auch mysql_real_escape_string() wurde in PHP 7 entfernt.)

     

Wichtig

     

Der beste Weg, SQL Injection zu verhindern, ist die Verwendung Prepared Statements statt Flucht , wie die akzeptierte Antwort demonstriert.

     

Es gibt Bibliotheken wie Aura.Sql und EasyDB , die es Entwicklern ermöglichen, einfacher vorbereitete Anweisungen zu verwenden. Um mehr zu erfahren, warum Prepared Statements sind besser auf die SQL-Injection Stoppen finden href="https://stackoverflow.com/a/12118602/2224584"> diese mysql_real_escape_string() Bypass und vor kurzem Unicode SQL-Injection-Schwachstellen in Wordpress Fest

Injection Prävention - mysql_real_escape_string ()

PHP hat eine speziell angefertigten Funktion, um diese Angriffe zu verhindern. Alles was Sie tun müssen, ist die Bissen einer Funktion, mysql_real_escape_string verwenden.

mysql_real_escape_string nimmt eine Zeichenfolge, die in einer MySQL-Abfrage und gibt die gleiche Zeichenfolge mit allen SQL-Injection-Versuche sicher entkommen verwendet werden wird. Grundsätzlich wird es diese lästigen Anführungszeichen ersetzen ( ‚) ein Benutzer mit einem MySQL-sicheren Ersatz geben könnte, ein entflohener Anführungszeichen \‘.

Hinweis: Sie müssen mit der Datenbank verbunden sein, um diese Funktion zu nutzen

!

// Verbindung zu MySQL

$name_bad = "' OR 1'"; 

$name_bad = mysql_real_escape_string($name_bad);

$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";


$name_evil = "'; DELETE FROM customers WHERE 1 or username = '"; 

$name_evil = mysql_real_escape_string($name_evil);

$query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
echo "Escaped Evil Injection: <br />" . $query_evil;

Sie finden weitere Details in finden MySQL - SQL-Injection Prävention .

  

Veraltete Warnung:   Dieser Beispielcode Antwort (wie der Beispielcode Frage) verwendet PHP MySQL Erweiterung, die in PHP 5.5.0 und entfernt vollständig in PHP 7.0.0 veraltet wurde.

     

Sicherheitswarnung : Diese Antwort ist mit Sicherheit am besten Praktiken nicht im Einklang. Flüchten ist unzureichend SQL-Injection vermeiden, verwenden Sie Prepared Statements statt. Verwenden Sie die Strategie umrissen unten auf eigene Gefahr. (Auch mysql_real_escape_string() wurde in PHP 7 entfernt.)

Sie könnten etwas Grundsätzliches wie folgt tun:

$safe_variable = mysqli_real_escape_string($_POST["user-input"], $dbConnection);
mysqli_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

Das wird nicht jedes Problem lösen, aber es ist ein sehr gutes Sprungbrett. Ich verließ aus offensichtlichen Elementen wie die Variable Existenz Überprüfung Format (Zahlen, Buchstaben, usw.).

Was auch immer Sie am Ende mit, stellen Sie sicher, dass Sie Ihre Eingaben überprüfen wurde von magic_quotes oder einem anderen gut gemeinten Müll und, wenn nötig, führen Sie es durch stripslashes oder was auch immer sanieren es nicht bereits verstümmelt.

  

Veraltete Warnung:   Dieser Beispielcode Antwort (wie der Beispielcode Frage) verwendet PHP MySQL Erweiterung, die in PHP 5.5.0 und entfernt vollständig in PHP 7.0.0 veraltet wurde.

     

Sicherheitswarnung : Diese Antwort ist mit Sicherheit am besten Praktiken nicht im Einklang. Flüchten ist unzureichend SQL-Injection vermeiden, verwenden Sie Prepared Statements statt. Verwenden Sie die Strategie umrissen unten auf eigene Gefahr. (Auch mysql_real_escape_string() wurde in PHP 7 entfernt.)

parametrisierte Abfrage und Eingabevalidierung ist der Weg zu gehen. Es gibt viele Szenarien, unter denen SQL-Injektion auftreten können, obwohl mysql_real_escape_string() verwendet wurde.

Diese Beispiele sind anfällig für SQL-Injection:

$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
RunQuery("SELECT userid, username FROM sql_injection_test LIMIT $offset, 10");

oder

$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
RunQuery("SELECT userid, username FROM sql_injection_test ORDER BY `$order`");

In beiden Fällen können Sie nicht ' verwenden, um die Verkapselung zu schützen.

Quelle : The Unexpected SQL Injection (Wenn entweichende nicht genügend)

Meiner Meinung nach sind der beste Weg, um im allgemeinen SQL-Injection in Ihrer PHP-Anwendung (oder eine Web-Anwendung, was das betrifft) zu verhindern, ist über die Anwendung der Architektur zu denken. Wenn die einzige Möglichkeit, gegen SQL-Injection zu schützen, ist daran zu erinnern, eine spezielle Methode oder eine Funktion zu verwenden, der das Richtige tut jedes Mal, wenn Sie in die Datenbank zu sprechen, tun Sie es falsch. Auf diese Weise ist es nur eine Frage der Zeit, bis Sie die korrekte Schreibweise Ihre Abfrage zu einem bestimmten Zeitpunkt in Ihrem Code formatiert werden vergessen.

Die Annahme der MVC-Muster und einen Rahmen wie CakePHP oder CodeIgniter ist wahrscheinlich der richtige Weg zu gehen: Gemeinsame Aufgaben wie das Erstellen sichere Datenbankabfragen gelöst wurden und zentral in einem solchen Rahmen durchgeführt. Sie helfen Ihnen, Ihre Web-Anwendung in einer vernünftigen Art und Weise zu organisieren und machen Sie mehr über das Laden denken und Speichern von Objekten als sicher einzelne SQL-Abfragen.

Ich bin für gespeicherten Prozeduren ( MySQL gespeicherte Prozeduren von einer sicherheitstechnischen Sicht seit 5,0 ) unterstützt hat - die Vorteile sind -

  1. Die meisten Datenbanken (einschließlich MySQL ) Benutzerzugriff ermöglichen beschränkt werden gespeicherte Prozeduren ausgeführt werden. Die feinkörnige Sicherheit Zugangskontrolle ist nützlich Eskalation von Privilegien Angriffen zu verhindern. Dies verhindert, dass kompromittierte Anwendungen von der Möglichkeit, SQL direkt gegen die Datenbank ausgeführt werden.
  2. Sie abstrakt die rohe SQL-Abfrage aus der Anwendung so weniger Informationen der Datenbankstruktur sind für die Anwendung verfügbar. Dies macht es schwieriger für Menschen, die darunter liegende Struktur der Datenbank und Design geeignet Angriffe zu verstehen.
  3. Sie akzeptieren nur Parameter, so sind die Vorteile der parametrisierte Abfragen gibt. Natürlich - IMO müssen Sie noch Ihre Eingabe sanieren - vor allem, wenn Sie innerhalb der gespeicherten Prozedur dynamische SQL verwenden
  4. .

Die Nachteile sind -

  1. Sie (Stored Procedures) sind schwer zu halten und neigen dazu, sehr schnell zu vermehren. Das macht sie ein Problem zu verwalten.
  2. Sie sind nicht sehr geeignet für dynamische Abfragen - wenn sie gebaut werden viele der Vorteile negiert dynamischen Code als Parameter zu akzeptieren, dann
  3. .

Es gibt viele Möglichkeiten zu verhindern, SQL-Injektionen und anderes SQL-Hacks. Sie können es leicht finden im Internet (Google-Suche). Natürlich PDO ist eine der guten Lösungen. Aber ich möchte Ihnen einige gute Links Prävention von SQL-Injection suggerieren.

Was ist Injektion SQL und wie verhindern

PHP-Handbuch für SQL-Injection

Microsoft Erklärung von SQL-Injection und Prävention in PHP

und einige andere wie Verhindern von SQL-Injection mit MySQL und PHP

Jetzt , warum Sie tun, müssen Sie Ihre Abfrage von SQL-Injection verhindern?

würde Ich mag Sie wissen lassen: Warum versuchen wir zu verhindern, dass SQL-Injection mit einem kurzen Beispiel unter:

Abfrage für Login-Authentifizierung match:

$query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' ";

Nun, wenn jemand (ein Hacker) puts

$_POST['email']= admin@emali.com' OR '1=1

und Passwort etwas ....

Die Abfrage wird in das System analysiert werden nur bis zu:

$query="select * from users where email='admin@emali.com' OR '1=1';

Der andere Teil wird verworfen. Also, was wird passieren? Ein nicht autorisierter Benutzer (Hacker) wird in der Lage sein Admin melden Sie sich als ohne sein Passwort mit. Jetzt kann er alles tun, die admin / E-Mail-Person tun kann. Sehen Sie, es ist sehr gefährlich, wenn SQL-Injection nicht verhindert wird.

Ich denke, wenn jemand will, PHP und MySQL oder einen anderen Datenbank-Server verwenden:

  1. Denken Sie über das Lernen PDO (PHP Data Objects) - es ist eine Datenbank-Zugriffsschicht eine einheitliche Bereitstellung Verfahren zum Zugriff auf mehrere Datenbanken.
  2. Denken Sie über das Lernen MySQLi
  3. Verwenden Sie nativen PHP-Funktionen wie: strip_tags , mysql_real_escape_string oder wenn die Variable numerisch, nur (int)$foo. Lesen Sie mehr über Art von Variablen in PHP hier . Wenn Sie Bibliotheken wie PDO oder MySQLi, verwenden Sie immer PDO :: quote () und < a href = "http://php.net/manual/en/mysqli.real-escape-string.php"> mysqli_real_escape_string () .

Bibliotheken Beispiele:

---- PDO

  

----- keine Platzhalter - reif für SQL-Injection! Es ist schlecht

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");
  

----- Unbenannt Platzhalter

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);
  

----- Named Platzhalter

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");

--- MySQLi

$request = $mysqliConnection->prepare('
       SELECT * FROM trainers
       WHERE name = ?
       AND email = ?
       AND last_login > ?');

    $query->bind_param('first_param', 'second_param', $mail, time() - 3600);
    $query->execute();

P. S :

PDO gewinnt diesen Kampf mit Leichtigkeit. Mit der Unterstützung für zwölf verschiedene Datenbanktreiber und benannte Parameter, können wir das ignorieren kleiner Leistungsverlust und zu seiner API gewöhnen. Aus Sicherheits Standpunkt, beide sind sicher, solange der Entwickler nutzt sie die Art, wie sie sollen verwendet werden

Doch während beide PDO und MySQLi recht schnell sind, MySQLi führt unwesentlich schneller in Benchmarks - ~ 2,5% für nicht vorbereitet Aussagen und ~ 6,5% für präpariertes diejenigen.

Und bitte jede Frage zu Ihrer Datenbank testen -. Es ist eine bessere Art und Weise Injektion zu verhindern

Wenn möglich, werfen die Typen Ihrer Parameter. Aber es ist nur die Arbeit an einfachen Typen wie int, bool und Schwimmer.

$unsafe_variable = $_POST['user_id'];

$safe_variable = (int)$unsafe_variable ;

mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

Wenn Sie möchten die Vorteile von Cache-Maschinen nehmen, wie Redis oder < a href = "http://en.wikipedia.org/wiki/Memcached" rel = "noreferrer"> Memcached , vielleicht könnte DALMP eine Wahl sein. Es nutzt reine MySQLi . Sehen Sie sich diese. DALMP Database Abstraction Layer für MySQL mit PHP

Sie können aber auch ‚vorbereiten‘ Ihre Argumente vor Ihrer Anfrage vorbereitet, so dass Sie eine vollständig vorbereitete Anweisungen Abfrage dynamische Abfragen und am Ende haben aufbauen können. DALMP Database Abstraction Layer für MySQL mit PHP.

Für jene nicht sicher, wie PDO verwenden (aus den mysql_ Funktionen), habe ich ein sehr, sehr einfach PDO-Wrapper , dass eine einzelne Datei. Es besteht zu zeigen, wie einfach es ist, alle gängigen Dinge Anwendungen tun müssen getan werden. Kompatibel mit PostgreSQL, MySQL und SQLite.

Im Grunde, lesen Sie es , während Sie das Handbuch , um zu sehen wie Sie die PDO-Funktionen setzen im wirklichen Leben zu verwenden, machen es einfach Werte im Format speichern und abrufen Sie wollen.

  

Ich möchte eine einzelne Spalte

$count = DB::column('SELECT COUNT(*) FROM `user`);
     

Ich möchte ein Array (Schlüssel => Wert) ergibt (das heißt für die Herstellung einer Auswahlbox)

$pairs = DB::pairs('SELECT `id`, `username` FROM `user`);
     

Ich möchte eine einzelne Zeile Ergebnis

$user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));
     

Ich möchte eine Reihe von Ergebnissen

$banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));

Mit dieser PHP-Funktion mysql_escape_string() Sie können eine gute Prävention auf eine schnelle Art und Weise bekommen.

Zum Beispiel:

SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'

mysql_escape_string - ein String für die Verwendung in einem mysql_query

Für mehr Prävention, Sie am Ende hinzufügen ...

wHERE 1=1   or  LIMIT 1

Schließlich erhalten Sie:

SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1

Einige Richtlinien für die Sonderzeichen in SQL-Anweisungen zu entkommen.

Verwenden Sie keine MySQL , diese Erweiterung ist veraltet, verwenden MySQLi oder PDO .

MySQLi

Für manuell Sonderzeichen in einem String entkommen können Sie die mysqli_real_escape_string Funktion. Die Funktion funktioniert nicht richtig, es sei denn, der richtige Zeichensatz wird mit mysqli_set_charset .

Beispiel:

$mysqli = new mysqli( 'host', 'user', 'password', 'database' );
$mysqli->set_charset( 'charset');

$string = $mysqli->real_escape_string( $string );
$mysqli->query( "INSERT INTO table (column) VALUES ('$string')" );

Für die automatische Entkommen von Werten mit vorbereiteten Anweisungen verwenden mysqli_prepare , und mysqli_stmt_bind_param wo Typen für die entsprechenden Bindevariablen müssen vorgesehen für eine entsprechende Umwandlung:

Beispiel:

$stmt = $mysqli->prepare( "INSERT INTO table ( column1, column2 ) VALUES (?,?)" );

$stmt->bind_param( "is", $integer, $string );

$stmt->execute();

Egal ob Sie vorbereitete Anweisungen oder mysqli_real_escape_string verwenden, können Sie immer die Art der Eingabedaten müssen wissen, mit dem Sie arbeiten.

Wenn Sie also eine vorbereitete Anweisung verwenden, können Sie die Typen der Variablen für mysqli_stmt_bind_param Funktion angegeben werden muss.

Und die Verwendung von mysqli_real_escape_string ist, wie der Name schon sagt, in einer Reihe von Sonderzeichen zu entkommen, so wird es nicht ganze Zahlen sicher machen. Der Zweck dieser Funktion ist es, die Zeichenfolgen in SQL-Anweisungen zu verhindern, brechen, und die Schäden an der Datenbank, die es verursachen könnte. mysqli_real_escape_string ist eine nützliche Funktion, wenn sie richtig verwendet werden, insbesondere, wenn sie mit sprintf kombiniert.

Beispiel:

$string = "x' OR name LIKE '%John%";
$integer = '5 OR id != 0';

$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5

$integer = '99999999999999999999';
$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647

Die einfache Alternative zu diesem Problem könnte durch die Gewährung von entsprechenden Berechtigungen in der Datenbank selbst gelöst werden. Zum Beispiel: Wenn Sie eine MySQL-Datenbank verwenden, dann in die Datenbank durch Terminal eingeben oder zur Verfügung gestellten UI und folgen Sie einfach diesem Befehl ein:

 GRANT SELECT, INSERT, DELETE ON database TO username@'localhost' IDENTIFIED BY 'password';

Damit wird den Benutzer beschränkt nur mit der angegebenen Abfrage nur beschränkt werden. Entfernen Sie die Berechtigung Löschen und so würden die Daten nie aus der von der PHP-Seite gefeuert Abfrage gelöscht. Das zweite, was zu tun ist, die Privilegien zu spülen, so dass die MySQL die Berechtigungen und Updates aktualisiert wird.

FLUSH PRIVILEGES; 

Weitere Informationen über bündig .

die aktuellen Berechtigungen Um zu sehen, dass der Benutzer die folgende Abfrage ausgelöst.

select * from mysql.user where User='username';

Weitere Informationen über GRANT .

  

Sicherheitswarnung : Diese Antwort ist mit Sicherheit am besten Praktiken nicht im Einklang. Flüchten ist unzureichend SQL-Injection vermeiden, verwenden Sie Prepared Statements statt. Verwenden Sie die Strategie umrissen unten auf eigene Gefahr. (Auch mysql_real_escape_string() wurde in PHP 7 entfernt.)

     

Veraltete Warnung : Die MySQL-Erweiterung ist zu diesem Zeitpunkt veraltet. Wir empfehlen die Verwendung der PDO-Erweiterung

Ich benutze drei verschiedene Möglichkeiten, um meine Web-Anwendung zu verhindern, dass eine SQL-Injection verwundbar zu sein.

  1. Die Verwendung von mysql_real_escape_string(), die eine vordefinierte Funktion in PHP , und dieser Code fügen Sie Schrägstriche auf die folgenden Zeichen: \x00, \n, \r, \, ', " und \x1a. Führen Sie die Eingabewerte als Parameter die Möglichkeit von SQL-Injektion zu minimieren.
  2. Die modernste Art und Weise ist gU zu verwenden.

Ich hoffe, dies wird Ihnen 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 () wird hier nicht schützen. Wenn Sie einfache Anführungszeichen (‘‚) um Ihre Variablen innerhalb Ihrer Anfrage ist, was Sie gegen diese schützt. Hier ist eine Lösung unten folgt aus:

$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

Die Frage hat einige gute Antworten zu dies.

Ich schlage vor, mit PDO ist die beste Option.

Edit:

mysql_real_escape_string() als PHP 5.5.0 veraltet. Verwenden Sie entweder mysqli oder PDO.

Eine Alternative zu mysql_real_escape_string () ist

string mysqli_real_escape_string ( mysqli $link , string $escapestr )

Beispiel:

$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");

viele nützliche Antworten betrifft, so hoffe ich einige Werte auf diesen Thread hinzuzufügen. SQL-Injection ist ein Angriff, der durch Benutzereingaben (Eingänge, die vom Benutzer gefüllt und dann verwendet, innerhalb Abfragen), die SQL-Injection-Muster korrekt sind Abfragesyntax durchgeführt werden kann, während wir es nennen können: schlechte Abfragen für schlechte Gründe, gehen wir davon aus, dass es vielleicht sein, eine schlechte Person, die versucht, geheime Informationen zu erhalten (unter Umgehung Zugangskontrolle), die die drei Prinzipien der Sicherheit (Vertraulichkeit, Integrität, Verfügbarkeit) beeinflussen.

Nun, unser Punkt ist, Sicherheitsbedrohungen wie SQL-Injection-Angriffe zu verhindern, ist die Frage zu stellen (wie SQL-Injection-Angriff mit PHP verhindern), realistischer sein, Datenfilterung oder Eingangsdaten Clearing ist der Fall bei der Verwendung von Benutzereingaben Daten innerhalb eines solchen Abfrage mit PHP oder einer anderen Programmiersprache ist nicht der Fall ist, oder, wie von mehr Menschen empfohlen moderner Technik wie vorbereitete Anweisung oder andere Werkzeuge zu verwenden, die zur Zeit SQL-Injection-Prävention unterstützt, der Ansicht, dass diese Werkzeuge nicht mehr verfügbar? Wie Sie Ihre Anwendung sicher?

Mein Ansatz gegen SQL-Injection ist: Clearing-Benutzer-Eingabedaten, bevor sie in die Datenbank zu senden (bevor es in jeder Abfrage)

.

Datenfilterung für (unsichere Daten auf sichere Daten konvertieren) Bedenken Sie, dass PDO und MySQLi nicht verfügbar ist, wie können Sie Ihre Anwendung sicher? Hast du mich zwingen, sie zu benutzen? Was ist mit anderen Sprachen anders als PHP? Ich ziehe es allgemeine Ideen zu schaffen, wie es für breitere Grenze nicht nur für eine spezifische Sprache verwendet werden.

  1. SQL-Benutzer (Begrenzung Benutzerberechtigungen): am häufigsten SQL-Operationen sind (SELECT, UPDATE, INSERT), dann, warum ein Benutzer UPDATE-Privileg zu geben, dass es nicht erforderlich? Zum Beispiel Login und Suchergebnisseiten verwenden nur SELECT, dann, warum mit DB-Benutzer auf diesen Seiten mit hohen Privilegien? RULE:. Nicht für alle Privilegien, für alle SQL-Operationen eines Datenbankbenutzer erstellen, können Sie Ihr Schema wie (deluser, Select, Updateuser) als Benutzername für die einfache Nutzung erstellen

finden Sie unter Prinzip der geringst möglichen Privilegien

  1. Datenfilterung: bevor Sie eine Abfrage von Benutzereingaben Aufbau sollte für Programmierer validiert und gefiltert werden, ist es wichtig, einige Eigenschaften für jeden Benutzer-Eingabevariablen zu definieren: Datentyp, Datenmuster und Datenlänge . ein Feld, das eine Zahl zwischen (x und y) muss genau mit dem genauen Regel validiert wird, für ein Feld, das eine Zeichenkette (Text) ist: Muster der Fall ist, zum Beispiel Benutzername kann einige Zeichen enthalten, müssen nur sagen, [a- zA-Z0-9_-.] die Länge variiert zwischen (x und n), wobei x und n (ganze Zahlen, x <= n). Regel: die Schaffung sind genaue Filter und Prüfregeln für mich best practice

  2. .
  3. Mit anderen Tool: Hier werde ich auch mit Ihnen überein, dass vorbereitete Anweisung (parametrisierte Abfrage) und Stored Procedures, hier die Nachteile diese Art und Weise ist, erfordert fortgeschrittene Fähigkeiten, die für die meisten Benutzer nicht vorhanden ist, die Grundidee hier hier nichts zu der ursprünglichen Abfrage hinzufügen, wie (keine oder x = x) zwischen der SQL-Abfrage und den Daten zu unterscheiden, die im Innern verwendet wird, können beide Ansätze auch bei unsicheren Daten verwendet werden, da die Benutzer-Eingabedaten. Weitere Informationen finden Sie OWASP SQL-Injection-Prevention-Spickzettel .

Nun, wenn Sie ein erfahrener Benutzer sind, mit dieser Verteidigung beginnen, wie Sie möchten, aber für Anfänger, wenn sie nicht schnell gespeicherte Prozedur implementieren können und die Erklärung vorbereitet, ist es besser, Eingangsdaten zu filtern, so viel sie können.

Schließlich wollen wir, dass betrachtenBenutzer sendet diesen Text stattdessen 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'

Dieser Eingang kann ohne vorbereitete Anweisung und Stored Procedures frühzeitig überprüft werden, aber auf der sicheren Seite zu sein, sie beginnt nach Benutzer-Datenfilterung und Validierung verwendet wird.

Der letzte Punkt erkennt unerwartetes Verhalten, das mehr Aufwand und Komplexität erfordert; es ist nicht für normale Web-Anwendungen empfohlen. Unerwartetes Verhalten in über Benutzereingabe ist SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA, Wurzel, sobald diese Worte erkannt, können Sie die Eingabe vermeiden.

UPDATE1:

Ein Benutzer kommentierte, dass dieser Beitrag nutzlos, OK! Hier ist, was OWASP.ORG bereitgestellt:

  

Primär Verteidigung:
   
      Option 1: Die Verwendung von Prepared Statements (parametrisierte Abfragen)
      Option 2: Die Verwendung von Stored Procedures
      Option # 3: Austretende alle Benutzer definiert Eingang
   
  Zusätzliche Verteidigung:
   
      Auch Erzwingen: Least Privilege
      Führen Sie auch: Weiße Liste Eingabevalidierung

Wie Sie vielleicht wissen, behauptet ein Artikel sollte durch gültiges Argument gestützt werden, mindestens eine Referenz! Ansonsten gilt es als als Angriff und schlechten Anspruch!

Update2:

Von der PHP-Handbuch, PHP: Prepared Statements - Handbuch :

  

Escaping und SQL-Injection-

     

Bound Variablen werden automatisch vom Server entkommen. Das   Server fügt ihre entkam Werte an den entsprechenden Stellen in der   Anweisung Vorlage vor der Ausführung. Ein Hinweis muss die zur Verfügung gestellt werden   Server für die Art der gebundenen Variablen, eine geeignete zu erstellen   Umwandlung. Siehe die mysqli_stmt_bind_param () Funktion für mehr   Information.

     

Die automatische Entkommen von Werten innerhalb des Servers ist manchmal   eine Sicherheitsfunktion als SQL-Injection zu verhindern. Das Gleiche   Sicherheitsgrad kann mit nicht vorbereiteten Anweisungen erreicht werden, wenn   Eingabewerte richtig entkommen.

Update3:

Ich habe Testfälle für zu wissen, wie PDO und MySQLi die Abfrage an den MySQL-Server senden, wenn vorbereitete Anweisung:

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));

Query 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();

Query 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 Erklärung auch die Daten entweicht, sonst nichts.

Wie auch in der obigen Aussage The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly erwähnt, daher beweist dies, dass die Datenvalidierung wie intval() ist eine gute Idee für ganzzahlige Werte, bevor sie eine Abfrage zu senden, aber auch vor böswilliger Benutzer Daten verhindern, dass die Abfrage zu senden ist korrekt und brauchbares Konzept .

Bitte beachten Sie, diese Frage für weitere Einzelheiten: sendet PDO raw Anfrage an MySQL während Mysqli vorbereitete Abfrage sendet, die beide das gleiche Ergebnis

Referenzen:

  1. SQL-Injection-Spickzettel
  2. SQL Injection
  3. Informationssicherheit
  4. Sicherheit Principles
  5. Datenvalidierung

Eine einfache Möglichkeit wäre, einen PHP-Framework verwenden wie CodeIgniter oder Laravel die wie Filterung und aktive Datensatz eingebaute Funktionen haben, so dass Sie sich um diese Nuancen keine Sorge.

** Achtung: Der Ansatz in dieser Antwort beschrieben gilt nur ganz bestimmte Szenarien und nicht sicher ist, da SQL-Injection-Angriffe nicht nur verlassen können X=Y injizieren auf sein **

.

Wenn die Angreifer versuchen, in Form zu hacken über PHP $_GET Variable oder mit der Query-String-URL, würden Sie in der Lage sein, sie zu fangen, wenn sie nicht sicher.

RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
RewriteRule ^(.*) ^/track.php

Da 1=1, 2=2, 1=2, 2=1, 1+1=2, etc ... sind die häufigsten Fragen zu einer SQL-Datenbank eines Angreifers. Vielleicht auch wird es von vielen Hacking-Anwendungen verwendet wird.

Aber man muss vorsichtig sein, dass Sie eine sichere Abfrage von Ihrer Website neu schreiben müssen. Der obige Code Sie eine Spitze geben, neu zu schreiben oder umleiten (es hängt von Ihnen ab) , dass Hacking-spezifischen dynamischen Abfrage-String in eine Seite, die die a href des Angreifers speichert <= "http: // en.wikipedia.org/wiki/IP_address“rel =‚noreferrer‘> IP-Adresse , oder sogar ihre Cookies, Verlauf, im Browser oder andere sensible Informationen, so dass Sie mit ihnen später ihr Konto umgehen können durch das Verbot oder Kontakt mit Behörden.

Es gibt so viele Antworten für PHP und MySQL , aber hier ist der Code für PHP und Oracle zur Verhinderung von SQL-Injection sowie regelmäßige Verwendung von oci8 Treiber:

$conn = oci_connect($username, $password, $connection_string);
$stmt = oci_parse($conn, 'UPDATE table SET field = :xx WHERE ID = 123');
oci_bind_by_name($stmt, ':xx', $fieldval);
oci_execute($stmt);

Eine gute Idee ist es, ein 'objektrelationalen Mapper' zu verwenden, wie Idiorm

$user = ORM::for_table('user')
->where_equal('username', 'j4mie')
->find_one();

$user->first_name = 'Jamie';
$user->save();

$tweets = ORM::for_table('tweet')
    ->select('tweet.*')
    ->join('user', array(
        'user.id', '=', 'tweet.user_id'
    ))
    ->where_equal('user.username', 'j4mie')
    ->find_many();

foreach ($tweets as $tweet) {
    echo $tweet->text;
}

Es spart nicht nur von SQL-Injektionen, aber von Syntaxfehlern auch! Unterstützt auch Sammlungen von Modellen mit Methode Verkettungs filtern oder anwenden Aktionen, um mehrere Ergebnisse auf einmal und mehreren Verbindungen.

  

Veraltete Warnung:   Dieser Beispielcode Antwort (wie der Beispielcode Frage) verwendet PHP MySQL Erweiterung, die in PHP 5.5.0 und entfernt vollständig in PHP 7.0.0 veraltet wurde.

     

Sicherheitswarnung : Diese Antwort ist mit Sicherheit am besten Praktiken nicht im Einklang. Flüchten ist unzureichend SQL-Injection vermeiden, verwenden Sie Prepared Statements statt. Verwenden Sie die Strategie umrissen unten auf eigene Gefahr. (Auch mysql_real_escape_string() wurde in PHP 7 entfernt.)

Mit PDO und mySQLi ist eine gute Praxis, SQL-Injektionen zu verhindern, aber wenn Sie wirklich mit MySQL-Funktionen und Abfragen arbeiten wollen, wäre es besser, zu verwenden,

mysql_real_escape_string

$unsafe_variable = mysql_real_escape_string($_POST['user_input']);

Es gibt mehr Möglichkeiten, dies zu verhindern: wie zu identifizieren - wenn die Eingabe eine Zeichenkette, Zahl, Zeichen oder ein Array ist, gibt es so viele eingebauten Funktionen sind, dies zu erkennen. Auch wäre es besser, diese Funktionen zu nutzen Eingangsdaten überprüfen.

is_string

$unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');

is_numeric

$unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');

Und es ist so viel besser, diese Funktionen zu nutzen Eingangsdaten mit mysql_real_escape_string überprüfen.

Ich habe diese kleine Funktion mehrere Jahre geschrieben vor:

function sqlvprintf($query, $args)
{
    global $DB_LINK;
    $ctr = 0;
    ensureConnection(); // Connect to database if not connected already.
    $values = array();
    foreach ($args as $value)
    {
        if (is_string($value))
        {
            $value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'";
        }
        else if (is_null($value))
        {
            $value = 'NULL';
        }
        else if (!is_int($value) && !is_float($value))
        {
            die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.');
        }
        $values[] = $value;
        $ctr++;
    }
    $query = preg_replace_callback(
        '/{(\\d+)}/', 
        function($match) use ($values)
        {
            if (isset($values[$match[1]]))
            {
                return $values[$match[1]];
            }
            else
            {
                return $match[0];
            }
        },
        $query
    );
    return $query;
}

function runEscapedQuery($preparedQuery /*, ...*/)
{
    $params = array_slice(func_get_args(), 1);
    $results = runQuery(sqlvprintf($preparedQuery, $params)); // Run query and fetch results.   
    return $results;
}

Dies ermöglicht Aussagen in einem Einzeiler C # -ish String.Format wie Laufen:

runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);

Es entweicht unter Berücksichtigung der Variablentyp. Wenn Sie versuchen, Tabelle, Spaltennamen zu parametrieren, es würde scheitern, da es jede Zeichenfolge in Anführungszeichen setzt, die eine ungültige Syntax ist.

SECURITY UPDATE: Die bisherige str_replace Version erlaubt Injektionen durch Zugabe von {#} Token in Benutzerdaten. Diese preg_replace_callback Version keine Probleme verursachen, wenn der Ersatz diese Token enthält.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top