lxml 清理器忽略 base64 图像
我在我的HTML代码中使用lxml.html.clean来处理不可信的输入。然后我发现lxml会把data:
标签给去掉了。但是我想插入一个以base64格式存储的图片(因为我从数据库中获取,没有文件),所以我需要这个标签。比如说,看看这个例子:
from lxml.html.clean import Cleaner
cleaner = Cleaner()
cleaner.clean_html("""
<img src="http://test.com/img.png"/>
<img src="data:image/png;base64,aGVsbG8="/>
""")
结果是'<span><img src="http://test.com/img.png"><img src=""></span>'
。第一个图片的链接没有被处理,第二个则被处理了。
有没有什么办法可以让我使用base64代码,同时又不让安全漏洞通过呢?
1 个回答
我在安装了 lxml 3.1.0 后,发现了这个问题。这里有一个解决方案,使用了“猴子补丁”技术——也就是在 lxml.html.clean
模块中替换查找的正则表达式,以避免删除包含 data:image/.*;base64 的链接。
import re
import lxml
from lxml.html.clean import Cleaner
new_pattern = '\s*(?:javascript:|jscript:|livescript:|vbscript:|data:[^(?:image/.+;base64)]+|about:|mocha:)'
print(new_pattern)
lxml.html.clean._javascript_scheme_re = re.compile(new_pattern, re.I)
cleaner = Cleaner()
dochtml = """
<img src="http://test.com/img.png"/>
<img src="data:image/png;base64,aGVsbG8="/>
<img src="data:unsafe/contents;base64,aGVsbG8="/>
<img src="data:text/html;base64,PGh0bWw+PHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPmFsZXJ0KCdoaScpPC9zY3JpcHQ+PC9odG1sPg=="/>
"""
r = cleaner.clean_html(dochtml)
print(r)
结果
<span><img src="http://test.com/img.png">
<img src="data:image/png;base64,aGVsbG8=">
<img src="">
<img src="">
</span>
不过,这个方法有个缺点——它依赖于一个内部变量名,而这个变量名并没有在公开接口中说明。所以模块的开发者可能会更改这个变量的名字,或者改进他们的正则表达式。
为了更安全一点,我建议在网络服务器上创建一个 URL 处理程序,通过 ID 从数据库中返回图片内容。这样在你的 HTML 文档中,就可以写成 <img src="http://myserver/showimg?id=123213">
。不过,这样做会涉及到很多额外的部分,比如需要有网络服务器等等。而且如果不希望全世界都能访问这些图片,这个方法就行不通了。
旧答案:
应该可以配置 Cleaner 来保留这些标签,但我无法重现你的情况——对我来说,它就是正常工作的。我使用的是 Python 2.7.2 和 lxml 2.2.8 win-32。请问你用的是什么 Python 和 lxml 的版本?
我尝试运行你的例子,发现第二个图片标签的内容没有被删除。