Python : assainir du HTML

Ce billet date de plusieurs années, ses informations peuvent être devenues obsolètes.

L'autre jour je me suis dit que ça serait sympa de laisser les gens saisir quelques balises HTML dans les commentaires de mon blog. Et je me suis rappelé qu'il y a quelques années, j'ai appris à la dure que laisser les utilisateurs saisir du HTML brut était la porte ouverte à toutes les fenêtres. Si vous ne savez pas pourquoi, je vous encourage fortement à vous entraîner sur le codelab Web Application Exploits and Defenses. Et oui, le web c'est pire que le Far West.

Pourtant, c'est cool de laisser les gens baliser les commentaires, surtout ici, car mon lectorat est une caillera HTML aware.

Or il se trouve que parser le HTML à coup de regex c'est dur et ça peut être inefficace et en plus ça rend ouf. Même s'il s'agit juste d'un sous-ensemble de balises HTML c'est dur. Ainsi, il est toujours bon de se rappeler, comme souligné dans la FAQ: Untrusted users and HTML, que :

No method of displaying untrusted HTML is 100% safe.

Mais ici, on aime le risque bordel. Et on aime Python et Django. Et on aime aussi le HTML. Et on sait que programmer c'est difficile, et que dans certains cas il vaut mieux faire du shopping :) Oh oui, on en sait des choses ici.

C'est pourquoi, à force d'en avoir entendu parler, à droite, à gauche, j'ai décidé d'utiliser html5lib. Il est certain que je n'ai pas fait le choix de la performance, mais plutôt celui de la meilleure sécurité possible dans la mesure du possible.

J'ai d'abord cherché à me servir directement de html5lib pour assainir le HTML, et puis je suis tombé sur Bleach qui correspond tout à fait à ce que je voulais faire, une sorte de wrapper au dessus de html5lib permettant de se limiter à un sous ensemble de tags et d'attributs.

J'en ai quand même profité pour regarder un peu le code de html5lib et j'ai utilisé la lib pour implémenter une petite validation de la syntaxe stricte du code HTML des commentaires, et ce bien sûr afin de punir les newbies :D Ca à l'air de bien tourner et c'est en test ici même pour le moment :

from html5lib import HTMLParser, treebuilders
from html5lib.html5parser import ParseError

# validate HTML syntax
p = HTMLParser( tree=treebuilders.getTreeBuilder('dom'), strict=True )
try:
    dom_tree = p.parseFragment( comment )
except ParseError:
    raise forms.ValidationError(_(u"Syntaxe HTML invalide !"))

Avant HTML5 et video : WebM Après Coupe du Monde 2010

Tag Kemar Joint