Wie kann man XSS mit HTML / PHP verhindern?

256

Wie verhindere ich XSS (Cross-Site Scripting) nur mit HTML und PHP?

Ich habe zahlreiche andere Beiträge zu diesem Thema gesehen, aber ich habe keinen Artikel gefunden, der klar und präzise beschreibt, wie XSS tatsächlich verhindert werden kann.

Tim Tim
quelle
3
Nur ein Hinweis, dass dies den Fall nicht löst, in dem Sie Benutzereingaben als HTML-Attribut verwenden möchten. Zum Beispiel die Quell-URL eines Bildes. Kein gewöhnlicher Fall, aber leicht zu vergessen.
Michael Mior
@ MichaelMior hier ist eine Lösung, um XSS in hrefoder srcHTML-Attribut zu verhindern : stackoverflow.com/questions/19047119/…
Taufe
Es gibt einen schönen Artikel hier , die erklärt , XSS und wie man es verhindern in verschiedenen Sprachen (inkl. PHP).
XCore

Antworten:

296

Grundsätzlich müssen Sie die Funktion htmlspecialchars()immer dann verwenden, wenn Sie etwas an den Browser ausgeben möchten, das von der Benutzereingabe stammt.

Die richtige Art, diese Funktion zu verwenden, ist ungefähr so:

echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');

Die Google Code University bietet außerdem folgende sehr lehrreiche Videos zur Web-Sicherheit:

Alix Axel
quelle
7
@ TimTim: In den meisten Fällen ja. Wenn Sie jedoch HTML-Eingaben zulassen müssen, wird es etwas schwieriger, und wenn dies der Fall ist, empfehle ich Ihnen, etwas wie htmlpurifier.org
Alix Axel
@Alix Axel, so ist die Antwort htmlspecialchars zu verwenden oder verwenden htmlpurifier.org ?
TimTim
3
Wenn Sie HTML-Eingaben akzeptieren müssen, verwenden Sie HTML Purifier, falls nicht htmlspecialchars().
Alix Axel
9
htmlspecialchars oder htmlentities? Überprüfen Sie hier stackoverflow.com/questions/46483/…
kiranvj
4
Meistens ist es richtig, aber es ist nicht so einfach. Sie sollten in Betracht ziehen, nicht vertrauenswürdige Zeichenfolgen in HTML, Js, Css und nicht vertrauenswürdige HTML in HTML einzufügen. Schauen Sie sich das an: owasp.org/index.php/…
Bronzemann
41

Eine meiner Lieblingsreferenzen bei OWASP ist das Cross-Site Scripting Erklärung für denn obwohl es eine große Anzahl von XSS-Angriffsvektoren gibt, kann das Befolgen einiger Regeln die Mehrheit von ihnen stark verteidigen!

Dies ist PHP Security Cheat Sheet

Wahyu Kristianto
quelle
7
Ich auch .. Dies ist XSS Filter Evasion Cheat Sheet owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
1
Nicht gerade XSS, aber ich denke, XSS und CSRF sind häufig verwechselt
Simon
2
Diese Seite existiert nicht mehr
Mazzy
1
@ Mazzy letzten Cache web.archive.org/web/20180817180409/owasp.org/index.php/…
Wahyu Kristianto
15

Einer der wichtigsten Schritte besteht darin, Benutzereingaben zu bereinigen, bevor sie verarbeitet und / oder an den Browser zurückgegeben werden. PHP hat einige " Filter " " -Funktionen, die verwendet werden können.

Die Form, die XSS-Angriffe normalerweise haben, besteht darin, einen Link zu einem externen Javascript einzufügen, das böswillige Absichten für den Benutzer enthält. Lesen Sie mehr darüber hier .

Sie möchten auch Ihre Website testen - ich kann das Firefox-Add-On XSS Me empfehlen .

James Kolpack
quelle
Was brauche ich, um sicherzustellen, dass ich die Eingabe genau bereinige? Gibt es ein bestimmtes Zeichen / eine bestimmte Zeichenfolge, auf die ich achten muss?
TimTim
27
@ TimTim - nein. Alle Benutzereingaben sollten immer als inhärent feindlich angesehen werden.
Zombat
Außerdem können interne Daten (Mitarbeiter, Systemadministrator usw.) unsicher sein. Sie sollten die mit Interpretation angezeigten Daten (mit Protokolldatum und Benutzer) identifizieren und überwachen.
Samuel Dauzon
9

In der Reihenfolge der Präferenz:

  1. Wenn Sie eine Template-Engine (z. B. Twig, Smarty, Blade) verwenden, überprüfen Sie, ob diese eine kontextsensitive Escape-Funktion bietet. Ich weiß aus Erfahrung, dass Twig es tut.{{ var|e('html_attr') }}
  2. Wenn Sie HTML zulassen möchten, verwenden Sie HTML Purifier . Selbst wenn Sie glauben, nur Markdown oder ReStructuredText zu akzeptieren, möchten Sie den HTML-Code dieser Markup-Sprachen bereinigen.
  3. Verwenden Sie andernfalls htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)und stellen Sie sicher, dass der Rest Ihres Dokuments denselben Zeichensatz wie verwendet $charset. In den meisten Fällen,'UTF-8' ist der gewünschte Zeichensatz.

Stellen Sie außerdem sicher, dass Sie bei der Ausgabe und nicht bei der Eingabe maskieren .

Scott Arciszewski
quelle
7

Cross-Posting als konsolidierte Referenz aus der SO-Dokumentation Beta, die offline geschaltet wird.

Problem

Cross-Site-Scripting ist die unbeabsichtigte Ausführung von Remotecode durch einen Webclient. Jede Webanwendung kann sich XSS aussetzen, wenn sie Eingaben von einem Benutzer entgegennimmt und diese direkt auf einer Webseite ausgibt. Wenn die Eingabe HTML oder JavaScript enthält, kann Remotecode ausgeführt werden, wenn dieser Inhalt vom Webclient gerendert wird.

Wenn beispielsweise eine Seite eines Drittanbieters eine JavaScript-Datei enthält:

// http://example.com/runme.js
document.write("I'm running");

Und eine PHP-Anwendung gibt direkt eine übergebene Zeichenfolge aus:

<?php
echo '<div>' . $_GET['input'] . '</div>';

Wenn ein nicht aktivierter GET-Parameter enthält, <script src="http://example.com/runme.js"></script>lautet die Ausgabe des PHP-Skripts:

<div><script src="http://example.com/runme.js"></script></div>

Das JavaScript eines Drittanbieters wird ausgeführt und der Benutzer sieht auf der Webseite "Ich laufe".

Lösung

Vertrauen Sie in der Regel niemals den Eingaben eines Kunden. Jeder GET-, POST- und Cookie-Wert kann alles sein und sollte daher validiert werden. Wenn Sie einen dieser Werte ausgeben, maskieren Sie diese, damit sie nicht auf unerwartete Weise ausgewertet werden.

Beachten Sie, dass selbst in den einfachsten Anwendungen Daten verschoben werden können und es schwierig ist, alle Quellen im Auge zu behalten. Daher wird empfohlen, die Ausgabe immer zu umgehen.

PHP bietet je nach Kontext einige Möglichkeiten, der Ausgabe zu entgehen.

Filterfunktionen

PHPs Filterfunktionen erlauben die Eingabedaten an den PHP - Skript zu hygienisiert oder validiert in vielerlei Hinsicht . Sie sind nützlich beim Speichern oder Ausgeben von Client-Eingaben.

HTML-Codierung

htmlspecialcharskonvertiert alle "HTML-Sonderzeichen" in ihre HTML-Codierungen, was bedeutet, dass sie dann nicht als Standard-HTML verarbeitet werden. So beheben Sie unser vorheriges Beispiel mit dieser Methode:

<?php
echo '<div>' . htmlspecialchars($_GET['input']) . '</div>';
// or
echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';

Würde ausgeben:

<div>&lt;script src=&quot;http://example.com/runme.js&quot;&gt;&lt;/script&gt;</div>

Alles innerhalb des <div>Tags wird vom Browser nicht als JavaScript-Tag interpretiert, sondern als einfacher Textknoten. Der Benutzer wird sicher sehen:

<script src="http://example.com/runme.js"></script>

URL-Codierung

Bei der Ausgabe einer dynamisch generierten URL bietet PHP die urlencodeFunktion, gültige URLs sicher auszugeben. Wenn ein Benutzer beispielsweise Daten eingeben kann, die Teil eines anderen GET-Parameters werden:

<?php
$input = urlencode($_GET['input']);
// or
$input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL);
echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';

Alle böswilligen Eingaben werden in einen verschlüsselten URL-Parameter konvertiert.

Verwendung spezialisierter externer Bibliotheken oder OWASP AntiSamy-Listen

Manchmal möchten Sie HTML oder andere Code-Eingaben senden. Sie müssen eine Liste autorisierter Wörter (weiße Liste) und nicht autorisierter Wörter (schwarze Liste) führen.

Sie können Standardlisten herunterladen, die auf der OWASP AntiSamy-Website verfügbar sind . Jede Liste ist für eine bestimmte Art von Interaktion geeignet (ebay api, tinyMCE usw.). Und es ist Open Source.

Es gibt Bibliotheken, um HTML zu filtern und XSS-Angriffe für den allgemeinen Fall zu verhindern und mindestens so gut wie AntiSamy-Listen mit sehr einfacher Verwendung auszuführen. Zum Beispiel haben Sie HTML Purifier

Matt S.
quelle
5

Viele Frameworks helfen beim Umgang mit XSS auf verschiedene Arten. Wenn Sie Ihre eigenen rollen oder XSS- Probleme haben , können wir filter_input_array (verfügbar in PHP 5> = 5.2.0, PHP 7) nutzen. Normalerweise füge ich dieses Snippet meinem SessionController hinzu, da alle Aufrufe dort vor jedem anderen Controller durchgeführt werden interagiert mit den Daten. Auf diese Weise werden alle Benutzereingaben an einem zentralen Ort bereinigt. Wenn dies zu Beginn eines Projekts oder bevor Ihre Datenbank vergiftet wird, sollten Sie zum Zeitpunkt der Ausgabe keine Probleme haben ... stoppt Müll rein, Müll raus.

/* Prevent XSS input */
$_GET   = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST  = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
/* I prefer not to use $_REQUEST...but for those who do: */
$_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST;

Mit dem obigen Befehl werden ALLE HTML- und Skript-Tags entfernt. Wenn Sie eine Lösung benötigen, die sichere Tags basierend auf einer Whitelist ermöglicht, lesen Sie HTML Purifier .


Wenn Ihre Datenbank bereits vergiftet ist oder Sie zum Zeitpunkt der Ausgabe mit XSS arbeiten möchten, empfiehlt OWASP , eine benutzerdefinierte Wrapper-Funktion für zu erstellen echound diese ÜBERALL zu verwenden, wo Sie vom Benutzer bereitgestellte Werte ausgeben:

//xss mitigation functions
function xssafe($data,$encoding='UTF-8')
{
   return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);
}
function xecho($data)
{
   echo xssafe($data);
}
Webaholik
quelle
2

Sie können auch einige XSS-bezogene HTTP-Antwortheader über festlegen header(...)

X-XSS-Schutz "1; Modus = Block"

Natürlich ist der XSS-Schutzmodus des Browsers aktiviert.

Inhaltssicherheitsrichtlinie "default-src 'self'; ..."

um die serverseitige Inhaltssicherheit zu aktivieren. Weitere Informationen zu CSP (Content Security Policy) finden Sie in diesem Dokument: http://content-security-policy.com/ Insbesondere das Einrichten von CSP zum Blockieren von Inline-Skripten und externen Skriptquellen ist für XSS hilfreich.

Eine allgemeine Liste nützlicher HTTP-Antwortheader zur Sicherheit Ihrer Webanwendung finden Sie unter OWASP: https://www.owasp.org/index.php/List_of_useful_HTTP_headers

chris
quelle
1
<?php
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

// Remove javascript: and vbscript: protocols
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

do
{
    // Remove really unwanted tags
    $old_data = $data;
    $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);

// we are done...
return $data;
}
Abdo-Host
quelle
5
Sie sollten es nicht so verwenden, preg_replacewie es evalfür Ihre Eingabe verwendet wird. owasp.org/index.php/PHP_Security_Cheat_Sheet#Code_Injection
CrabLab
0

Verwenden Sie htmlspecialcharsauf PHP. Vermeiden Sie bei HTML die Verwendung von:

element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);

wo varwird vom Benutzer gesteuert .

Versuchen eval(var)Sie natürlich auch zu vermeiden , wenn Sie eines von ihnen verwenden müssen, dann versuchen Sie, JS zu maskieren, HTML zu maskieren und Sie müssen möglicherweise etwas mehr tun, aber für die Grundlagen sollte dies ausreichen.

Pablo
quelle
0

Der beste Weg, um Ihre Eingabe zu schützen, ist die Verwendungsfunktion htmlentities. Beispiel:

htmlentities($target, ENT_QUOTES, 'UTF-8');

Weitere Informationen erhalten Sie hier .

Marco Concas
quelle