web-dev-qa-db-fra.com

Strip_tags () est-il vulnérable aux attaques de script?

Y a-t-il une attaque XSS connue ou une autre attaque qui la fait passer

$content = "some HTML code";
$content = strip_tags($content);

echo $content;

?

Le manuel a un avertissement:

Cette fonction ne modifie aucun attribut sur les balises que vous autorisez à utiliser allowable_tags, y compris le style et les attributs onmouseover qu'un utilisateur espiègle peut abuser lors de la publication de texte qui sera affiché aux autres utilisateurs.

mais cela est lié à l'utilisation du paramètre allowable_tags uniquement.

En l'absence de balises autorisées , strip_tags() est-il vulnérable à toute attaque?

Chris Shiflett semble dire que c'est sûr:

Utiliser des solutions matures

Lorsque cela est possible, utilisez des solutions existantes et matures au lieu d'essayer de créer les vôtres. Des fonctions comme strip_tags () et htmlentities () sont de bons choix.

est-ce correct? Veuillez, si possible, citer des sources.

Je connais le purificateur HTML, htmlspecialchars () etc.- Je ne suis pas à la recherche de la meilleure méthode pour assainir HTML. Je veux juste connaître ce problème spécifique. C'est une question théorique qui a été soulevée ici .

Référence: strip_tags() implémentation dans le PHP

49
Pekka

Comme son nom l'indique, strip_tags Devrait supprimer toutes les balises HTML. La seule façon de le prouver est d'analyser le code source. L'analyse suivante s'applique à un appel strip_tags('...'), sans deuxième argument pour les balises en liste blanche.

Tout d'abord, une théorie sur les balises HTML: une balise commence par un < Suivi de caractères non blancs. Si cette chaîne commence par un ?, Elle ne doit pas être analysée . Si cette chaîne commence par un !--, Elle est considérée comme un commentaire et le texte suivant ne doit pas non plus être analysé. Un commentaire se termine par un -->, À l'intérieur d'un tel commentaire, les caractères comme < Et > Sont autorisés. Les attributs peuvent apparaître dans les balises, leurs valeurs peuvent éventuellement être entourées d'un caractère de guillemet (' Ou "). Si une telle citation existe, elle doit être fermée, sinon si un > Est rencontré, la balise n'est pas fermée.

Le code <a href="example>xxx</a><a href="second">text</a> Est interprété dans Firefox comme:

<a href="http://example.com%3Exxx%3C/a%3E%3Ca%20href=" second"="">text</a>

La fonction PHP strip_tags est référencée dans ligne 4036 de ext/standard/string.c . Cette fonction appelle la fonction fonction interne php_strip_tags_ex .

Il existe deux tampons, l'un pour la sortie, l'autre pour "à l'intérieur des balises HTML". Un compteur nommé depth contient le nombre de crochets ouverts (<).
La variable in_q Contient le caractère de citation (' Ou ") Le cas échéant, et 0 Sinon. Le dernier caractère est stocké dans la variable lc.

La fonction contient cinq états, trois sont mentionnés dans la description ci-dessus de la fonction. Sur la base de ces informations et du corps de la fonction, les états suivants peuvent être dérivés:

  • L'état 0 est l'état de sortie (pas dans aucune balise)
  • L'état 1 signifie que nous sommes à l'intérieur d'une balise html normale (le tampon de balise contient <)
  • L'état 2 signifie que nous sommes à l'intérieur d'une balise php
  • État 3: nous sommes sortis de l'état de sortie et avons rencontré les caractères < Et ! (Le tampon de balises contient <!)
  • État 4: à l'intérieur du commentaire HTML

Nous devons juste faire attention à ce qu'aucune balise ne puisse être insérée. Autrement dit, < Suivi d'un caractère non blanc. ligne 4326 vérifie une casse avec le caractère < Décrit ci-dessous:

  • Si entre guillemets (par exemple <a href="inside quotes">), Le caractère < Est ignoré (supprimé de la sortie).
  • Si le caractère suivant est un espace blanc, < Est ajouté au tampon de sortie .
  • si en dehors d'une balise HTML, l'état devient 1 ("à l'intérieur de la balise HTML") et le dernier caractère lc est défini sur <
  • Sinon, si à l'intérieur d'une balise HTML, le compteur nommé depth est incrémenté et le caractère ignoré.

Si > Est rencontré alors que la balise est ouverte (state == 1), in_q Devient 0 ("Pas dans une citation") et state devient 0 ("pas dans une balise"). Le tampon de balises est supprimé.

La vérification des attributs (pour les caractères comme ' Et ") Est effectuée sur le tampon de balises qui est supprimé. La conclusion est donc:

strip_tags sans une liste blanche de balises est sûr pour l'inclusion en dehors des balises, aucune balise ne sera autorisée.

Par "balises extérieures", je veux dire pas dans les balises comme dans <a href="in tag">outside tag</a>. Le texte peut cependant contenir < Et >, Comme dans >< a>>. Cependant, le résultat n'est pas du code HTML valide, <, > Et & Doivent encore être échappés, en particulier le &. Cela peut être fait avec htmlspecialchars() .

La description de strip_tags Sans argument de liste blanche serait:

S'assure qu'aucune balise HTML n'existe dans la chaîne retournée.

48
Lekensteyn

Je ne peux pas prédire les futurs exploits, d'autant plus que je n'ai pas regardé le code source PHP pour cela. Cependant, il y a eu des exploits dans le passé parce que les navigateurs acceptaient des balises apparemment non valides (comme <s\0cript>). Il est donc possible qu'à l'avenir, quelqu'un puisse exploiter un comportement de navigateur étrange.

Cela mis à part, l'envoi de la sortie directement au navigateur en tant que bloc complet de HTML ne devrait jamais être non sécurisé:

echo '<div>'.strip_tags($foo).'</div>'

Cependant, ce n'est pas sûr:

echo '<input value="'.strip_tags($foo).'" />';

car on pourrait facilement terminer le devis via " et insérez un gestionnaire de script.

Je pense qu'il est beaucoup plus sûr de toujours convertir les parasites < en &lt; (et la même chose avec des guillemets).

10
Matthew

Selon cet outil en ligne , cette chaîne sera "parfaitement" échappée, mais le résultat est un autre malveillant!

<<a>script>alert('ciao');<</a>/script>

Dans la chaîne, les "vraies" balises sont <a> et </a>, puisque < et script> seuls ne sont pas des balises.

J'espère que je me trompe ou que c'est juste à cause d'une ancienne version de PHP, mais il vaut mieux vérifier dans votre environnement.

5
Ludovico Grossi

Les balises de bande sont parfaitement sûres - si tout ce que vous faites est de sortir le texte dans le corps html.

Il n'est pas nécessairement sûr de le mettre dans les attributs mysql ou url.

2
kemus