Schützen htmlspecialchars und mysql_real_escape_string meinen PHP-Code vor Injektion?

Lesezeit: 10 Minuten

Schutzen htmlspecialchars und mysql real escape string meinen PHP Code vor Injektion
Frechweich

Heute früh wurde eine Frage zu Eingabevalidierungsstrategien in Web-Apps gestellt.

Die Top-Antwort zum Zeitpunkt des Schreibens schlägt in vor PHP nur mit htmlspecialchars und mysql_real_escape_string.

Meine Frage ist: Reicht das immer? Gibt es noch mehr, was wir wissen sollten? Wo brechen diese Funktionen zusammen?

Schutzen htmlspecialchars und mysql real escape string meinen PHP Code vor Injektion
Frechweich

Versuchen Sie bei Datenbankabfragen immer, vorbereitete parametrisierte Abfragen zu verwenden. Die mysqli und PDO Bibliotheken unterstützen dies. Dies ist unendlich sicherer als die Verwendung von Escaping-Funktionen wie z mysql_real_escape_string.

Jawohl, mysql_real_escape_string ist praktisch nur eine String-Escape-Funktion. Es ist keine Wunderwaffe. Alles, was es tun wird, ist, gefährliche Zeichen zu maskieren, damit sie sicher in einer einzigen Abfragezeichenfolge verwendet werden können. Wenn Sie Ihre Eingaben jedoch nicht vorher bereinigen, sind Sie anfällig für bestimmte Angriffsvektoren.

Stellen Sie sich folgendes SQL vor:

$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);

Sie sollten erkennen können, dass dies anfällig für Exploits ist.
Stellen Sie sich vor, die id Parameter enthielt den gemeinsamen Angriffsvektor:

1 OR 1=1

Es gibt keine riskanten Zeichen zum Codieren, also wird es direkt durch den Escape-Filter geleitet. Uns verlassen:

SELECT fields FROM table WHERE id= 1 OR 1=1

Das ist ein schöner SQL-Injection-Vektor und würde es dem Angreifer ermöglichen, alle Zeilen zurückzugeben. Oder

1 or is_admin=1 order by id limit 1

was produziert

SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1

Dadurch kann der Angreifer in diesem völlig fiktiven Beispiel die Daten des ersten Administrators zurückgeben.

Obwohl diese Funktionen nützlich sind, müssen sie mit Vorsicht verwendet werden. Sie müssen sicherstellen, dass alle Webeingaben bis zu einem gewissen Grad validiert werden. In diesem Fall sehen wir, dass wir ausgenutzt werden können, weil wir nicht überprüft haben, ob eine Variable, die wir als Zahl verwenden, tatsächlich numerisch ist. In PHP sollten Sie häufig eine Reihe von Funktionen verwenden, um zu überprüfen, ob Eingaben Integer, Gleitkommazahlen, alphanumerische Zeichen usw. sind. Aber wenn es um SQL geht, beachten Sie am meisten den Wert der vorbereiteten Anweisung. Der obige Code wäre sicher gewesen, wenn es sich um eine vorbereitete Anweisung gehandelt hätte, da die Datenbankfunktionen dies gewusst hätten 1 OR 1=1 ist kein gültiges Literal.

Wie für htmlspecialchars(). Das ist ein eigenes Minenfeld.

Es gibt ein echtes Problem in PHP, da es eine ganze Reihe verschiedener HTML-bezogener Escape-Funktionen hat und keine klare Anleitung, welche Funktionen genau was tun.

Erstens, wenn Sie sich in einem HTML-Tag befinden, haben Sie echte Probleme. Ansehen

echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';

Wir befinden uns bereits in einem HTML-Tag, also brauchen wir < oder > nicht, um irgendetwas Gefährliches zu tun. Unser Angriffsvektor könnte einfach sein javascript:alert(document.cookie)

Jetzt sieht das resultierende HTML aus

<img src= "https://stackoverflow.com/questions/110575/javascript:alert(document.cookie)" />

Der Angriff geht direkt durch.

Es wird schlimmer. Warum? da htmlspecialchars (wenn auf diese Weise aufgerufen) codiert nur doppelte Anführungszeichen und nicht einzelne. Also wenn wir hätten

echo "<img src="" . htmlspecialchars($_GET["imagesrc']) . ". />";

Unser böser Angreifer kann jetzt ganz neue Parameter injizieren

pic.png' onclick='location.href=xxx' onmouseover="...

gibt uns

<img src="https://stackoverflow.com/questions/110575/pic.png" onclick='location.href=xxx' onmouseover="..." />

In diesen Fällen gibt es kein Wundermittel, Sie müssen nur die Eingabe selbst santisieren. Wenn Sie versuchen, schlechte Charaktere herauszufiltern, werden Sie sicherlich scheitern. Nehmen Sie einen Whitelist-Ansatz und lassen Sie nur die Zeichen durch, die gut sind. Schaue auf die XSS-Spickzettel für Beispiele, wie vielfältig Vektoren sein können

Auch wenn Sie verwenden htmlspecialchars($string) Außerhalb von HTML-Tags sind Sie immer noch anfällig für Multi-Byte-Zeichensatz-Angriffsvektoren.

Am effektivsten können Sie eine Kombination aus mb_convert_encoding und htmlentities wie folgt verwenden.

$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');

Auch das macht IE6 angreifbar, wegen der Art und Weise, wie es mit UTF umgeht. Sie könnten jedoch auf eine eingeschränktere Codierung wie ISO-8859-1 zurückgreifen, bis die Verwendung von IE6 nachlässt.

Eine eingehendere Studie zu den Multibyte-Problemen finden Sie unter https://stackoverflow.com/a/12118602/1820

  • Das einzige, was hier fehlt, ist, dass das erste Beispiel für die DB-Abfrage … ein einfaches intval() die Injektion lösen würde. Verwenden Sie immer intval() anstelle von mysqlescape…(), wenn Sie eine Zahl und keinen String benötigen.

    –Robert K

    9. April 2009 um 3:15 Uhr

  • und denken Sie daran, dass die Verwendung parametrisierter Abfragen es Ihnen ermöglicht, Daten immer als Daten und nicht als Code zu behandeln. Verwenden Sie eine Bibliothek wie PDO und verwenden Sie nach Möglichkeit parametrisierte Abfragen.

    – Frechheit

    14. April 2009 um 10:47 Uhr

  • Zwei Anmerkungen: 1. Im ersten Beispiel wären Sie auf der sicheren Seite, wenn Sie den Parameter auch in Anführungszeichen setzen, wie $result = "SELECT fields FROM table WHERE id = '".mysql_real_escape_string($_POST['id'])."'"; 2. Im zweiten Fall (Attribut mit URL) gibt es keine Verwendung für htmlspecialchars überhaupt; In diesen Fällen sollten Sie die Eingabe mit einem URL-Codierungsschema codieren, z. B. using rawurlencode. Auf diese Weise kann ein Benutzer nichts einfügen javascript: et al.

    – Marcel Korpel

    27. März 2011 um 20:00 Uhr

  • „htmlspecialchars codiert nur doppelte Anführungszeichen und keine einfachen“: das stimmt nicht, es hängt davon ab, ob Flags gesetzt sind, siehe its Parameter.

    – Marcel Korpel

    30. April 2011 um 22:49 Uhr

  • Dies sollte fett gedruckt werden: Take a whitelist approach and only let through the chars which are good. Einer Blacklist wird immer etwas entgehen. +1

    – Jo Smo

    9. Juli 2014 um 10:15 Uhr

Zusätzlich zu Cheekysofts ausgezeichneter Antwort:

  • Ja, sie werden Sie schützen, aber nur, wenn sie absolut korrekt verwendet werden. Wenn Sie sie falsch verwenden, sind Sie immer noch anfällig und haben möglicherweise andere Probleme (z. B. Datenbeschädigung).
  • Bitte verwenden Sie stattdessen parametrisierte Abfragen (wie oben angegeben). Sie können sie zB über PDO oder über einen Wrapper wie PEAR DB verwenden
  • Stellen Sie sicher, dass magic_quotes_gpc und magic_quotes_runtime immer ausgeschaltet sind und niemals versehentlich eingeschaltet werden, nicht einmal kurz. Dies ist ein früher und zutiefst fehlgeleiteter Versuch der PHP-Entwickler, Sicherheitsprobleme (die Daten zerstören) zu verhindern.

Es gibt nicht wirklich eine Patentlösung zum Verhindern von HTML-Einschleusung (z. B. Cross-Site-Scripting), aber Sie können dies möglicherweise einfacher erreichen, wenn Sie eine Bibliothek oder ein Vorlagensystem für die HTML-Ausgabe verwenden. Lesen Sie die Dokumentation dazu, wie Sie Dinge entsprechend entkommen können.

In HTML müssen Dinge je nach Kontext unterschiedlich maskiert werden. Dies gilt insbesondere für Zeichenfolgen, die in Javascript platziert werden.

Ich würde den obigen Beiträgen definitiv zustimmen, aber ich muss eine kleine Sache als Antwort auf die Antwort von Cheekysoft hinzufügen, insbesondere:

Versuchen Sie bei Datenbankabfragen immer, vorbereitete parametrisierte Abfragen zu verwenden. Die mysqli- und PDO-Bibliotheken unterstützen dies. Dies ist unendlich sicherer als die Verwendung von Escape-Funktionen wie mysql_real_escape_string.

Ja, mysql_real_escape_string ist praktisch nur eine String-Escape-Funktion. Es ist keine Wunderwaffe. Alles, was es tun wird, ist, gefährliche Zeichen zu maskieren, damit sie sicher in einer einzigen Abfragezeichenfolge verwendet werden können. Wenn Sie Ihre Eingaben jedoch nicht vorher bereinigen, sind Sie anfällig für bestimmte Angriffsvektoren.

Stellen Sie sich folgendes SQL vor:

$result = “SELECT fields FROM table WHERE id = “.mysql_real_escape_string($_POST[‘id’]);

Sie sollten erkennen können, dass dies anfällig für Exploits ist. Stellen Sie sich vor, der id-Parameter enthält den gemeinsamen Angriffsvektor:

1 ODER 1=1

Es gibt keine riskanten Zeichen zum Codieren, also wird es direkt durch den Escape-Filter geleitet. Uns verlassen:

Felder AUS Tabelle AUSWÄHLEN, WO ID = 1 ODER 1=1

Ich habe eine schnelle kleine Funktion codiert, die ich in meine Datenbankklasse eingefügt habe, die alles entfernt, was keine Zahl ist. Es verwendet preg_replace, also gibt es wahrscheinlich eine etwas optimiertere Funktion, aber es funktioniert zur Not …

function Numbers($input) {
  $input = preg_replace("/[^0-9]/","", $input);
  if($input == '') $input = 0;
  return $input;
}

Also anstatt zu verwenden

$result = “SELECT fields FROM table WHERE id = “.mysqlrealescapestring(“1 OR 1=1”);

ich würde … benutzen

$result = “SELECT fields FROM table WHERE id = “.Numbers(“1 OR 1=1”);

und es würde die Abfrage sicher ausführen

Felder AUS Tabelle AUSWÄHLEN, WO ID = 111

Sicher, das hat gerade verhindert, dass die richtige Zeile angezeigt wird, aber ich denke nicht, dass das ein großes Problem für jeden ist, der versucht, SQL in Ihre Site einzufügen;)

  • Perfekt! Dies ist genau die Art der Desinfektion, die Sie benötigen. Der ursprüngliche Code ist fehlgeschlagen, weil er nicht bestätigt hat, dass eine Zahl numerisch ist. Ihr Code tut dies. Sie sollten Numbers() für alle ganzzahligen Variablen aufrufen, deren Werte von außerhalb der Codebasis stammen.

    – Frechheit

    22. September 2008 um 22:44 Uhr

  • Es ist erwähnenswert, dass intval() dafür perfekt funktioniert, da PHP für Sie automatisch Integer in Strings umwandelt.

    – Adam Ernst

    12. Oktober 2008 um 23:45 Uhr

  • Ich bevorzuge Intervall. Es verwandelt 1abc2 in 1, nicht 12.

    – Jmucchiello

    5. Februar 2009 um 22:10 Uhr

  • Intervall ist besser, besonders bei ID. Wenn es beschädigt wurde, ist es meistens genauso wie oben, 1 oder 1 = 1. Sie sollten wirklich nicht die Ausweise anderer Leute preisgeben. Intval gibt also die richtige ID zurück. Danach sollten Sie überprüfen, ob die ursprünglichen und bereinigten Werte gleich sind. Es ist eine großartige Möglichkeit, Angriffe nicht nur zu stoppen, sondern die Angreifer zu finden.

    – Dreieinigkeit

    17. Oktober 2014 um 16:21 Uhr


  • Die falsche Zeile wäre verheerend, wenn Sie persönliche Daten anzeigen, Sie würden die Informationen eines anderen Benutzers sehen! stattdessen wäre es besser zu überprüfen return preg_match('/^[0-9]+$/',$input) ? $input : 0;

    – Frank Forte

    31. Januar 2016 um 19:47 Uhr


Ein wichtiger Teil dieses Puzzles sind Kontexte. Jemand, der “1 OR 1=1” als ID sendet, ist kein Problem, wenn Sie jedes Argument in Ihrer Abfrage angeben:

SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"

Was in … resultiert:

SELECT fields FROM table WHERE id='1 OR 1=1'

was unwirksam ist. Da Sie die Zeichenfolge maskieren, kann die Eingabe nicht aus dem Zeichenfolgenkontext ausbrechen. Ich habe dies bis Version 5.0.45 von MySQL getestet, und die Verwendung eines Zeichenfolgenkontexts für eine Integer-Spalte verursacht keine Probleme.

$result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id'];

Funktioniert gut, sogar noch besser auf 64-Bit-Systemen. Achten Sie jedoch auf die Einschränkungen Ihres Systems bei der Adressierung großer Zahlen, aber für Datenbank-IDs funktioniert dies in 99% der Fälle hervorragend.

Sie sollten auch eine einzelne Funktion/Methode zum Bereinigen Ihrer Werte verwenden. Auch wenn diese Funktion nur ein Wrapper für mysql_real_escape_string() ist. Warum? Denn eines Tages, wenn ein Exploit für Ihre bevorzugte Methode zum Bereinigen von Daten gefunden wird, müssen Sie ihn nur an einer Stelle aktualisieren, anstatt systemweit zu suchen und zu ersetzen.

1646930650 224 Schutzen htmlspecialchars und mysql real escape string meinen PHP Code vor Injektion
Jarett L

warum, oh WARUM, würden Sie nicht Anführungszeichen um Benutzereingaben in Ihre SQL-Anweisung aufnehmen? scheint ziemlich dumm, es nicht zu tun! Das Einfügen von Anführungszeichen in Ihre SQL-Anweisung würde “1 oder 1 = 1” zu einem erfolglosen Versuch machen, oder?

Sie sagen also jetzt: “Was ist, wenn der Benutzer ein Anführungszeichen (oder doppelte Anführungszeichen) in die Eingabe einfügt?”

Nun, einfache Lösung dafür: Entfernen Sie einfach die vom Benutzer eingegebenen Anführungszeichen. z.B: input =~ s/'//g;. jetzt scheint es mir sowieso, dass Benutzereingaben gesichert wären …

988480cookie-checkSchützen htmlspecialchars und mysql_real_escape_string meinen PHP-Code vor Injektion?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy