it-swarm-eu.dev

SQL-Injection - warum sind Escape-Anführungszeichen nicht mehr sicher?

Raw SQL

Wenn Sie SQL schreiben - für alles, was wirklich menschliche Eingaben erfordert, wurden viele Dinge getan, um die Injektion zu vermeiden.

Jeder, der von SQL Injection gehört hat, weiß, dass (ich werde PHP als Beispiel verwenden)) so etwas nicht sicher ist:

$sql = "SELECT * FROM `users` 
.  WHERE `userName` = "{$_POST["username"]}" 
.  AND `pass` = "{$_POST["pass"]}";";

Magie

Dann kam natürlich jemand auf die Idee, "magische Fluchtzitate" zu verwenden, um Programmeingaben zu verarbeiten, die aufgrund korrekter Praktiken nicht korrekt bereinigt und direkt in SQL eingefügt wurden. Dies hat das Problem mit der SQL-Injection nicht wirklich gelöst, aber es bedeutete, dass alle Benutzereingaben verstümmelt wurden.

Schrägstriche hinzufügen

Also haben einige Leute magische Zitate abgeschaltet. Dann analysierten sie Benutzereingaben vor dem SQL-Punkt durch addslashes(), was theoretisch allen Anführungszeichen entgeht und Ihr Hacker nicht ' OR 1=1 Ausführen kann, aber selbst die Dokumentation für Addslashes sagt es selbst Sie sollten keine Addslashes verwenden, es heißt, dass Sie die datenbankspezifische Funktion wie mysql_real_escape_string() verwenden, aber dies wird von einigen immer noch als nicht ausreichend bezeichnet.

Hinzufügen von datenbankspezifischen Schrägstrichen

Wir können also kein DBMS-spezifisches *_real_escape_string Verwenden, wir können kein add slashes Verwenden, das "magische Anführungszeichen" verursachte viele Probleme, und das Web ist voll von kurz formulierten Anführungszeichen wie ::

"Ein engagierter Hacker wird einen Weg finden, durch Ihre Anführungszeichen-Schleifen zu springen. Verwenden Sie einfach die von DBAL vorbereiteten Anweisungen" - John Q, jeder Programmierer

Okay, das hat mich genug erschreckt, um Prepare-Anweisungen und eine DBAL zu verwenden. Es hat nichts wirklich erklärt, aber es klingt gut, weil ich es viel gehört habe.

Vorbereitete Aussagen

Jetzt verwenden wir PDO oder eine DBAL aus einem Framework oder etwas anderes, das unsere gesamte SQL-Datei umschließt und sicherstellt, dass niemand eine SQL-Injection ausführen kann.

Meine Frage ist im Grunde ein "Warum nicht?", Kein "Was soll ich verwenden?". Das Web ist voll von Leuten, die Ihnen sagen, dass Sie dies oder jenes oder was auch immer verwenden sollen, aber keine Erklärungen, warum diese Dinge passieren mussten.

Direkte Fragen

Gezielte Fragen (Erinnerung, ich frage nach SQL, PHP war eine Beispielsprache, weil es schlechte Repräsentation in SQL gibt, Konzepte sind universell):

  1. Warum können wir nicht allen Benutzereingaben mit "Magie" entkommen?
  2. Warum waren Addslashes nicht "gut genug"?
  3. Was ist falsch an der Verwendung von DB-spezifischen Escape-Funktionen und warum war es besser als Addslashes?
  4. Warum werden vorbereitete Anweisungen mit Frameworks und PDO als Goldstandard von SQL gefeiert? Warum sind sie besser? Warum kann ich mit diesen keine SQL-Injection durchführen, wo ich es mit den zuvor genannten Mitteln hätte tun können? Kann ein Programmierer nicht irgendwie es schaffen, das noch zu vermasseln? Worauf sollten sie achten?
  5. Irgendwelche anderen Bedenken, die ich nicht angesprochen habe?
78
Incognito

Warum können wir nicht allen Benutzereingaben mit "Magie" entkommen?

Zum Zeitpunkt der Anwendung der Magie ist nicht bekannt, wo die Daten landen werden. Magische Anführungszeichen zerstören also Daten, die nicht ungehindert in eine Datenbank geschrieben wurden.

Es kann nur in der HTML-Antwort verwendet werden, die an den Client zurückgesendet wird. Stellen Sie sich ein Formular vor, das nicht vollständig ausgefüllt wurde und dem Benutzer daher erneut angezeigt wird. Bei magischen Anführungszeichen werden die beim ersten Versuch eingegebenen Daten jetzt mit SQL-Escapezeichen versehen, was auf einer HTML-Seite bedeutungslos ist. Noch schlimmer: Bei der zweiten Übermittlung werden die Daten erneut mit SQL-Escapezeichen versehen.

Warum waren Addslashes nicht "gut genug"?

Es gibt Probleme mit Multibyte-Zeichen:

' 27
\ 5c
뼧 bf 5c

Das sind zwei Bytes, aber nur ein Unicode-Zeichen.

Da addslashes nichts über Unicode weiß, konvertiert es die Eingabe bf 27 bis bf 5c 27. Wenn dies von einem Unicode-fähigen Programm gelesen wird, wird es als 뼧 'angesehen. Boom.

Eine gute Erklärung für dieses Problem finden Sie unter http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string

Was ist falsch an der Verwendung von DB-spezifischen Escape-Funktionen und warum war es besser als Addslashes?

Sie sind besser, weil sie sicherstellen, dass das Escapezeichen die Daten genauso interpretiert wie die Datenbank (siehe letzte Frage).

Aus Sicherheitsgründen sind sie in Ordnung, wenn Sie sie für jede einzelne Datenbankeingabe verwenden. Aber sie haben das Risiko, dass Sie einen von ihnen irgendwo vergessen.

Bearbeiten : Als getahobby hinzugefügt: Oder dass Sie xxx_escape_strings für Zahlen verwenden, ohne sie in der SQL-Anweisung in Anführungszeichen zu setzen und ohne sicherzustellen, dass es sich um tatsächliche Zahlen von handelt Umwandlung oder Konvertierung der Eingabe in den entsprechenden Datentyp /Bearbeiten

Aus Sicht der Softwareentwicklung sind sie schlecht, weil sie es viel schwieriger machen, Unterstützung für andere SQL-Datenbankserversoftware hinzuzufügen.

Warum werden vorbereitete Anweisungen mit Frameworks und PDO als Goldstandard von SQL gefeiert? Warum sind sie besser?

PDO ist meistens aus Gründen des Software-Designs eine gute Sache. Dies erleichtert die Unterstützung anderer Datenbankserversoftware erheblich. Es verfügt über eine objektorientierte Schnittstelle, die viele der kleinen datenbankspezifischen Inkompatibilitäten abstrahiert.

Warum kann ich mit diesen [vorbereiteten Anweisungen] keine SQL-Injektion durchführen, wo ich es mit den zuvor genannten Mitteln hätte tun können?

Der Teil " konstante Abfrage mit variablen Parametern " in vorbereiteten Anweisungen ist hier wichtig. Der Datenbanktreiber entzieht sich automatisch allen Parametern, ohne dass der Entwickler darüber nachdenken muss.

Parametrisierte Abfragen sind aus syntaktischen Gründen oft einfacher zu lesen als normale Abfragen mit maskierten Parametern. Je nach Umgebung können sie etwas schneller sein.

Die Verwendung vorbereiteter Anweisungen mit Parametern kann mit statischen Code-Analyse-Tools überprüft werden. Ein fehlender Aufruf von xxx_escape_string wird nicht so einfach und zuverlässig erkannt.

Kann ein Programmierer es nicht irgendwie schaffen, das noch zu vermasseln? Worauf sollten sie achten?

"Vorbereitete Anweisungen" implizieren, dass die Konstanten sind. Das dynamische Generieren vorbereiteter Anweisungen - insbesondere mit Benutzereingaben - weist immer noch alle Probleme mit der Injektion auf.

52

[1.] Warum können wir nicht allen Benutzereingaben mit "Magie" entkommen?

Weil magische Zitate in zweierlei Hinsicht gebrochen werden:

  1. Nicht alle $ _-Daten (REQUEST/GET/POST) werden in die Datenbank aufgenommen. Und damit Sie einen Sinn daraus machen können, müssen Sie sich der Eingabe entziehen.
  2. Sie sind das addslashes -Äquivalent (siehe meinen Hinweis zu [2.]), daher sind sie nicht wirklich sicher.

[2.] Warum waren Addslashes nicht "gut genug"?

Es gibt viele Möglichkeiten, um aus der Einschränkung addslashes herauszukommen. Daher ist sie grundlegend fehlerhaft, Sie versuchen jedoch, sie zu verwenden.

[3.] Was ist falsch an der Verwendung von DB-spezifischen Escape-Funktionen und warum war es besser als Addslashes?

Nichts wirklich. Das ist einfach das Mantra, warum PDO/vorbereitet "besser" sind. Sie sind übrigens besser als addslashes, da sie sich um viele Faktoren kümmern, einschließlich der Codierung. Hier ist ein kleines Geheimnis; PDO verwendet sie intern, aber nicht addslashes ...

[4.] Warum werden vorbereitete Anweisungen mit Frameworks und PDO als Goldstandard von SQL gefeiert? Warum sind sie besser? Warum kann ich mit diesen keine SQL-Injection durchführen, wo ich es mit den zuvor genannten Mitteln hätte tun können?

Sie sind nicht der Goldstandard, sie sind nicht "sicherer" als DB-spezifische Funktionen und Sie können SQL-Injection ausführen mit diesen auch. Und nein, Sie können keine SQL-Injection mit ordnungsgemäß bereinigten Eingaben durchführen.

Wie bei allen Technologien neigen Entwickler dazu, religiöse (fanatische?) Tendenzen für etwas "Neues" zu entwickeln. Aus diesem Grund erhalten Sie erfahrene Zend Certified Engineers (TM), die Ihnen raten, nicht zu vorbereiteten Aussagen zu wechseln.

Die Realität ist jedoch, dass alles davon abhängt, zu wissen, was Sie tun. Wenn Sie einen Artikel anhand seiner numerischen ID laden, müssen Sie nicht entkommen, noch weniger PDO. Sie müssen lediglich sicherstellen, dass ID tatsächlich eine Ganzzahl ist.

Aus einer realistischeren Perspektive besteht die allgemeine Regel nicht darin, PDO/vorbereitete Anweisungen zu verwenden, sondern die richtigen Funktionen zu verwenden, dh Sie müssen verwenden mysql_real_escape_string() anstelle von addslashes() oder mysql_escape_string().

[5.] Kann ein Programmierer das nicht irgendwie noch vermasseln? Worauf sollten sie achten?

Na sicher! Aber es ist nicht "worauf zu achten ist", sondern "zu wissen, was Sie tun".

Sie sehen, eval($_GET['code']) * ist völlig legitim, wenn es an der richtigen Stelle verwendet wird (z. B. ein lokaler PHP Test Runner).

Wenn Sie ein ORM zum Ausführen einer bedingten Abfrage verwenden, geben Sie Code direkt ein. Daher besteht möglicherweise die Möglichkeit, dass Sie SQL-Injection erhalten, wenn Sie dies nicht richtig machen (abhängig vom jeweiligen ORM). (Hypothetisches) Beispiel:

// update() sets the value of a column given a condition
//
//                         .--escaping is automatic here
//                         |                           .--hypothetical SQL injection
//                         v                           v
Db()->update('name',$_GET['newname'])->where(' id = '.$_GET['id']);

(* Ich kann mir nur vorstellen, dass die unzähligen Profis ihren Kopf darüber schlagen.)

13
Christian

Am Ende des Tages muss eine Eingabe erfolgen, um Ihre Abfragen vor SQL Injection zu schützen. Parametrisierte Abfragebibliotheken wie PDO und ADODB verwenden Escape . Sie erzwingen diese Vorgehensweise lediglich auf implizit sichere Weise. Durch die Einschränkung, dass magic_quotes_gpc [~ # ~] nicht [~ # ~] tut, ist dies eine grundlegend fehlerhafte Herangehensweise an das Problem.

1) Flucht kann problematisch sein, wenn Sie nicht verstehen, was Sie tun. Diese Art von Problem kann weiterhin ausgenutzt werden, wenn magic_quotes_gpc aktiviert ist.

mysql_query("select * from users where id=".addslashes($_GET[id]));

PoC Exploit: http: //localhost/vuln.php? Id = sleep ( )

Patch:

mysql_query("select * from users where id='".addslashes($_GET[id])."'");

Lektion: Sie benötigen keine Anführungszeichen, um die SQL-Injection auszunutzen.

2) Nehmen wir an, Sie entkommen nur Anführungszeichen:

mysql_query("select * from users where name='".htmlspecialchars($_GET[name],ENT_QUOTES)."' and id='".htmlspecialchars($_GET[id],ENT_QUOTES)."'");

PoC Exploit: http: //localhost/vuln.php? Name = \& id = + oder + sleep (30)/*

Patch:

mysql_query("select * from users where name='".addslashes($_GET[name])."' and id='".addslashes($_GET[id])."'");

Lektion : Backslashes sind genauso gefährlich wie Anführungszeichen.

3) Was ist mit der Sprachcodierung?

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".addslashes($_GET[name])."'");

PoC Exploit: http: //localhost/vuln.php? Name =% bf% 27 = sleep (30)/*

Patch:

mysql_query("SET CHARACTER SET 'gbk'");
mysql_query("select * from user where name='".mysql_real_escape_string($_GET[name])."'");

Schlussfolgerung:

Das Entweichen ist unbedingt erforderlich, um eine SQL-Injektion in einer Anwendung zu verhindern. In PHP PDO und ADOB sind großartige parametrisierte Abfragebibliotheken, die das Entkommen von Benutzereingaben erzwingen. Das Problem ist, dass viele Programmierer nicht verstehen, was das Entkommen ist. Eine Bibliothek zum Erzwingen dieser Sicherheitsrichtlinie ist vorhanden Die beste Verteidigungsmethode, da Sie die Fluchtregeln nicht verstehen müssen.

9
rook

Informationen zu den DB-spezifischen Escape-Funktionen. Es gibt viele Szenarien, in denen SQL-Injection auftreten kann, obwohl mysql_real_escape_string () verwendet wurde. LIMIT und ORDER BY sind wirklich knifflig!

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

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

oder

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

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

Quelle : Die unerwartete SQL-Injection (wenn das Escaping nicht ausreicht) <- Lesen Sie dies

5
Cut Copy

Filter können umgangen werden und Daten, die in SQL-Anweisungen eingehen, können von mehr Stellen als nur Benutzereingaben stammen. Die Einstiegspunkte in eine von SQL beeinflusste Quelle/Senke können beispielsweise gespeichert werden (höherer Ordnung), aber eindeutig sind HTTP-GET-Parameter und POST-Parameter aus HTML-Formularen nicht die einzigen Benutzermöglichkeiten) Eingang.

Parametrisierte Abfragen machen Ihre SQL-Anweisungen nicht unbedingt frei von Injektionen. Sie erfordern auch eine variable Bindung, das Entfernen von Zeichenfolgenoperationen/-verkettungen und die Vermeidung bestimmter Sicherheitsprobleme mit einer Vielzahl von SQL-Klauseln.

Die meisten Entwickler vergessen auch, ihre Komponenten von Drittanbietern und andere Abhängigkeiten auf SQL-Injection-Probleme zu überprüfen, und erkennen manchmal nicht, dass diese Einschlüsse ihren eigenen Code anfällig machen können.

Am besten beauftragen Sie ein Beratungsunternehmen für Anwendungssicherheit, um Ihre Anwendung (en) auf die Produktionsbereitschaft vorzubereiten und Ihre Appdev-Teams darin zu schulen, Anwendungssicherheitskontrollen in ihre Prozess- und Entwicklungstechnologie einzubauen.

4
atdre

Um Hendricks Antwort zu erweitern. Es ist leicht, sich real_escape_string als Wundermittel vorzustellen, wenn dies in Wirklichkeit nicht der Fall ist. Ich habe gesehen, dass Leute diese Funktion verwenden, wenn sie intval verwenden oder die Eingabe stattdessen in eine Ganzzahl umwandeln möchten. Sie können immer noch injiziert werden, wenn Sie die Escape-Zeichenfolge im falschen Kontext verwenden.

3
getahobby