HTML Entities 转换问题
用 Python 给富文本编辑器的后端做一个 HTMLPurifier 组件。各种 XSS 技巧都筛了一遍。觉得万无一失了,没想到还是栽在了坑里。
HTMLPurifier 组件使用 Python HTMLParser 来实现。HTMLParser 在处理 HTML Entities 的时候和主流的浏览器不一致。主流浏览器(FireFox、Chrome、IE)都允许省略HTML Entities末尾的分号。而 HTMLParser 的unescape 函数在处理时要求必须有结尾分号,导致后端的 HTML 过滤被绕过。
如下代码:
HTML<a href="javascript:alert()">XSS</a>
对于 HTMLParser 来说,:
并不是一个正确的 HTML Entity,所以不会进行任何处理,链接被识别为 URL 路径,而不是 JavaScript 调用协议。但是主流浏览器会将:
解析成 :
,链接被识别为 JavaScript 调用协议。渲染后的 HTML 代码成了:
HTML<a href="javascript:alert()">XSS</a>
不单单是 Python 的 HTMLParser 对 HTML Entities 的处理方式和主流浏览器不一致,PHP 的 html_entity_decode()
函数也存在同样的问题。
另外对于
、&
、:
,Chrome 的处理方法竟然不一致:
 TEXT
解析为TEXT
, 
转换成了空格;&TEXT
解析为&TEXT
,&
转换成了&
;&colonTEXT
解析为&colonTEXT
,&colon
没能转换成:
。