Wie kann ich verhindern, dass SQL-injection in PHP?
Wenn Benutzereingaben eingefügt werden, ohne die änderung in eine SQL-Abfrage, dann die Anwendung wird Sie anfällig für SQL-injection, wie im folgenden Beispiel:
$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
Denn der Benutzer kann die Eingabe so etwas wie value'); DROP TABLE table;--
, und die Abfrage wird:
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
Was kann getan werden, um dies zu verhindern?
InformationsquelleAutor |
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verwenden Sie vorbereitete Anweisungen und parametrisierte Abfragen. Diese sind SQL-Anweisungen, die gesendet und analysiert, indem der Datenbank-server getrennt von Parametern. Auf diese Weise ist es unmöglich für einen Angreifer zu injizieren bösartigen SQL.
Haben Sie grundsätzlich zwei Möglichkeiten dies zu erreichen:
Mit PDO (für jeden unterstützten Datenbanktreiber):
Mit MySQLi (für MySQL):
Wenn Sie versuchen eine Verbindung zu einer anderen Datenbank als MySQL, es ist ein Treiber-spezifische zweite option, die Sie beziehen können (z.B.
pg_prepare()
undpg_execute()
für PostgreSQL). PDO ist die Universelle option.Richtigen Einstellung der Verbindung
Beachten Sie, dass bei der Verwendung von
PDO
Zugriff auf eine MySQL-Datenbank real prepared statements sind nicht standardmäßig verwendet. Um dies zu beheben, müssen Sie deaktivieren die emulation der Anweisungen vorbereitet. Ein Beispiel zum erstellen einer Verbindung mit PDO:Im obigen Beispiel, den Fehler-Modus ist nicht unbedingt notwendig, aber es wird empfohlen, fügen Sie es. Auf diese Weise wird das script nicht stoppen, mit einem
Fatal Error
wenn etwas schief geht. Und es gibt dem Entwickler die chance zucatch
alle Fehler(s), diethrow
n alsPDOException
s.Was ist zwingend, jedoch ist der erste
setAttribute()
Linie, die sagt PDO zu deaktivieren emulierte vorbereitete Anweisungen und verwenden Sie real prepared statements. Dies stellt sicher, dass die Erklärung und die Werte sind nicht von PHP geparst, bevor Sie an den MySQL-server (was ein möglicher Angreifer keine chance zu injizieren bösartigen SQL).Allerdings können Sie die
charset
in den Optionen der Konstruktor, es ist wichtig zu beachten, dass 'ältere' Versionen von PHP (< 5.3.6) ignoriert den charset-parameter in der DSN.Erklärung
Was passiert, ist, dass die SQL-Anweisung übergeben
prepare
analysiert und zusammengestellt von der Datenbank-server. Durch Angabe von Parametern (entweder ein?
oder ein benannter parameter wie:name
im Beispiel oben) weisen Sie die Datenbank-engine, bei der Sie filtern möchten. Dann, wenn Sie anrufenexecute
die vorbereitete Anweisung ist in Kombination mit der parameter-Werte, die Sie angeben.Die wichtige Sache hier ist, dass die parameter-Werte werden kombiniert mit dem kompilierten Anweisung nicht in einer SQL-string. SQL-Injektion funktioniert durch Tricks das Skript in darunter bösartige strings, wenn Sie es schafft, die SQL an die Datenbank gesendet werden. So schicken die den tatsächlichen SQL-getrennt von den Parametern, die Sie begrenzen das Risiko, am Ende mit etwas, das Sie nicht wollen. Alle Parameter, die Sie senden, wenn Sie mit einer vorbereiteten Anweisung wird nur als Zeichenfolgen behandelt werden (obwohl der Datenbank-engine können tun, einige der Optimierung und damit der Parameter kann am Ende als zahlen natürlich auch). In dem obigen Beispiel, wenn die
$name
variable enthält'Sarah'; DELETE FROM employees
das Ergebnis wäre einfach eine Suche nach der Zeichenfolge"'Sarah'; DELETE FROM employees"
, und Sie wird nicht enden, bis mit eine leere Tabelle.Ein weiterer Vorteil der Verwendung von prepared statements ist, dass wenn Sie ausführen, die gleiche Anweisung mehrfach in einer Sitzung-es wird nur analysiert werden, und einmal übersetzt, so dass Sie etwas Geschwindigkeit gewinnt.
Oh, und da Sie gefragt haben, wie es für eine insert -, hier ein Beispiel (mit PDO):
Können prepared statements verwendet werden, die für dynamische Abfragen?
Während Sie immer noch die Verwendung von vorbereiteten Anweisungen für die Abfrage-Parameter, die Struktur der dynamischen Abfrage selbst kann nicht parametriert werden und bestimmte Abfrage-Funktionen können nicht eingestellt.
Für diese speziellen Szenarien, das beste, was zu tun ist, verwenden Sie ein whitelist-filter, die schränkt die möglichen Werte.
Auch die offizielle Dokumentation von mysql_query erlaubt nur das ausführen einer Abfrage, so dass jede andere Abfrage neben ; wird ignoriert. Auch wenn diese bereits veraltet, es gibt eine Menge von Systeme unter PHP 5.5.0 und möglicherweise verwenden Sie diese Funktion. php.net/manual/en/function.mysql-query.php
Dies ist eine schlechte Angewohnheit, aber ist ein post-problem-Lösung : Nicht nur für SQL-injection-aber für jede Art von Injektionen (zum Beispiel gab es eine anzeigen-Vorlage-Injektion Loch in F3 framework v2), wenn Sie bereit alte website oder in der app leidet Injektion Mängel , eine Lösung ist, weisen Sie die Werte Ihres supperglobal vordefinierten vars wie $_POST mit maskierten Werte an bootstrap. Von PDO, noch ist es möglich, zu entkommen (auch für heute-frameworks) : substr($pdo- > quote($str, \PDO::PARAM_STR), 1, -1)
Diese Antwort fehlt die Erklärung, was ist eine vorbereitete Anweisung - in einer - Sache- es ist die Leistung beeinträchtigt, wenn Sie eine Menge von Anweisungen vorbereitet, die während Ihrer Anfrage und manchmal macht es 10x Leistung Treffer. Besser wäre die Verwendung von PDO mit dem parameter-Bindung aus, aber Anweisung Vorbereitung aus.
Mit PDO ist besser, wenn man eine direkte Anfrage stellen Sie sicher, Sie verwenden mysqli::escape_string
InformationsquelleAutor
Wenn Sie eine aktuelle version von PHP, die
mysql_real_escape_string
option unten beschrieben nicht mehr verfügbar (obwohlmysqli::escape_string
ist ein modernes äquivalent). In diesen Tagen werden diemysql_real_escape_string
option würde nur dann Sinn machen, für legacy-code, der auf einer alten version von PHP.Du hast zwei Optionen - escaping der Sonderzeichen in Ihren
unsafe_variable
oder über eine parametrisierte Abfrage. Beide würden schützen Sie vor SQL-injection. Die parametrisierte Abfrage ist besser als die Praxis, sondern erfordern den Wechsel zu einer neueren MySQL-Erweiterung in PHP bevor Sie es verwenden können.Werden wir decken das untere Auswirkungen string Flucht einer der ersten.
Siehe auch die details der
mysql_real_escape_string
Funktion.Verwenden Sie die parametrisierte Abfrage verwenden, benötigen Sie MySQLi eher als die MySQL Funktionen. Umschreiben Ihr Beispiel, wir bräuchten so etwas wie die folgenden.
Die wichtige Funktion, die Sie wollen, um zu Lesen, es wäre
mysqli::prepare
.Auch, wie andere vorgeschlagen haben, finden Sie es vielleicht hilfreich/einfacher Schritt, eine Ebene der Abstraktion, mit etwas PDO.
Bitte beachten Sie, dass der Fall Sie gefragt haben, ist ziemlich einfach und, mehr komplexe Fälle erfordern komplexere Ansätze. Insbesondere:
mysql_real_escape_string
. Bei dieser Art der Fall, Sie wäre besser dran, vorbei die Eingabe des Benutzers über eine whitelist, um zu gewährleisten, dass nur "sichere" Werte zugelassen werden.mysql_real_escape_string
Ansatz, Sie leiden unter dem problem beschrieben Polynom in den Kommentaren unten. In diesem Fall ist es schwieriger, da ganze zahlen würden nicht von Anführungsstrichen umgeben sein, so dass Sie umgehen konnte, mit, indem Sie überprüfen, dass die Eingabe des Benutzers enthält nur Ziffern.mysql_real_escape_string
genug ist, oder ich muss die Verwendung von parametrisierten auch?halten Sie eine gute Praxis der Verwendung von parametrisierten Abfragen, auch an einem lokalen Projekt. Mit parametrisierten Abfragen Sie sind der garantiert sein, dass es kein SQL-injection. Aber Bedenken sollte man bereinigen der Daten zu vermeiden, Schein-retrieval (d.h. XSS-injection, wie setzen Sie HTML-code in einem text) mit
htmlentities
zum BeispielGute Praxis-parametrisierten Abfragen und binden-Werte, sondern real-escape-string ist gut für jetzt
Ich verstehe die Einbeziehung von
mysql_real_escape_string()
für die Vollständigkeit, bin aber kein fan von Liste der am anfälligsten für Fehler-Ansatz zuerst. Der Leser kann nur schnell schnappen Sie sich das erste Beispiel. Gute Sache, es ist veraltet, jetzt 🙂InformationsquelleAutor
Jede Antwort hier deckt nur einen Teil des Problems.
In der Tat, es gibt vier unterschiedliche Abfrage-Teile, die wir hinzufügen können, um es dynamisch zu: -
Und prepared statements cover-nur zwei von Ihnen.
Aber manchmal müssen wir unsere Anfrage noch mehr Dynamik, hinzufügen von Operatoren oder Bezeichner als gut.
So, wir müssen verschiedene Schutz-Techniken.
In der Regel so ein Schutz-Ansatz basiert auf whitelisting.
In diesem Fall, jede dynamische parameter werden sollte hardcoded im Skript und ausgewählt.
Zum Beispiel, um dynamische Bestellung:
Allerdings gibt es einen anderen Weg, um secure IDS - Flucht. Solange Sie eine Kennung angegeben ist, können Sie entkommen backticks innerhalb von Verdoppelung.
Als weiteren Schritt können wir dann leihen Sie sich eine wirklich geniale Idee, mit einigen Platzhalter (proxy zu repräsentieren den tatsächlichen Wert in der Abfrage) aus dem prepared statements und erfinden ein Platzhalter, der von einem anderen Typ - Bezeichner Platzhalter.
So, um die lange Geschichte kurz zu machen: es ist ein Platzhalter, nicht vorbereitete Anweisung kann als eine silberne Kugel.
Also, eine Allgemeine Empfehlung kann formuliert werden als
, Solange Sie das hinzufügen von dynamischen Teile der Abfrage mit Platzhalter (und die Platzhalter richtig bearbeitet natürlich), können Sie sicher sein, dass Ihre Anfrage ist sicher.
Immer noch, es ist ein Problem mit SQL-syntax-Schlüsselwörter (wie
AND
,DESC
und so), aber white-listing scheint der einzige Ansatz in diesem Fall.Update
Zwar gibt es eine Allgemeine Vereinbarung über die besten Praktiken in Bezug auf SQL-injection-Schutz, gibt es noch viele schlechte Praktiken als gut. Und einige von Ihnen zu tief verwurzelt in den Köpfen der PHP-Benutzer. Für die Instanz, auf der dieser Seite gibt es (wenn auch unsichtbar für den Besucher) mehr als 80 Antworten gelöscht - alle entfernt, die von der Gemeinschaft aufgrund der schlechten Qualität oder die Förderung der schlechte und veraltete Praktiken. Schlimmer noch, einige der schlechten Antworten sind nicht gelöscht, sondern prosperieren.
Beispielsweise (1) (2) noch(3) viele(4) Antworten(5), einschließlich der die zweithäufigste Antwort von Ihnen positiv bewertet werden, dass Sie die manuelle string-escaping - ein veralteter Ansatz, die nachweislich unsicher.
Oder es ist eine etwas bessere Antwort, die nahelegt, dass nur eine andere Methode der string-Formatierung und sogar rühmt es als das ultimative Allheilmittel. Zwar ist es natürlich nicht. Diese Methode ist nicht besser als normale string-Formatierung, aber es hält alle seine Nachteile: es ist anwendbar für Zeichenfolgen und nur, wie jede andere manuelle Formatierung, es ist im Grunde optional, nicht obligatorische Maßnahme, anfällig für menschliche Fehler jeglicher Art.
Ich denke, dass all dies, weil ein sehr Alter Aberglaube, unterstützt durch solche Behörden wie OWASP oder das PHP-Handbuch, die verkündet die Gleichheit von was auch immer zu "entkommen" und zum Schutz von SQL-injections.
Unabhängig davon, welche PHP-Handbuch sagt für das Alter,
*_escape_string
keineswegs macht Daten sicher und nie wurde gedacht. Neben nutzlos für jede SQL Teil andere als string, Handbuch der Flucht ist falsch, denn es ist "manuell" als das Gegenteil von automatisch.Und OWASP macht es noch schlimmer, mit Betonung auf der Flucht Benutzereingaben das ist ein völliger Unsinn: es sollte keine solchen Wörter in den Kontext von injection-Schutz. Jeder Variablen ist potenziell gefährlich - unabhängig von der Quelle! Oder, in anderen Worten - jede variable muss richtig formatiert werden, die in der Abfrage egal, die Quelle wieder. Es ist das Ziel, was zählt. Der moment, in dem ein Entwickler beginnt zu trennen die Schafe von den Böcken (Gedanken, ob einige bestimmte variable ist "sicher" oder nicht) er/Sie nimmt seinen/Ihren ersten Schritt in Richtung Katastrophe. Nicht zu erwähnen, dass auch die Formulierung legt nahe Massen-Flucht an die Stelle, ähnelt das sehr magic quotes Funktion - schon verachtet, verworfen und entfernt.
So, im Gegensatz zu was auch immer zu "entkommen", prepared statements ist der Maßnahme, die in der Tat schützt vor SQL-injection (wenn anwendbar).
Wenn Sie noch nicht überzeugt sind, hier eine Schritt-für-Schritt-Erklärung, die ich schrieb, The Hitchhiker ' s Guide to SQL-Injection-Prävention, wo ich erklärte, alle diese Fragen im detail zusammengestellt Abschnitt ausschließlich um schlechte Praktiken und deren Offenlegung.
FILTER_SANITIZE_NUMBER_INT
nur erlaubt, Anzahl Zeichen, damit Whitelisting-Zeichen, keine ganzen strings. In Kombination mit prepared statements, es macht einen guten "Gürtel und Hosenträger" - Ansatz.Sie nicht brauchen, whitelisting hier. Jeder Bereinigung werden redundante. Weniger Regeln zu befolgen, desto weniger Fehler werden Sie machen. Obwohl Sie tun können, jede Validierungen, tun Sie es aus Gründen der Anwendungslogik, aber nicht für die Datenbank.
InformationsquelleAutor
Ich würde empfehlen, mit PDO (PHP Data Objects) zum ausführen von parametrisierten SQL-Abfragen.
Dadurch wird nicht nur der Schutz vor SQL-injection, es beschleunigt auch Abfragen.
Und durch die Verwendung von PDO anstatt
mysql_
,mysqli_
, undpgsql_
Funktionen, die Sie für Ihre app ein wenig mehr abstrahiert von der Datenbank, in die selten vorkommen, dass Sie haben, um Schalter Datenbank-Anbieter.Mit parametrisierten Abfragen ist, was beschleunigt die Abfragen. Technisch mysqli könnte noch schneller durch eine sehr kleine Marge. Die tatsächliche Zeitspanne, die der server braucht, um auf die Abfrage, die Finsternis keinen Unterschied im timing, das kann passieren, weil du mit einem wrapper. Aber mysqli ist an die Datenbank gebunden. Wenn Sie möchten, verwenden Sie eine andere Datenbank-engine, die Sie haben zu ändern, werden alle Anrufe, die mysqli verwendet. Nicht so für PDO.
PDO nicht unterstützt dynamic
order by
leider 🙁InformationsquelleAutor
Verwenden
PDO
und vorbereitete Abfragen.(
$conn
ist einPDO
Objekt)InformationsquelleAutor
Wie Sie sehen können, die Leute empfehlen die Verwendung von prepared statements. Es ist nicht falsch, aber wenn Sie Ihre Abfrage ausgeführt wird, nur einmal pro Prozess, es wäre eine leichte performance-Einbußen.
War ich vor diesem Problem, aber ich denke, ich löste es in sehr anspruchsvolle Art und Weise - die Hacker nutzen, um vermeiden Sie die Verwendung von Anführungszeichen. Ich habe diese in Verbindung mit emulierte vorbereitete Anweisungen. Ich benutze es, um zu verhindern, dass alle möglichen SQL-injection-Angriffe.
Mein Ansatz:
Wenn Sie erwarten Eingaben werden integer-stellen Sie sicher, es ist wirklich integer. In einer Variablen-Typ-Sprache wie PHP ist es diese sehr wichtig. Sie können zum Beispiel diese sehr einfache, aber wirkungsvolle Lösung:
sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);
Wenn Sie erwarten nichts anderes von integer hex es. Wenn Sie hex es, Sie perfekt zu entfliehen diesem allen, Eingang. In C/C++ gibt es eine Funktion namens
mysql_hex_string()
, in PHP, die Sie verwenden könnenbin2hex()
.Nicht befürchten, dass das escaped string haben 2x Größe seiner ursprünglichen Länge, weil, selbst wenn Sie
mysql_real_escape_string
, PHP zuordnen muss gleiche Kapazität((2*input_length)+1)
, das ist das gleiche.Dieser hex-Methode wird oft verwendet, wenn Sie die übertragung von binären Daten, aber ich sehe keinen Grund, warum nicht verwenden Sie es auf alle Daten, die zur Vermeidung von SQL-injection-Angriffe. Beachten Sie, dass Sie voranstellen müssen Daten mit
0x
oder verwenden Sie die MySQL-FunktionUNHEX
statt.So, zum Beispiel, die Abfrage:
Werden:
oder
Hex ist die perfekte Flucht. Keine Möglichkeit zu injizieren.
Unterschied zwischen UNHEX Funktion und 0x-Präfix
Gab es einige Diskussionen in den Kommentaren, so will ich endlich klar zu machen. Diese beiden Ansätze sind sich sehr ähnlich, aber Sie sind ein wenig anders, in gewisser Weise:
* * 0x** Präfix kann nur für Daten verwendet, die Spalten wie char -, varchar -, text -, block -, Binär, etc.
Auch seine Verwendung ist etwas kompliziert, wenn Sie legen Sie eine leere Zeichenfolge. Sie haben, um vollständig ersetzen Sie es mit
''
oder Sie erhalten eine Fehlermeldung.UNHEX() funktioniert auf alle Spalte; Sie haben keine sorgen zu machen über die leere Zeichenfolge.
Hex-Methoden werden oft als Angriffe
Beachten Sie, dass das hex-Methode wird Häufig verwendet, um eine SQL-injection-Angriff, wo die ganzen zahlen sind genau wie bei strings und entkam nur mit
mysql_real_escape_string
. Dann vermeiden Sie die Verwendung von Anführungszeichen.Zum Beispiel, wenn Sie nur etwas wie das hier tun:
einen Angriff zu injizieren Sie sehr leicht. Betrachten Sie die folgenden eingefügten code zurückgegeben, aus dem Skript:
sind und jetzt nur noch extrahieren, die die Struktur einer Tabelle:
Dann wählen Sie einfach alle Daten, die lieben wollen. Ist es nicht cool?
Aber wenn die coder von einem injizierbaren Website hex, keine injection möglich sein, da die Abfrage würde wie folgt Aussehen:
SELECT ... WHERE id = UNHEX('2d312075...3635')
+
aber mitCONCAT
. Und zu der Leistung: ich denke nicht, dass es Auswirkungen auf die Leistung, denn mysql hat, analysieren von Daten, und es spielt keine Rolle, ob der Herkunft, string oder hexWelche Fehler treten hierbei auf? Werden bestimmte.
Sie verstehen die Konzept... Wenn Sie wollen, um string in mysql-Sie nennen es so
'root'
oder Sie können hex es0x726f6f74
ABER wenn Sie möchten eine Zahl ein und senden Sie Sie als string, werden Sie wahrscheinlich schreiben '42' nicht CHAR(42) ... '42' in hex wäre0x3432
nicht0x42
Ich habe nichts zu sagen... einfach nur lol... wenn Sie immer noch wollen, um zu versuchen hex auf numerische Felder, siehe zweiten Kommentar. Ich Wette mit dir, dass es klappt.
Sie noch nicht verstehen ? Sie können nicht verwenden, 0x und concat, weil wenn der string leer ist, werden Sie am Ende mit einem Fehler. Wenn Sie möchten, einfache alternative zu Ihrer Anfrage versuchen, diese
SELECT title FROM article WHERE id = UNHEX(' . bin2hex($_GET["id"]) . ')
InformationsquelleAutor
Injection-prevention - mysql_real_escape_string()
PHP hat einen speziell angefertigten Funktion zu verhindern, dass diese Angriffe. Alles, was Sie tun müssen, ist, verwenden Sie den Bissen der Funktion
mysql_real_escape_string
.mysql_real_escape_string
nimmt eine Zeichenfolge, die verwendet werden in einer MySQL-Abfrage und zurückgeben der gleichen Zeichenfolge mit allen SQL-injection-versuche, sicher zu entkommen. Im Grunde, es wird diejenigen ersetzen, die lästigen Anführungszeichen ('), die ein Benutzer möglicherweise geben Sie mit einer MySQL-sichere Alternative, ein entflohener zitieren,\'.HINWEIS: müssen Sie eine Verbindung zu der Datenbank, um diese Funktion zu verwenden!
//Verbindung zu MySQL
Finden Sie weitere details in MySQL - SQL-Injection-Prävention.
Ich bin nicht einverstanden mit dieser 'eine speziell-aus-Funktion, um zu verhindern, dass diese Angriffe". Ich denke, dass
mysql_real_escape_string
Zweck ist in ermöglichen, zu bauen, die richtige SQL-Abfrage für jeden Eingangs-Daten-string. Verhinderung von sql-injection ist der Nebeneffekt dieser Funktion.Sie dont verwenden Sie Funktionen schreiben, die korrekte Eingabe von Daten-strings. Sie schreiben Sie einfach die richtige diejenigen, die nicht brauchen, Flucht oder bereits geflüchtet. mysql_real_escape_string() kann entworfen worden, mit dem Zweck, die Sie erwähnen im Sinn, aber seine einzige Wert ist die Verhinderung der Injektion.
WARNUNG!
mysql_real_escape_string()
ist nicht unfehlbar.mysql_real_escape_string
ist nun veraltet, also nicht mehr eine praktikable option. Es wird entfernt werden, die in der Zukunft von PHP. Seine besten zu bewegen auf, was der PHP-oder MySQL-Leute empfehlen.InformationsquelleAutor
Könnten Sie etwas tun, basic wie dieses:
Diese nicht jedes problem lösen, aber es ist ein sehr gutes Sprungbrett. Ich verließ Sie offensichtlich Elemente, wie etwa die überprüfung der Variablen Existenz, formatieren (zahlen, Buchstaben, etc.).
Wenn Sie nicht zitieren, den string, es ist immer noch injizierbare. Nehmen
$q = "SELECT col FROM tbl WHERE x = $safe_var";
zum Beispiel. Einstellung$safe_var
zu1 UNION SELECT password FROM users
funktioniert in diesem Fall, weil der Mangel an Zitaten. Es ist auch möglich, das einschleusen von strings in der Abfrage mitCONCAT
undCHR
.Völlig richtig, aber ich würde sehen, das nur als falsche Verwendung. So lange wie Sie es richtig zu verwenden, wird es auf jeden Fall funktionieren.
WARNUNG!
mysql_real_escape_string()
ist nicht unfehlbar.mysql_real_escape_string
ist nun veraltet, also nicht mehr eine praktikable option. Es wird entfernt werden, die in der Zukunft von PHP. Seine besten zu bewegen auf, was der PHP-oder MySQL-Leute empfehlen.InformationsquelleAutor
Was auch immer Sie tun, am Ende mit, stellen Sie sicher, dass Sie überprüfen Sie Ihre Eingaben nicht bereits entstellt durch
magic_quotes
oder einige andere gut gemeinte Müll, und, wenn nötig, führen Sie es durchstripslashes
oder was auch immer zu desinfizieren.Ab PHP 5.4, die Greuel bekannt als 'magic quotes' getötet tote. Und good riddance schlechten Müll.
InformationsquelleAutor
Parametrisierte Abfrage-UND Eingabe-Validierung ist der Weg zu gehen. Es gibt viele Szenarien, unter denen SQL-injection auftreten, obwohl
mysql_real_escape_string()
verwendet wurde.Diese Beispiele sind anfällig für SQL-injection:
oder
In beiden Fällen können Sie nicht verwenden
'
zum Schutz der Kapselung.Quelle: Die Unerwartete SQL-Injection (Bei der Flucht Nicht Genug)
InformationsquelleAutor
Meiner Meinung nach, der beste Weg, um in der Regel verhindern, dass SQL-injection in PHP-Anwendung (oder jede web-Anwendung, für diese Angelegenheit) ist, zu denken, über die Architektur Ihrer Anwendung. Wenn der einzige Weg, um Schutz vor SQL-injection ist daran zu erinnern, eine spezielle Methode oder Funktion, Die Richtige jedes mal, wenn Sie mit der Datenbank sind, machst du es falsch. So, es ist nur eine Frage der Zeit, bis Sie vergessen, um richtig formatieren Sie Ihre Abfrage zu einem gewissen Punkt in Ihrem code.
Annahme des MVC-Musters, und ein framework wie CakePHP oder CodeIgniter ist wohl der richtige Weg zu gehen: Gemeinsame Aufgaben wie das erstellen von secure-Datenbank-Abfragen wurden gelöst und zentral umgesetzt in einem solchen Rahmen. Sie helfen, organisieren Sie Ihre web-Anwendung in einer vernünftigen Art und Weise und machen Sie glauben, mehr über das laden und speichern von Objekten als etwa sicher konstruieren einzelne SQL-Abfragen.
Sie sind absolut richtig. Es ist sehr wichtig, um zu verstehen, was Los ist und warum. Aber die chance, dass ein true-and-versucht und aktiv genutzt und entwickelt framework ausgeführt hat und lösen eine Menge von Fragen und gepatcht viele Sicherheitslücken schon ziemlich hoch. Es ist eine gute Idee, einen Blick auf die Quelle, um ein Gefühl für die code-Qualität. Wenn es eine ungetestete Durcheinander, es ist wahrscheinlich nicht sicher.
Hier. Hier. Gute Punkte. Allerdings würden Sie Zustimmen, dass viele Menschen studieren können und lernen, sich zu verabschieden, ein MVC-system, aber nicht jeder kann es reproduzieren von hand (Controller und server). Kann man zu weit gehen mit diesem Punkt. Muss ich verstehen, meine Mikrowelle, bevor ich Sie erwärmen mein Erdnuss-butter pecan cookies meiner Freundin machte ich? 😉
Ich bin damit einverstanden! Ich denke, dass der use-case, der einen Unterschied macht: Bin ich der Aufbau einer Foto-Galerie für meine persönliche homepage, oder bin ich der Aufbau einer online-banking-web-Anwendung? Im letzteren Fall ist es sehr wichtig zu verstehen, die details-Sicherheit und wie ein framework das ich verwende, ist die Abwehr dieser.
Ah, die Sicherheits-Ausnahme von der do it yourself-Folge. Siehe, ich Neige dazu bereit, es zu riskieren alles und gehen für pleite. 🙂 Scherz. Mit genügend Zeit, können die Menschen lernen, einen verdammt sicheren Anwendung. Zu viele Menschen sind in Eile. Werfen Sie Ihre Hände nach oben und davon ausgehen, dass die frameworks sind sicherer. Nachdem alle, Sie haben nicht genug Zeit zu testen und zu Dinge herauszufinden. Darüber hinaus ist die Sicherheit ein Feld, das erfordert engagierte Studie. Es ist nicht etwas, was bloße Programmierer wissen, in der Tiefe, die aufgrund von Verständnis von algorithmen und design-patterns.
InformationsquelleAutor
Bin ich dafür, gespeicherte Prozeduren ( MySQL hat gespeicherte Prozeduren unterstützen seit 5.0 ) aus der Sicht der Sicherheit - die Vorteile sind -
Die Nachteile sind -
InformationsquelleAutor
Gibt es viele Möglichkeiten der Verhinderung von SQL-injections und andere SQL-hacks. Sie können leicht finden es im Internet (Google-Suche). Natürlich PDO ist eine der guten Lösungen. Aber ich möchte Ihnen einige gute links, die Vermeidung von SQL-Injection.
Was ist eine SQL injection und wie zu verhindern
PHP-Handbuch für SQL-injection
Microsoft Erklärung, SQL-injection und Prävention in PHP
und einige andere wie Verhinderung von SQL-injection mit MySQL und PHP
Nun, warum Sie das tun, müssen Sie verhindern, dass Ihre Abfrage von SQL-injection?
Möchte ich Sie wissen lassen: Warum tun wir versuchen, zur Verhinderung von SQL-injection mit einem kleinen Beispiel unten:
Abfrage für login-Authentifizierung match:
Nun, wenn jemand (ein hacker) stellt
und Passwort nichts....
Wird die Abfrage analysiert werden, in das system nur bis zu:
Den anderen Teil verworfen werden. Also, was wird passieren? Ein nicht autorisierter Benutzer (hacker) können sich als admin einloggen, ohne sein Passwort. Nun, er kann alles tun, die admin/E-Mail person tun kann. Sehen, es ist sehr gefährlich, wenn der SQL-Injektion nicht verhindern.
InformationsquelleAutor
Ich denke, wenn jemand will, um den Einsatz von PHP und MySQL oder eine andere Datenbank-server:
(int)$foo
. Lesen Sie mehr über den Typ von Variablen in PHP hier. Wenn Sie mit Bibliotheken wie PDO oder MySQLi verwenden Sie immer PDO::quote() und mysqli_real_escape_string().Bibliotheken Beispiele:
---- PDO
--- MySQLi
P. S:
PDO gewinnt diese Schlacht mit Leichtigkeit. Mit Unterstützung für zwölf
verschiedene Datenbank-Treiber und benannte Parameter, die wir ignorieren können, die
kleinen performance-Verlust, und erhalten Sie verwendet, um die API. Sicherheit
Standpunkt, beide von Ihnen sind so lange sicher, wie der Entwickler nutzt Sie
die Art, wie Sie eingesetzt werden sollen
Aber während die beiden PDO und MySQLi sind Recht schnell, MySQLi führt
unwesentlich schneller in benchmarks – ~2,5% für nicht-vorbereitet
Aussagen, und ~6,5% für Sie vorbereitet lieben.
Und bitte testen Sie jede Abfrage an Ihre Datenbank - es ist ein besserer Weg, um zu verhindern, dass die Injektion.
InformationsquelleAutor
Wenn möglich, wandeln Sie die Typen Ihrer Parameter. Aber es ist nur einfache Typen wie int, bool und float.
InformationsquelleAutor
Wenn Sie möchten, um die Vorteile der cache-engines, wie Redis oder Memcached, vielleicht DALMP könnte eine Wahl sein. Es nutzt rein MySQLi. Überprüfen Sie dies: DALMP Database Abstraction Layer für MySQL mit PHP.
Können, können Sie auch 'Vorbereitung' Ihre Argumente, bevor Sie die Vorbereitung Ihrer Abfrage, so dass Sie bauen können dynamische Abfragen und am Ende eine voll prepared statements Abfrage. DALMP Database Abstraction Layer für MySQL mit PHP.
InformationsquelleAutor
Für diejenigen, die nicht sicher sind, wie zu verwenden PDO (aus
mysql_
Funktionen), machte ich eine sehr, sehr einfach PDO wrapper , ist eine einzelne Datei. Es existiert, um zu zeigen, wie einfach es ist zu tun, all die gemeinsamen Dinge, die Anwendungen, die getan werden müssen. Funktioniert mit PostgreSQL, MySQL und SQLite.Im Grunde genommen, Lesen Sie es während Sie die Bedienungsanleitung Lesen, um zu sehen, wie die PDO-Funktionen zu verwenden, im wirklichen Leben, um es einfach zu speichern und abrufen von Werten in dem format Sie wollen.
InformationsquelleAutor
Verwendung dieser PHP-Funktion
mysql_escape_string()
Sie können eine gute Prävention in einer schnellen Weise.Beispiel:
mysql_escape_string
— Escapes eine Zeichenfolge für die Verwendung in einem mysql_queryFür mehr Prävention, Sie können fügen Sie am Ende ...
Endlich bekommen Sie:
InformationsquelleAutor
Ein paar Richtlinien für das escaping von Sonderzeichen in SQL-Anweisungen.
Nicht verwenden MySQL, diese Erweiterung ist veraltet, verwenden Sie MySQLi oder PDO.
MySQLi
Für das manuelle escaping von Sonderzeichen in einer Zeichenfolge, die Sie verwenden können, die mysqli_real_escape_string Funktion. Die Funktion funktioniert nicht ordnungsgemäß, wenn der richtige Zeichensatz eingestellt ist mit mysqli_set_charset.
Beispiel:
Für die automatische escaping von Werten mit prepared statements verwenden mysqli_prepare, und mysqli_stmt_bind_param wo Typen für die entsprechenden bind-Variablen bereitgestellt werden müssen, die für eine adäquate Umsetzung:
Beispiel:
Egal, ob Sie verwenden vorbereitete Anweisungen oder mysqli_real_escape_string, müssen Sie immer wissen, welche Art von input-Daten mit dem Sie arbeiten.
Also, wenn Sie eine vorbereitete Anweisung verwenden, müssen Sie den Typen der Variablen für mysqli_stmt_bind_param Funktion.
Und der Einsatz von mysqli_real_escape_string ist, wie der name schon sagt, die Maskierung von Sonderzeichen in einem string, also wird es nicht um ganze zahlen sicher. Der Zweck dieser Funktion ist es, zu verhindern, brechen Sie die Zeichenfolgen in SQL-Anweisungen, und der Schaden an der Datenbank, die es verursachen könnte. mysqli_real_escape_string-Funktion ist besonders nützlich, wenn verwendet, richtig, vor allem, wenn in Kombination mit sprintf.
Beispiel:
InformationsquelleAutor
Die einfache alternative für dieses problem könnte gelöst werden, durch die Gewährung von entsprechenden Berechtigungen in der Datenbank selbst.
Zum Beispiel: wenn Sie eine MySQL-Datenbank dann in die Datenbank eingeben über terminal oder der Benutzeroberfläche zur Verfügung gestellt, und Folgen Sie einfach diesen Befehl:
Diese beschränken die Benutzer erhalten nur beschränkt mit der die angegebene Abfrage ist nur. Entfernen Sie die Berechtigung löschen und so die Daten nie gelöscht, aus der die Abfrage ausgelöst von der PHP-Seite.
Das zweite, was zu tun ist, Spülen Sie die Berechtigungen so, dass der MySQL aktualisiert die Berechtigungen und updates.
mehr Informationen über flush.
Sehen Sie die aktuellen Berechtigungen für den Benutzer Feuer die folgende Abfrage.
Erfahren Sie mehr über GRANT.
Recht, ist es nicht bieten eine Lösung, aber ist das, was Sie tun können, bevor die hand, um zu vermeiden, Dinge.
Wenn mein Ziel ist, zu Lesen private Daten aus Ihrer Datenbank, dann nicht mit der Berechtigung LÖSCHEN bedeutet nichts.
Take it easy, ich war nur darauf hindeutet, gute Praktiken für die Abfederung der Folgen.
Sie wollen nicht "erweichen Folgen", Sie wollen alles tun, um gegen Sie zu schützen. Um fair zu sein, obwohl die Einstellung des richtigen Benutzer Zugriff wichtig ist, aber nicht wirklich das, was der OP fordert.
InformationsquelleAutor
Ich drei verschiedene Möglichkeiten, um zu verhindern, dass meine web-Anwendung anfällig für SQL-injection.
mysql_real_escape_string()
, die eine vordefinierte Funktion in PHP, und diesen code hinzufügen, umgekehrte Schrägstriche, um die folgenden Zeichen:\x00
,\n
,\r
,\
,'
,"
und\x1a
. Übergeben Sie die input-Werte als Parameter zu minimieren die Möglichkeit von SQL-injection.Ich hoffe das 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 nicht schützen hier. Wenn Sie verwenden Sie einfache Anführungszeichen (' ') rund um Ihren Variablen innerhalb deiner Abfrage ist das, was schützt Sie gegen diese. Hier ist eine Lösung unter:
$iId = (int) mysql_real_escape_string("1 OR 1=1");
$sSql = "SELECT * FROM table WHERE id = $iId";
Diese Frage hat einige gute Antworten dazu.
Schlage ich vor, mithilfe von PDO ist die beste option.
Edit:
mysql_real_escape_string()
ist deprecated seit PHP 5.5.0. Verwenden Sie entweder mysqli oder PDO.Alternative zu mysql_real_escape_string() ist
Beispiel:
InformationsquelleAutor
In Bezug auf viele nützliche Antworten, ich hoffe, fügen Sie einige Werte in diesem thread.
SQL-injection ist ein Angriff, der kann getan werden, durch Eingaben des Benutzers (Eingaben, gefüllt durch user und dann in Abfragen), SQL-injection-Muster sind richtige Abfrage-syntax, während wir nennen es: bad-Abfragen für schlechte Gründe, gehen wir davon aus, dass es möglicherweise zu einem schlechten Menschen, die versuchen, geheime Informationen (unter Umgehung access control), die auf die drei Prinzipien der Sicherheit (Vertraulichkeit, Integrität, Verfügbarkeit).
Nun, unser Punkt ist, um zu verhindern, dass Bedrohungen wie SQL-injection-Angriffe, die Frage zu Fragen, (Wie Sie verhindern, dass SQL-injection-Angriff mit PHP), werden realistischer, Daten filtern oder löschen von input-Daten ist dann der Fall, wenn die Verwendung von Benutzer-input-Daten, die in einem solchen Abfrage mit PHP oder anderen Programmiersprachen nicht der Fall ist, oder wie empfohlen, um mehr Menschen zur Nutzung moderner Technik, wie eine vorbereitete Anweisung oder andere tools, die zurzeit unterstützt SQL-injection-Prävention, beachten Sie, dass diese tools nicht mehr verfügbar? Wie sichern Sie Ihre Anwendung?
Mein Ansatz gegen SQL-injection ist: clearing-user-input-Daten vor dem senden an die Datenbank (vor der Verwendung in einer Abfrage).
Daten-Filterung für die (Umwandlung von unsicheren Daten sichere Daten)
Bedenken Sie, dass PDO und MySQLi nicht verfügbar ist, wie können Sie sicher Ihre Anwendung? Tun Sie mich zwingen, Sie zu nutzen? Was ist mit anderen Sprachen außer PHP? Ich ziehe um Allgemeine Ideen, wie Sie können verwendet werden, für eine breitere Grenze nicht nur für eine bestimmte Sprache.
REGEL: erstellen Sie einen Datenbank-Benutzer für alle Berechtigungen für alle SQL-Operationen, erstellen Sie Ihr System wie (deluser, selectuser, updateuser) als Benutzernamen für die einfache Nutzung.
sehen Prinzip der geringsten Rechte
Daten-Filterung: vor dem erstellen einer Abfrage von Benutzereingaben validiert werden soll und gefiltert, für Programmierer, es ist wichtig zu definieren, einige Eigenschaften für jede user-Eingabe-Variablen:
Daten, Typ, Daten, Muster und Daten Länge. ein Feld ist eine Zahl zwischen (x und y) muss genau überprüft über genaue Regel für ein Feld, das eine Zeichenfolge (text): Muster ist zum Beispiel der Fall, darf der Benutzername enthalten nur einige Zeichen können sagen, [a-zA-Z0-9_-.] die Länge variiert zwischen (x und n), wobei x und n (Integer, x <=n ).
Regel: erstellen von genauen Filter-und Prüfregeln sind die beste übung für mich.
Andere tools verwenden: Hier werde ich auch mit Ihnen überein, dass vorbereitete Anweisung (Parametrierung) Abfragen und Gespeicherten Prozeduren, die Nachteile hier ist diese Art und Weise erfordern erweiterte Kompetenzen, die nicht vorhanden sind für die meisten Benutzer, die grundlegende Idee hier ist zu unterscheiden zwischen der SQL-Abfrage und die Daten in beide Ansätze können verwendet werden, auch mit unsicheren Daten, weil der Benutzer-Eingabe-Daten hier nichts hinzufügen, um die ursprüngliche Abfrage wie (bzw. x=x).
Für mehr Informationen, Lesen Sie bitte OWASP SQL-Injection Prevention Cheat Sheet.
Nun, wenn Sie ein Fortgeschrittener Benutzer sind, starten Sie mit dieser Verteidigung, wie Sie möchten, aber, für Anfänger, wenn Sie nicht schnell zu implementieren, gespeicherte Prozedur vorbereitet und die Aussage, es ist besser, filter, input-Daten, so viel Sie können.
Endlich, wir betrachten, dass Benutzer sendet diesen text unten anstelle der Eingabe von Benutzername:
Dieser Eingang kann frühzeitig überprüft werden, ohne prepared Statements und gespeicherte Prozeduren, aber um auf der sicheren Seite sein, mit Ihnen beginnt nach der Benutzer-Daten-Filterung und Validierung.
Letzter Punkt ist die Erkennung von unerwarteten Verhalten, das erfordert mehr Aufwand und Komplexität; es ist nicht empfohlen für normale web-Anwendungen.
Unerwartetes Verhalten in der oben Benutzer-Eingabe WÄHLEN, UNION, WENN die SUBSTRING -, BENCHMARK -, SHA -, Wurzel-sobald diese Worte erkannt werden, können Sie vermeiden, die Eingabe.
UPDATE1:
Ein user kommentierte, dass dieser Beitrag nutzlos ist, OK! Hier ist, was OWASP.ORG zur Verfügung gestellt:
Wie Sie vielleicht wissen, fordern ein Artikel sollte unterstützt werden durch das gültige argument, mindestens eine Referenz! Ansonsten ist es als Angriff und schlechtes behaupten!
Update2:
Aus dem PHP-Handbuch, PHP: Prepared Statements - Handbuch:
Update3:
Ich erstellte Testfälle, um zu wissen, wie PDO und MySQLi senden Sie die Abfrage an den MySQL-server bei der Verwendung von prepared statement:
PDO:
Query Log:
MySQLi:
Query Log:
Es ist klar, dass eine vorbereitete Anweisung ist auch die Flucht vor die Daten, sonst nichts.
Als auch in der oben aufgeführten Anweisung
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
daher, das beweist, dass die Validierung von Daten, wieintval()
ist eine gute Idee für integer-Werte vor dem senden einer Abfrage, darüber hinaus wird verhindert, dass böswillige Benutzer Daten vor dem versenden der Abfrage ist richtige und gültige Ansatz.Sehen Sie sich bitte die Frage genauer: PDO sendet roh-Abfrage zu MySQL während Mysqli schickt vorbereitete Abfrage, beide produzieren das gleiche Ergebnis
Referenzen:
InformationsquelleAutor
Ein einfacher Weg wäre, um ein PHP-framework wie CodeIgniter oder Laravel die eingebauten Funktionen wie Filterung und active-record, so dass Sie nicht haben, um über sorgen diese Nuancen.
InformationsquelleAutor
** Warnung: die hier beschriebenen Ansatz in diese Antwort gilt nur für sehr spezielle Szenarien und ist nicht sicher, da SQL-injection-Angriffe nicht nur Vertrauen in der Lage zu injizieren
X=Y
.**Wenn die Angreifer versuchen, hacken Sie sich in das Formular über PHP
$_GET
oder variable mit der URL übergeben, würden Sie in der Lage sein, um Sie zu fangen, wenn Sie nicht sicher sind.Weil
1=1
,2=2
,1=2
,2=1
,1+1=2
, usw... sind die häufigsten Fragen, die an eine SQL-Datenbank von einem Angreifer. Vielleicht ist das auch der es ist verwendet durch viele hacking-Anwendungen.Aber Sie müssen vorsichtig sein, dass Sie nicht umgeschrieben werden, sichere Abfrage von Ihrer Website. Der obige code gibt dir einen Tipp, umschreiben oder umleiten (es hängt von Ihnen ab), die hacking-spezifische dynamische query-string in eine Seite, speichert der Angreifer Die IP-Adresse, oder SOGAR IHRE COOKIES, Verlauf, browser-oder anderer sensibler Informationen, so können Sie sich mit Ihnen später durch das Verbot von Ihrem Konto oder Kontaktaufnahme mit Behörden.
InformationsquelleAutor
Gibt es so viele Antworten für PHP und MySQL, aber hier ist der code für PHP und Oracle zur Verhinderung von SQL-injection-sowie der regelmäßigen Verwendung von oci8-Treiber:
InformationsquelleAutor
Eine gute Idee ist die Verwendung einer 'Objekt-relationalen mapper wie Idiorm:
Es spart Ihnen nicht nur von SQL-Injektionen, aber vom syntax-Fehler auch! Unterstützt auch Sammlungen von Modellen mit der Methode Verkettung von filtern oder anwenden von Aktionen auf mehrere Ergebnisse auf einmal und mehrere verbindungen.
InformationsquelleAutor
Mit PDO und MYSQLi ist eine gute Praxis, um zu verhindern, dass SQL-Injektionen, aber wenn Sie wirklich wollen, um die Arbeit mit den MySQL-Funktionen und Abfragen, es wäre besser, verwenden
mysql_real_escape_string
Gibt es mehr Fähigkeiten, das zu verhindern: wie identifizieren - wenn die Eingabe eine Zeichenfolge, eine Zahl, char oder array, es gibt so viele eingebaute Funktionen, um dies zu erkennen. Auch, es wäre besser, diese Funktionen zu überprüfen, input-Daten.
is_string
is_numeric
Ist und es so viel besser ist, um jene Funktionen zur Prüfung von input-Daten mit
mysql_real_escape_string
.WARNUNG!
mysql_real_escape_string()
ist nicht unfehlbar.mysql_real_escape_string
ist nun veraltet, also nicht mehr eine praktikable option. Es wird entfernt werden von PHP in die Zukunft. Seine besten zu bewegen auf, was der PHP-oder MySQL-Leute empfehlen.Thema: kein Vertrauen in die Weiterleitung der Daten. Alles, was Sie erwarten, ist ein Müll-Daten mit Sonderzeichen und Boolesche Logik, die sollte selbst ein Teil der SQL-Abfrage kann ausgeführt werden. Halten Sie die $_POST-Werte nur Daten, nicht den SQL-Teil.
InformationsquelleAutor
Ich geschrieben habe, diese kleine Funktion vor einigen Jahren:
Dieser ermöglicht das ausführen von Anweisungen in einem one-liner C#-ish String.Format wie:
Tritt es in Anbetracht der Variablen-Typ. Wenn Sie versuchen, Sie zu parametrisieren-Tabelle, die Spaltennamen, es würde scheitern, als es bringt jede Zeichenfolge in Anführungszeichen, die ist eine ungültige syntax.
SICHERHEITS-UPDATE: Die bisherigen
str_replace
version erlaubt Injektionen durch hinzufügen {#} Token in der Benutzer-Daten. Diesepreg_replace_callback
version nicht zu Problemen führen, wenn der Ersatz enthält diese Token.InformationsquelleAutor