1271 Stimmen

Wie kann ich Benutzereingaben mit PHP bereinigen?

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?

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? :)

26voto

jasonbar Punkte 12905

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.

20voto

dangel Punkte 1466

Mit PHP 5.2 wurde die filter_var Funktion.

Es unterstützt eine große Anzahl von SANITIZE , VALIDATE Filter.

18voto

webaholik Punkte 1370

Es gibt keine Auffangfunktion, denn es gibt mehrere Anliegen, die behandelt werden müssen.

  1. 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).

  1. 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;
    }
  1. 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 o print um vom Benutzer eingegebene Werte anzuzeigen, verwenden Sie htmlspecialchars 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
  1. Rufen Sie externe Shell-Befehle mit exec() o system() Funktionen, oder zum backtick 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 verwenden escapeshellcmd wenn Sie den gesamten Befehl abbrechen möchten ODER escapeshellarg um einzelnen Argumenten zu entgehen.

18voto

Mark Martin Punkte 356

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.

15voto

Hamish Downer Punkte 15913

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).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X