Question

Je travaille à trouver un bon moyen de faire l'utilisateur a fourni des données, dans ce cas, autoriser le HTML et l'ont soit aussi sûr et rapide que possible.

Je sais que chaque personne sur ce site semble penser http://htmlpurifier.org est la réponse ici. Je suis d'accord en partie. htmlpurifier a le meilleur code source ouvert là-bas pour filtrer HTML fournie par l'utilisateur, mais il solution est très volumineux et n'est pas bon pour la performance sur un site à fort trafic. Je pourrais même y utiliser un jour de solution, mais pour l'instant mon objectif est de trouver une méthode plus légère.

J'utilise les 2 fonctions ci-dessous pour environ 2 ans et demi maintenant sans problème encore, mais je pense qu'il est temps de prendre des commentaires des pros ici s'ils me aider.

La première fonction est appelée FilterHTML ($ string) il est couru avant que les données d'utilisateur est enregistré dans une base de données MySQL. La deuxième fonction est appelée format_db_value (texte $, nl2br $ = false) et je l'utilise sur une page où je l'intention de montrer à l'utilisateur a présenté des données.

Ci-dessous les 2 fonctions est un groupe des codes XSS j'ai trouvé sur http: // ha.ckers.org/xss.html et je puis couru sur ces 2 fonctions pour voir comment mon code affectif est, je suis un peu satisfait des résultats, ils ont fait bloquer tous les codes que j'ai essayé mais je sais qu'il est pas encore à 100% de toute évidence en toute sécurité.

Pouvez-vous les gars s'il vous plaît regarder par-dessus et me donner des conseils pour mon code lui-même ou même sur le concept de filtrage html.

Je voudrais faire une approche whitelist un jour, mais htmlpurifier est la seule solution que j'ai trouvé intéressant d'utiliser pour cela et comme je l'ai mentionné il est léger que je le voudrais.

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);
}

Ci-dessous la fonction est utilisée lorsque l'utilisateur indiquant le code présenté sur une page Web

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;
        }
    }
}

Les codes ci-dessous sont de ha.ckers.org et ils semblent tous à l'échec de mes fonctions ci-dessus

Je n'ai pas essayé tout le monde sur ce site mais il y a beaucoup plus, ce n'est que certains d'entre eux.
Le code d'origine est sur la ligne supérieure de chaque jeu et le code après avoir exécuté mes fonctions est sur la ligne en dessous.

<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=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>
<IMG SRC=...alert('XSS')>

<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>
<IMG SRC=F  MLEJNALN !>

<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
<IMG SRC=...alert('XSS')>


<IMG SRC="jav&#x0A;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
'
)
"
>
Était-ce utile?

Autres conseils

La seule façon d'être sûr est de whitelist les balises et les attributs qu'ils peuvent utiliser et écrire regexps strictes pour valider les valeurs autorisées d'attributs. Si vous souhaitez autoriser des attributs tels que le « style », alors vous avez une complexité supplémentaire.

ne pourrait faire Liste noire attaque pour certaines personnes plus dur, mais il ne sera pas le rendre plus dur pour la personne qui utilise la technique que vous ne l'avez pas entendu parler encore.

J'essayer d'utiliser regexp ajouter des balises de fermeture manquantes à ce que les utilisateurs sont entrés et remplacer <br> avec <br /> et ainsi de suite, puis l'analyser en utilisant SimpleXML, itérer puis au-dessus et enlever toute étiquette qui ne sont pas dans la liste blanche, tout attribut n'est pas dans la liste blanche pour la balise donnée, et tout attribut qui a une valeur non conforme à regexp précise pour cet attribut. Après tout j'utiliser asXML () pour récupérer le texte. Je commencerais avec ensemble minimal de balises et d'attributs et d'ajouter de nouvelles au besoin d'être particulièrement prudent de tout ce qui peut contenir URL.

à mon humble avis htmlawed est le meilleur - maigre, rapide, couverture complète HTML, liste la plus souple ... noir ou blanc pour les balises et les attributs. Sûr? tous les Défaites ha.ckers codes XSS

Comment l'utilisation de l'analyseur HTML natif de PHP?

J'étais curieux à ce sujet, donc je l'ai écrit un code pour le test (nécessite 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);

La sortie, sans courir Tidy:

entrer image description ici

Semble ok. Ou at-il enlever trop? :) Devrait être beaucoup plus rapide que htmlpurifier, théoriquement plus sûr car il est moins permissive, et probablement plus rapide que les expressions rationnelles aussi.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top