消除不受信任的HTML (来防止XSS攻击)

问题

在做网站的时候,经常会提供用户评论的功能。有些不怀好意的用户,会搞一些脚本到评论内容中,而这些脚本可能会破坏整个页面的行为,更严重的是获取一些机要信息,此时需要清理该HTML,以避免跨站脚本cross-site scripting攻击(XSS)。

方法

使用jsoup HTML Cleaner 方法进行清除,但需要指定一个可配置的 Whitelist。

示例

String unsafe = 
  "<p><a href='http://example.com/' onclick='stealCookies()'>Link</a></p>";
String safe = Jsoup.clean(unsafe, Whitelist.basic());
// now: <p><a href="http://example.com/" rel="nofollow">Link</a></p>

说明

XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的特殊目的。XSS属于被动式的攻击,因为其被动且不好利用,所以许多人常忽略其危害性。所以我们经常只让用户输入纯文本的内容,但这样用户体验就比较差了。

一个更好的解决方法就是使用一个富文本编辑器WYSIWYG如CKEditor 和 TinyMCE。这些可以输出HTML并能够让用户可视化编辑。虽然他们可以在客户端进行校验,但是这样还不够安全,需要在服务器端进行校验并清除有害的HTML代码,这样才能确保输入到你网站的HTML是安全的。否则,攻击者能够绕过客户端的Javascript验证,并注入不安全的HMTL直接进入您的网站。

jsoup的whitelist清理器能够在服务器端对用户输入的HTML进行过滤,只输出一些安全的标签和属性。

jsoup提供了一系列的Whitelist基本配置,能够满足大多数要求;但如有必要,也可以进行修改,不过要小心。

这个cleaner非常好用不仅可以避免XSS攻击,还可以限制用户可以输入的标签范围。

五种基本白名单

Whitelist.none() 这个白名单只允许文本节点:所有HTML将被过滤。

Whitelist.simpleText() 这个白名单只允许简单的文本格式:b, em, i, strong, u。所有其他HTML(标签和属性)都将被删除。

Whitelist.basic() 这个白名单允许更全面的文本节点:a, b, blockquote, br, cite, code, dd, dl, dt, em, i, li, ol, p, pre, q, small, span, strike, strong, sub, sup, u, ul。和适当的属性。链接可以指向HTTP,HTTPS,FTP,邮件,有一个强制rel= nofollow属性。

Whitelist.basicWithImages() 这个白名单与basic()相同,又加上了IMG标签,可有适当的属性,src可指向HTTP或HTTPS。

Whitelist.relaxed() 这个白名单允许全方位的文本和HTML标签:a, b, blockquote, br, caption, cite, code, col, colgroup, dd, div, dl, dt, em, h1, h2, h3, h4, h5, h6, i, img, li, ol, p, pre, q, small, span, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, u, ul
链接没有强制rel= nofollow属性,但是你可以添加,如果需要的话。

如何配置白名单

通过以下方法添加白名单
addTags(java.lang.String...)
addAttributes(java.lang.String, java.lang.String...)
addEnforcedAttribute(java.lang.String, java.lang.String, java.lang.String)
addProtocols(java.lang.String, java.lang.String, java.lang.String...)

通过以下方法减少白名单
removeTags(java.lang.String...)
removeAttributes(java.lang.String, java.lang.String...)
removeEnforcedAttribute(java.lang.String, java.lang.String)
removeProtocols(java.lang.String, java.lang.String, java.lang.String...)

示例
        String html=null;

        Whitelist w=new Whitelist();

        w=w.relaxed();

        w.removeTags("a","h1", "h2", "h3", "h4", "h5", "h6");

        String content_html = Jsoup.clean(html, w);

        System.out.println(content_html);