如何使Beautiful Soup输出HTML实体?
我正在尝试清理一些来自客户端的HTML输入,以防止XSS攻击。我使用的是Python 2.6和Beautiful Soup库。我会解析输入,去掉不在白名单上的所有标签和属性,然后把处理后的内容再转回字符串。
但是……
>>> unicode(BeautifulSoup('text < text'))
u'text < text'
我觉得这看起来不是有效的HTML。而且用我的标签清理工具,可能会导致各种问题:
>>> print BeautifulSoup('<<script></script>script>alert("xss")<<script></script>script>').prettify()
<
<script>
</script>
script>alert("xss")<
<script>
</script>
script>
像<script></script>
这样的标签会被移除,剩下的内容不仅可能是XSS攻击,还可能是有效的HTML。
显而易见的解决办法是把所有的<
字符替换成<
,这样在解析后就不会被当作标签了(对于>&'"
也是一样)。不过,Beautiful Soup的文档只提到了如何解析实体,而没有提到如何生成它们。当然,我可以在所有NavigableString
节点上进行替换,但我担心会漏掉什么,所以我更希望能用一些经过验证的代码来完成这个工作。
为什么Beautiful Soup默认不转义<
(以及其他特殊字符),我该如何让它做到这一点呢?
另外,我也看过lxml.html.clean
。它似乎是基于黑名单的方式,而不是白名单,所以我觉得不太安全。标签可以在白名单中,但属性却不行,而且它允许的属性对我来说太多了(比如tabindex
)。此外,它在处理输入<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>
时还会抛出AssertionError
错误。这可不好。
如果有其他清理HTML的方法建议,我也非常欢迎。我并不是唯一一个想做这个的人,但似乎没有标准的解决方案。
2 个回答
lxml.html.clean.Cleaner
这个类可以让你设置一个标签白名单,也就是你可以用allow_tags
这个参数来指定哪些标签是允许的。同时,你还可以使用feedparser里预先计算好的属性白名单,通过safe_attrs_only
这个参数来实现。而且,lxml在序列化的时候确实能正确处理实体。
我知道这已经是你最初提问的3年半后了,但你可以在使用 prettify()
、encode()
或 decode()
时,加上 formatter='html'
这个参数,这样就能生成格式正确的HTML代码。