Ist meine anti XSS Methode OK für das Erlauben Benutzer HTML in PHP?
Frage
Ich arbeite eine gute Art und Weise auf der Suche nach Benutzern übermittelten Daten, in diesem Fall zu machen erlauben HTML und habe es so sicher und schnell wie ich kann.
Ich weiß, jede einzelne Person auf dieser Seite http://htmlpurifier.org scheint zu denken, ist die Antwort hier. Ich stimme teilweise. HTMLPurifier hat den besten Open-Source-Code gibt zum Filtern Benutzer HTML abgegeben, aber es Lösung ist sehr sperrig und ist für die Leistung nicht gut auf einem hohen Verkehr Ort. Ich könnte sogar dort Lösung einen Tag verwenden, aber jetzt mein Ziel ist es, eine leichtere Methode zu finden.
Ich habe mit den zwei folgenden Funktionen für etwa 2 ½ Jahre ohne Probleme noch nicht, aber ich denke, es ist Zeit, eine Eingabe von den Profis hier zu nehmen, wenn sie mir helfen.
Die erste Funktion aufgerufen wird FilterHTML ($ string) ist ran, bevor Benutzerdaten zu einer MySQL-Datenbank gespeichert wird. Die zweite Funktion wird aufgerufen, format_db_value ($ text, $ nl2br = false) und ich benutze es auf einer Seite, wo ich die Benutzer vorgelegten Daten zu zeigen, planen.
Unter den 2-Funktionen ist ein Bündel des XSS-Codes ich auf http: // ha.ckers.org/xss.html und ich lief sich auf diesen zwei Funktionen dann zu sehen, wie mein Code affektiven, ich etwas mit den Ergebnissen zufrieden bin, haben sie jeden Codeblock heraus, dass ich versuchte, aber ich weiß, dass es offensichtlich immer noch nicht zu 100% sicher ist.
Can ihr bitte Blick über sie und geben Sie mir einen Rat für meinen Code selbst oder auch im großen und ganzen html Filterung Konzept.
Ich möchte einen Whitelist-Ansatz eines Tages tun, aber HTMLPurifier ist die einzige Lösung, die ich wert gefunden haben, unter Verwendung von für das und wie ich bereits erwähnt es nicht leicht ist, wie ich möchte.
function FilterHTML($string) {
if (get_magic_quotes_gpc()) {
$string = stripslashes($string);
}
$string = html_entity_decode($string, ENT_QUOTES, "ISO-8859-1");
// convert decimal
$string = preg_replace('/&#(\d+)/me', "chr(\\1)", $string); // decimal notation
// convert hex
$string = preg_replace('/&#x([a-f0-9]+)/mei', "chr(0x\\1)", $string); // hex notation
//$string = html_entity_decode($string, ENT_COMPAT, "UTF-8");
$string = preg_replace('#(&\#*\w+)[\x00-\x20]+;#U', "$1;", $string);
$string = preg_replace('#(<[^>]+[\s\r\n\"\'])(on|xmlns)[^>]*>#iU', "$1>", $string);
//$string = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $string); //bad line
$string = preg_replace('#/*\*()[^>]*\*/#i', "", $string); // REMOVE /**/
$string = preg_replace('#([a-z]*)[\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', '...', $string); //JAVASCRIPT
$string = preg_replace('#([a-z]*)([\'\"]*)[\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', '...', $string); //VBSCRIPT
$string = preg_replace('#([a-z]*)[\x00-\x20]*([\\\]*)[\\x00-\x20]*@([\\\]*)[\x00-\x20]*i([\\\]*)[\x00-\x20]*m([\\\]*)[\x00-\x20]*p([\\\]*)[\x00-\x20]*o([\\\]*)[\x00-\x20]*r([\\\]*)[\x00-\x20]*t#iU', '...', $string); //@IMPORT
$string = preg_replace('#([a-z]*)[\x00-\x20]*e[\x00-\x20]*x[\x00-\x20]*p[\x00-\x20]*r[\x00-\x20]*e[\x00-\x20]*s[\x00-\x20]*s[\x00-\x20]*i[\x00-\x20]*o[\x00-\x20]*n#iU', '...', $string); //EXPRESSION
$string = preg_replace('#</*\w+:\w[^>]*>#i', "", $string);
$string = preg_replace('#</?t(able|r|d)(\s[^>]*)?>#i', '', $string); // strip out tables
$string = preg_replace('/(potspace|pot space|rateuser|marquee)/i', '...', $string); // filter some words
//$string = str_replace('left:0px; top: 0px;','',$string);
do {
$oldstring = $string;
//bgsound|
$string = preg_replace('#</*(applet|meta|xml|blink|link|script|iframe|frame|frameset|ilayer|layer|title|base|body|xml|AllowScriptAccess|big)[^>]*>#i', "...", $string);
} while ($oldstring != $string);
return addslashes($string);
}
Unter-Funktion wird verwendet, wenn Benutzercode auf einer Webseite eingereicht zeigt
function format_db_value($text, $nl2br = false) {
if (is_array($text)) {
$tmp_array = array();
foreach ($text as $key => $value) {
$tmp_array[$key] = format_db_value($value);
}
return $tmp_array;
} else {
$text = htmlspecialchars(stripslashes($text));
if ($nl2br) {
return nl2br($text);
} else {
return $text;
}
}
}
Die folgenden Codes sind von ha.ckers.org und sie alle scheinen auf meinen Funktionen über
zum scheitern verurteilt Ich habe nicht versucht, alle auf dieser Website, obwohl es viel mehr ist, ist dies nur einige von ihnen.
Der ursprüngliche Code ist auf der obere Zeile jeden Satz und den Code nach meinen Funktionen ausgeführt durch auf der Linie darunter.
<IMG SRC="javascript:alert(\'XSS\');"><b>hello</b> hiii
<IMG SRC=...alert('XSS');"><b>hello</b> hiii
<IMG SRC=JaVaScRiPt:alert('XSS')>
<IMG SRC=...alert('XSS')>
<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>
<IMG SRC=...alert(String.fromCharCode(88,83,83))>
<IMG SRC=javascript:alert('XSS')>
<IMG SRC=...alert('XSS')>
<IMG SRC=javascript:alert('XSS')>
<IMG SRC=F MLEJNALN !>
<IMG SRC=javascript:alert('XSS')>
<IMG SRC=...alert('XSS')>
<IMG SRC="jav
ascript:alert('XSS');">
<IMG SRC=...alert('XSS');">
perl -e 'print "<IMG SRC=javascript:alert("XSS")>";' > out
perl -e 'print "<IMG SRC=java\0script:alert(\"XSS\")>";' > out
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>
...
<iframe src=http://ha.ckers.org/scriptlet.html <
...
<LAYER SRC="http://ha.ckers.org/scriptlet.html"></LAYER>
......
<META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet">
...; REL=stylesheet">
<IMG STYLE="xss:...(alert('XSS'))">
<IMG STYLE="xss:expr/*XSS*/ession(alert('XSS'))">
<XSS STYLE="xss:...(alert('XSS'))">
<XSS STYLE="xss:expression(alert('XSS'))">
<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>
<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>
<IMG
SRC
=
"
j
a
v
a
s
c
r
i
p
t
:
a
l
e
r
t
(
'
X
S
S
'
)
"
>
<IMG
SRC
=...
a
l
e
r
t
(
'
X
S
S
'
)
"
>
Lösung
Hier sind vier Alternativen:
Andere Tipps
Der einzige Weg um sicher zu sein ist es, die weiße Liste der Tags und Attribute, die sie streng regexps verwenden und schreiben können zulässigen Werte von Attributen zu validieren. Wenn Sie Attribute erlauben, wie „Stil“ wollen, dann müssen Sie zusätzliche Komplexität.
Schwarze Liste könnte nur Angriff für einige Menschen härter machen, aber es wird nicht schwieriger macht jede für die Person, dass Anwendungen Technik, die Sie jetzt noch nicht gehört haben.
Ich würde versuchen, regexp mit Schließen-Tags hinzufügen fehlt, was die Nutzer eingegeben und ersetzen <br>
mit <br />
und so weiter, dann analysieren sie SimpleXML verwenden, dann Iterierte über sie und entfernen Sie das Etikett, das nicht in die weiße Liste ist, jedes Attribut, dass ist nicht für gegebenen Tag in der weißen Liste, und jedes Attribut, das einen Wert hat, um präzisen regexp für dieses Attribut nicht entspricht. Schließlich würde ich asXML () verwenden, um den Text wieder zu bekommen. Ich würde mit einem minimalen Satz von Tags und Attributen beginnen und neue hinzufügen als besonders vorsichtig etwas brauchte, die URL enthält.
IMHO htmlawed ist die beste - schlanke, schnelle, vollständige HTML-Abdeckung, flexibelste ... schwarze oder weiße Liste für Tags und Attribute. Sicher? Niederlagen alle die ha.ckers Codes XSS
Wie wäre es mit PHP nativen HTML-Parser?
Ich war neugierig, also habe ich einige Code geschrieben für die Prüfung (benötigt PHP 5.3.6 +):
$badHtml = file_get_contents('badHtml.txt');
$html = sprintf('<div id="input">%s</div>', $badHtml);
// tidy is no required, but may fix invalid markup
$tidy = new \tidy();
$tidy->parseString($html, array(), 'utf8');
$tidy->cleanRepair();
$dom = new \DomDocument('1.0', 'UTF-8');
libxml_use_internal_errors(true);
$dom->loadHtml($tidy);
$input = $dom->getElementById('input');
// tag as key, attributes as values
$allowed = array(
'table' => array('border'),
'tbody' => array(),
'tr' => array(),
'td' => array(),
'th' => array(),
'img' => array('src', 'alt'),
'p' => array(),
'ul' => array(),
'ol' => array(),
'li' => array(),
'a' => array('href', 'title'),
'strong' => array(),
'em' => array(),
'sub' => array(),
'sup' => array(),
);
$walk = function(\DomNode $node) use($allowed, &$walk){
// only check tags
if($node->nodeType !== XML_ELEMENT_NODE)
return;
if(!isset($allowed[$node->nodeName]))
return $node->parentNode->removeChild($node);
foreach($node->attributes as $key => $attr){
if(!in_array($key, $allowed[$node->nodeName], true))
$node->removeAttribute($key);
// expect URLs here
if(!in_array($key, array('href', 'src'), true))
continue;
if(!filter_var($attr->value, FILTER_VALIDATE_URL))
return $node->parentNode->removeChild($node);
}
array_map($walk, iterator_to_array($node->childNodes));
};
// convert DOMNodeList to array because this way the bad stuff
// can be removed within the loop
array_map($walk, iterator_to_array($input->childNodes));
// export HTML
$sanitized = $dom->saveHtml($input);
Der Ausgang, ohne Tidy ausgeführt wird:
Scheint ok. Oder hat es entfernen zu viel? :) Sollte Weg schneller als HTMLPurifier theoretisch mehr sichern, da es weniger freizügig, und wahrscheinlich schneller als die regulären Ausdrücke zu.