Gibt es irgendwo eine Auffangfunktion, die gut funktioniert, um Benutzereingaben für SQL-Injection- und XSS-Angriffe zu säubern und gleichzeitig bestimmte Arten von HTML-Tags zuzulassen?
Antworten
Zu viele Anzeigen?Um das XSS-Problem zu lösen, sehen Sie sich Folgendes an HTML-Reiniger . Es ist ziemlich konfigurierbar und hat eine anständige Erfolgsbilanz.
Die Lösung für SQL-Injection-Angriffe ist die Verwendung von vorbereiteten Anweisungen. Die PDO-Bibliothek und die mysqli-Erweiterung unterstützen diese.
Mit PHP 5.2 wurde die filter_var
Funktion.
Es unterstützt eine große Anzahl von SANITIZE
, VALIDATE
Filter.
Es gibt keine Auffangfunktion, denn es gibt mehrere Anliegen, die behandelt werden müssen.
- SQL-Einschleusung - Heutzutage sollte im Allgemeinen jedes PHP-Projekt mit vorbereitete Anweisungen über PHP Data Objects (PDO) als beste Praxis, Verhinderung eines Fehlers durch ein falsches Anführungszeichen sowie eine umfassende Lösung gegen Injektionen . Es ist auch die flexibelste und sicherste Art, auf Ihre Datenbank zuzugreifen.
チェックする (Das einzige richtige) PDO-Tutorial für so ziemlich alles, was Sie über PDO wissen müssen. (Ein herzliches Dankeschön an @YourCommonSense, den besten SO-Mitarbeiter, für diese großartige Ressource zu diesem Thema).
- XSS - Sanitize Daten auf dem Weg in...
-
HTML-Reiniger gibt es schon seit langem und wird immer noch aktiv aktualisiert. Sie können es verwenden, um bösartige Eingaben zu bereinigen und gleichzeitig eine großzügige und konfigurierbare Whitelist von Tags zu ermöglichen. Funktioniert hervorragend mit vielen WYSIWYG-Editoren, könnte aber für einige Anwendungsfälle zu schwer sein.
-
In anderen Fällen, in denen wir HTML/Javascript überhaupt nicht akzeptieren wollen, habe ich diese einfache Funktion als nützlich empfunden (und sie hat mehrere Prüfungen gegen XSS bestanden):
/* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }
- XSS - Daten auf dem Weg nach draußen säubern... Wenn Sie nicht garantieren können, dass die Daten ordnungsgemäß bereinigt wurden, bevor Sie sie Ihrer Datenbank hinzufügen, müssen Sie sie bereinigen, bevor Sie sie dem Benutzer anzeigen. Dazu können wir diese nützlichen PHP-Funktionen nutzen:
- Wenn Sie anrufen
echo
oprint
um vom Benutzer eingegebene Werte anzuzeigen, verwenden Siehtmlspecialchars
es sei denn, die Daten wurden ordnungsgemäß bereinigt und sind sicher und dürfen HTML anzeigen. json_encode
ist ein sicherer Weg, um vom Benutzer gelieferte Werte von PHP zu Javascript zu übertragen
- Rufen Sie externe Shell-Befehle mit
exec()
osystem()
Funktionen, oder zumbacktick
Betreiber? Wenn ja, haben Sie neben SQL Injection und XSS möglicherweise noch ein weiteres Problem, das Sie angehen müssen, Benutzer, die bösartige Befehle auf Ihrem Server ausführen . Sie müssen Folgendes verwendenescapeshellcmd
wenn Sie den gesamten Befehl abbrechen möchten ODERescapeshellarg
um einzelnen Argumenten zu entgehen.
Methoden zur Bereinigung von Benutzereingaben mit PHP:
-
Verwenden Sie moderne Versionen von MySQL und PHP.
-
Zeichensatz explizit festlegen:
- $mysqli->set_charset("utf8");Handbuch
- $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);Handbuch
- $pdo->exec("set names utf8");Handbuch
- $pdo = new PDO( "mysql:host=$host;dbname=$db", $user, $pass, array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ) );Handbuch
-
mysql_set_charset('utf8')[veraltet in PHP 5.5.0, entfernt in PHP 7.0.0].
-
Verwenden Sie sichere Zeichensätze:
- Wählen Sie utf8, latin1, ascii.., verwenden Sie keine anfälligen Zeichensätze big5, cp932, gb2312, gbk, sjis.
-
Verwenden Sie eine räumliche Funktion:
-
MySQLi vorbereitete Anweisungen:
$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "' OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute(); -
PDO::quote() - setzt Anführungszeichen um die Eingabezeichenkette (falls erforderlich) und bricht Sonderzeichen innerhalb der Eingabezeichenkette ab, wobei ein für den zugrunde liegenden Treiber geeigneter Anführungsstil verwendet wird:
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set $pdo->setAttribute(PDO::ATTR\_EMULATE\_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection) $var = $pdo->quote("' OR 1=1 /\*");not only escapes the literal, but also quotes it (in single-quote ' characters) $stmt = $pdo->query("SELECT \* FROM test WHERE name = $var LIMIT 1");
-
PDO Vorbereitete Erklärungen vs MySQLi Prepared Statements unterstützt mehr Datenbanktreiber und benannte Parameter:
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set $pdo->setAttribute(PDO::ATTR\_EMULATE\_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection) $stmt = $pdo->prepare('SELECT \* FROM test WHERE name = ? LIMIT 1'); $stmt->execute(\["' OR 1=1 /\*"\]);
-
mysql_real_escape_string[veraltet in PHP 5.5.0, entfernt in PHP 7.0.0]. -
mysqli_real_escape_string Umgeht Sonderzeichen in einer Zeichenkette für die Verwendung in einer SQL-Anweisung, wobei der aktuelle Zeichensatz der Verbindung berücksichtigt wird. Es wird jedoch empfohlen, Prepared Statements zu verwenden, da es sich dabei nicht einfach um escapte Strings handelt, sondern eine Anweisung einen vollständigen Abfrageausführungsplan enthält, einschließlich der Tabellen und Indizes, die verwendet werden sollen, was eine optimierte Methode darstellt.
-
Verwenden Sie einfache Anführungszeichen (' ') um Ihre Variablen innerhalb Ihrer Abfrage.
-
-
Prüfen Sie, ob die Variable das enthält, was Sie erwarten:
-
Wenn Sie eine Ganzzahl erwarten, verwenden Sie: ctype_digit — Check for numeric character(s);
$value = (int) $value;
$value = intval($value);
$var = filter_var('0755', FILTER_VALIDATE_INT, $options); -
Für Streicher verwenden: is_string() — Find whether the type of a variable is string
使用方法 Filterfunktion filter_var() - filtert eine Variable mit einem bestimmten Filter:
$email = filter_var($email, FILTER_SANITIZE_EMAIL);
$newstr = filter_var($str, FILTER_SANITIZE_STRING);mehr vordefinierte Filter -
filter_input() - Ruft eine bestimmte externe Variable nach Namen ab und filtert sie optional: $search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
-
preg_match() - Führen Sie eine Übereinstimmung mit einem regulären Ausdruck durch;
-
Schreiben Sie Ihre eigene Validierungsfunktion.
-
Ein Trick, der in dem speziellen Fall helfen kann, dass Sie eine Seite haben wie /mypage?id=53
und Sie die id in einer WHERE-Klausel verwenden, müssen Sie sicherstellen, dass id definitiv eine ganze Zahl ist, etwa so:
if (isset($_GET['id'])) {
$id = $_GET['id'];
settype($id, 'integer');
$result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
# now use the result
}
Aber das schließt natürlich nur einen bestimmten Angriff aus, also lesen Sie alle anderen Antworten. (Und ja, ich weiß, dass der Code oben nicht toll ist, aber er zeigt die spezifische Verteidigung).
48 Stimmen
Um Sql-Injection zu vermeiden, verwendet man heutzutage PDO oder MySQLi.
97 Stimmen
Die Verwendung von PDO oder MySQLi ist nicht genug. Wenn Sie Ihre SQL-Anweisungen mit nicht vertrauenswürdigen Daten erstellen, wie
select * from users where name='$name'
dann spielt es keine Rolle, ob Sie PDO oder MySQLi oder MySQL verwenden. Sie sind immer noch in Gefahr. Sie müssen parametrisierte Abfragen verwenden oder, wenn es sein muss, Escape-Mechanismen für Ihre Daten einsetzen, aber das ist weit weniger empfehlenswert.30 Stimmen
@AndyLester Wollen Sie damit andeuten, dass jemand PDO ohne vorbereitete Anweisungen verwendet? :)
76 Stimmen
Ich will damit sagen, dass "Benutzen Sie PDO oder MySQLi" nicht genug Information ist, um Anfängern zu erklären, wie man sie sicher benutzt. Sie und ich wissen, dass vorbereitete Anweisungen wichtig sind, aber ich gehe nicht davon aus, dass jeder, der diese Frage liest, dies weiß. Deshalb habe ich die ausdrücklichen Anweisungen hinzugefügt.
0 Stimmen
Ist also die Verwendung von PDO::prepare() oder PDO::quote() in diesem Fall die richtige Antwort?
37 Stimmen
Die Bemerkung von Andy ist völlig richtig. Ich habe meine mysql-Website vor kurzem auf PDO umgestellt, weil ich dachte, dass ich nun irgendwie vor Injektionsangriffen sicher sei. Erst während des Prozesses stellte ich fest, dass einige meiner SQL-Anweisungen immer noch mit Benutzereingaben erstellt wurden. Das habe ich dann mit Prepared Statements behoben. Einem völligen Neuling ist nicht ganz klar, dass es einen Unterschied gibt, da viele Experten zwar die Verwendung von PDO erwähnen, aber nicht auf die Notwendigkeit von vorbereiteten Anweisungen hinweisen. Die Annahme ist, dass dies offensichtlich ist. Aber nicht für einen Neuling.
0 Stimmen
Ich schätze, diese Antwort funktioniert: stackoverflow.com/questions/60174/
12 Stimmen
@Christian: GhostRider und AndyLester haben Recht. Lasst uns dies eine Lektion in Kommunikation sein. Ich war einmal ein Anfänger und es war scheiße, weil Experten einfach nicht wissen, wie man kommuniziert.
1 Stimmen
Die Bemerkung von Andy ist völlig richtig. Ich habe vor kurzem meine mysql-Website auf PDO umgestellt und dachte, dass ich nun irgendwie vor Injektionsangriffen sicher sei. Erst während des Prozesses stellte ich fest, dass einige meiner SQL-Anweisungen immer noch mit Benutzereingaben erstellt wurden. Das habe ich dann mit vorbereiteten Anweisungen behoben. Für einen absoluten Neuling ist es nicht ganz klar, dass es einen Unterschied gibt, da viele Experten die Verwendung von PDO erwähnen, aber nicht näher darauf eingehen.