如何使Beautiful Soup输出HTML实体?

11 投票
2 回答
6520 浏览
提问于 2025-04-16 03:57

我正在尝试清理一些来自客户端的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。

显而易见的解决办法是把所有的<字符替换成&lt;,这样在解析后就不会被当作标签了(对于>&'"也是一样)。不过,Beautiful Soup的文档只提到了如何解析实体,而没有提到如何生成它们。当然,我可以在所有NavigableString节点上进行替换,但我担心会漏掉什么,所以我更希望能用一些经过验证的代码来完成这个工作。

为什么Beautiful Soup默认不转义<(以及其他特殊字符),我该如何让它做到这一点呢?


另外,我也看过lxml.html.clean。它似乎是基于黑名单的方式,而不是白名单,所以我觉得不太安全。标签可以在白名单中,但属性却不行,而且它允许的属性对我来说太多了(比如tabindex)。此外,它在处理输入<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>时还会抛出AssertionError错误。这可不好。

如果有其他清理HTML的方法建议,我也非常欢迎。我并不是唯一一个想做这个的人,但似乎没有标准的解决方案。

2 个回答

2

lxml.html.clean.Cleaner这个类可以让你设置一个标签白名单,也就是你可以用allow_tags这个参数来指定哪些标签是允许的。同时,你还可以使用feedparser里预先计算好的属性白名单,通过safe_attrs_only这个参数来实现。而且,lxml在序列化的时候确实能正确处理实体。

7

我知道这已经是你最初提问的3年半后了,但你可以在使用 prettify()encode()decode() 时,加上 formatter='html' 这个参数,这样就能生成格式正确的HTML代码。

撰写回答