Markdown et XSS

Les attaques XSS (cross-site scripting) sont une technique connue pour obtenir accès à des informations privées sur les utilisateurs d’un site web. L’attaquant injecte du contenu HTML peut recommandable (un script) sur une page web qui lui permettra de lire les cookies d’un et de faire quelque chose de mal avec (tel que voler des mots de passe). Comme contremesure, vous devriez filtrer tout contenu suspicieux provenant de vos utilisateurs. Markdown n’inclus pas de filtre XSS, vous devez donc le fournir vous même. Mais faites attention à la façon dont vous le faite…

La règle de base est ceci : filtrez le contenu pour des attaques XSS après que Markdown ait fait sa conversion, pas avant. Si vous filtrez avant, le filtre brisera quelques éléments de la syntaxe Markdown et laissera des trous dans la sécurité. Aussi, prenez note que même si vous utilisez PHP Markdown dans somme mode sans HTML, où les balises HTML sont enlevées, vous n’êtes pas à l’abris des attaques XSS. Laissez-moi vous montrer pourquoi.

Voici un exemple d’attaque XSS où l’on mélange HTML et Markdown. Il s’agit d’un lien contenant un script (ce script est sans danger, mais celui d’un autre attaquant pourrait être plus malicieux).

> allô à <a name="n"
> href="javascript:alert('xss')">*toi*</a>

Maintenant, supposons qu’on applique le filtre XSS avant Markdown pour filtrer le HTML indésirable. Le filtre XSS, s’attendant à du HTML, verra sûrement la balise <a> comme se terminant au premier caractère de la deuxième ligne et laissera la balise intacte. Le href="javascript:…" sera vu comme du texte tout à fait normal et n’y touchera pas. Mais quand Markdown converti ceci au HTML, voici le résultat :

<blockquote>
 <p>allô à <a name="n"
 href="javascript:alert('xss')"><em>toi</em></a></p>
</blockquote>

Après Markdown, le premier > sur la deuxième ligne disparait parce qu’il est utilisé comme indicateur de bloc de citation dans la syntaxe Markdown, et vous avez maintenant un lien contenant une attaque XSS !

Est-ce que Markdown a généré le HTML ? Non, le HTML était déjà présent et à la vue dans le texte d’entrée. Le filtre XSS n’a pu le voir parce que le texte n’obéissait pas aux régles du HTML : c’était un mélange de Markdown et de HTML et le filtre ne connaît rien de Markdown.

Maintenant, on pourrait penser que désactiver le HTML dans Markdown règle le problème, mais ce n’est pas vraiment le cas. Considérons cet autre vecteur d’attaque utilisant la syntaxe Markdown elle-même pour créer un lien dangereux :

[un peu de texte](javascript:alert('xss'))

Une fois passé par Markdown, vous obtenez ceci :

<a href="javascript:alert('xss')">un peu de texte</a>

L’attaque XSS est encore là ! Markdown n’est pas un filtre XSS, il ne fait que passer l’URL qu’on lui donne dans le lien.

Et encore un fois, si on applique le filtre XSS avant Markdown, il ne filtrera rien puisque qu’il vera tout ça comme du texte. Tout ceci montre que ça prend prend toujours un filtre après Markdown pour vérifier le HTML généré, autrement on risque toujours des injections de javascript.

Donc en conclusion, si vous voulez assurez la sécurité, vous devez filtrer ce qui sort de Markdown, pas ce qui entre. Il n’y a pas d’autre choix.

Notez que si vous utilisez Wordpress, le filtre XSS kses est déjà intégré et il devrait fonctionner correctement avec PHP Markdown.


  • © 2003–2018 Michel Fortin.