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 kein Wundermittel. Alles, was es tun wird, ist, gefährliche Zeichen zu entkommen, damit sie sicher in einer einzelnen Abfragezeichenfolge verwendet werden können. Wenn Sie Ihre Eingaben jedoch nicht im Voraus bereinigen, sind Sie für bestimmte Angriffsmethoden anfällig.
Stellen Sie sich folgendes SQL vor:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Sie sollten sehen können, dass dies anfällig für Exploits ist.
Stellen Sie sich vor, der id
Parameter enthält den gemeinsamen Angriffsvektor:
1 OR 1=1
Es gibt keine riskanten Zeichen, die codiert werden müssen, sodass sie direkt durch den entweichenden Filter geleitet werden. Verlassen uns:
SELECT fields FROM table WHERE id= 1 OR 1=1
Dies ist ein schöner SQL-Injection-Vektor, der es dem Angreifer ermöglichen würde, 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 die Details des ersten Administrators in diesem vollständig fiktiven Beispiel zurückgeben.
Diese Funktionen sind zwar nützlich, müssen jedoch mit Vorsicht verwendet werden. Sie müssen sicherstellen, dass alle Web-Eingaben bis zu einem gewissen Grad validiert sind. In diesem Fall sehen wir, dass wir ausgenutzt werden können, weil wir nicht überprüft haben, ob eine Variable, die wir als Zahl verwendet haben, tatsächlich numerisch ist. In PHP sollten Sie häufig eine Reihe von Funktionen verwenden, um zu überprüfen, ob Eingaben Ganzzahlen, Gleitkommazahlen, alphanumerische Zeichen usw. sind. Beachten Sie jedoch bei SQL den Wert der vorbereiteten Anweisung am meisten. Der obige Code wäre sicher gewesen, wenn es sich um eine vorbereitete Anweisung handelte, da die Datenbankfunktionen gewusst hätten, dass 1 OR 1=1
es sich nicht um ein gültiges Literal handelt.
Wie für htmlspecialchars()
. Das ist ein eigenes Minenfeld.
Es gibt ein echtes Problem in PHP, dass es eine ganze Auswahl verschiedener HTML-bezogener Escape-Funktionen gibt und keine klare Anleitung, welche Funktionen genau was tun.
Erstens, wenn Sie sich in einem HTML-Tag befinden, sind Sie in echten Schwierigkeiten. Ansehen
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Wir befinden uns bereits in einem HTML-Tag, sodass wir <oder> nichts Gefährliches tun müssen. Unser Angriffsvektor könnte einfach seinjavascript:alert(document.cookie)
Jetzt sieht das resultierende HTML so aus
<img src= "javascript:alert(document.cookie)" />
Der Angriff kommt direkt durch.
Es wird schlimmer. Warum? weil htmlspecialchars
(wenn es so genannt wird) nur doppelte Anführungszeichen und keine einfachen Anführungszeichen codiert. Also wenn wir hätten
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Unser böser Angreifer kann jetzt ganz neue Parameter einfügen
pic.png' onclick='location.href=xxx' onmouseover='...
gibt uns
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
In diesen Fällen gibt es keine magische Kugel, Sie müssen nur die Eingabe selbst santisieren. Wenn Sie versuchen, schlechte Zeichen herauszufiltern, werden Sie sicherlich scheitern. Nehmen Sie einen Whitelist-Ansatz und lassen Sie nur die Zeichen durch, die gut sind. Schauen Sie sich das XSS-Spickzettel an, um Beispiele dafür zu finden, wie unterschiedlich Vektoren sein können
Selbst wenn Sie htmlspecialchars($string)
außerhalb von HTML-Tags verwenden, sind Sie dennoch 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');
Selbst dies macht IE6 aufgrund der Art und Weise, wie es mit UTF umgeht, anfällig. Sie können jedoch auf eine eingeschränktere Codierung wie ISO-8859-1 zurückgreifen, bis die IE6-Nutzung abfällt.
Eine ausführlichere Studie zu den Multibyte-Problemen finden Sie unter https://stackoverflow.com/a/12118602/1820
$result = "SELECT fields FROM table WHERE id = '".mysql_real_escape_string($_POST['id'])."'";
. B. 2. Im zweiten Fall (Attribut mit URL) ist dies überhaupt nicht sinnvollhtmlspecialchars
. In diesen Fällen sollten Sie die Eingabe mit einem URL-Codierungsschema codieren, zrawurlencode
. Auf diese Weise kann ein Benutzerjavascript:
et al. Nicht einfügen .Take a whitelist approach and only let through the chars which are good.
Eine schwarze Liste wird immer etwas verpassen. +1Zusätzlich zu Cheekysofts hervorragender Antwort:
Es gibt nicht wirklich eine Silberkugel, um die HTML-Injection zu verhindern (z. B. Cross-Site-Scripting), aber Sie können dies möglicherweise einfacher erreichen, wenn Sie eine Bibliothek oder ein Template-System für die Ausgabe von HTML verwenden. Lesen Sie dazu die Dokumentation, um zu erfahren, wie Sie den Dingen angemessen entkommen können.
In HTML müssen die Dinge je nach Kontext unterschiedlich maskiert werden. Dies gilt insbesondere für Zeichenfolgen, die in Javascript eingefügt werden.
quelle
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:
Ich habe eine kleine Funktion codiert, die ich in meine Datenbankklasse eingefügt habe und die alles entfernt, was keine Zahl ist. Es verwendet preg_replace, daher gibt es wahrscheinlich eine etwas optimierte Funktion, aber es funktioniert zur Not ...
Also anstatt zu benutzen
ich würde ... benutzen
und es würde die Abfrage sicher ausführen
Sicher, das hat es nur daran gehindert, die richtige Zeile anzuzeigen, aber ich denke nicht, dass dies ein großes Problem für jeden ist, der versucht, SQL in Ihre Site einzufügen;)
quelle
return preg_match('/^[0-9]+$/',$input) ? $input : 0;
Ein wichtiges Teil dieses Puzzles sind Kontexte. Jemand, der "1 OR 1 = 1" als ID sendet, ist kein Problem, wenn Sie jedes Argument in Ihrer Abfrage zitieren:
Was in ... endet:
das ist unwirksam. Da Sie der Zeichenfolge entkommen, kann die Eingabe nicht aus dem Zeichenfolgenkontext herausbrechen. Ich habe dies bis zur Version 5.0.45 von MySQL getestet, und die Verwendung eines Zeichenfolgenkontexts für eine Ganzzahlspalte verursacht keine Probleme.
quelle
Funktioniert gut, noch besser auf 64-Bit-Systemen. Beachten Sie die Einschränkungen Ihres Systems bei der Adressierung großer Zahlen. Bei Datenbank-IDs funktioniert dies jedoch in 99% der Fälle hervorragend.
Sie sollten auch eine einzige Funktion / Methode zum Reinigen 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 diese nur an einer Stelle aktualisieren und nicht systemweit suchen und ersetzen.
quelle
Warum, oh WARUM, würden Sie keine Anführungszeichen für Benutzereingaben in Ihre SQL-Anweisung aufnehmen? scheint ziemlich dumm nicht zu! Das Einfügen von Anführungszeichen in Ihre SQL-Anweisung würde "1 oder 1 = 1" zu einem erfolglosen Versuch machen, nicht wahr?
Nun sagen Sie: "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. zB :
input =~ s/'//g;
. jetzt scheint es mir sowieso, dass Benutzereingaben gesichert wären ...quelle