潘志宝
2024-12-12 3374d19db03cce97572c3a294f137d1ea70b307f
提交 | 用户 | 时间
e7c126 1 package com.iailab.framework.xss.core.clean;
H 2
3 import org.jsoup.Jsoup;
4 import org.jsoup.nodes.Document;
5 import org.jsoup.safety.Safelist;
6
7 /**
8  * 基于 JSONP 实现 XSS 过滤字符串
9  */
10 public class JsoupXssCleaner implements XssCleaner {
11
12     private final Safelist safelist;
13
14     /**
15      * 用于在 src 属性使用相对路径时,强制转换为绝对路径。 为空时不处理,值应为绝对路径的前缀(包含协议部分)
16      */
17     private final String baseUri;
18
19     /**
20      * 无参构造,默认使用 {@link JsoupXssCleaner#buildSafelist} 方法构建一个安全列表
21      */
22     public JsoupXssCleaner() {
23         this.safelist = buildSafelist();
24         this.baseUri = "";
25     }
26
27     /**
28      * 构建一个 Xss 清理的 Safelist 规则。
29      * 基于 Safelist#relaxed() 的基础上:
30      * 1. 扩展支持了 style 和 class 属性
31      * 2. a 标签额外支持了 target 属性
32      * 3. img 标签额外支持了 data 协议,便于支持 base64
33      *
34      * @return Safelist
35      */
36     private Safelist buildSafelist() {
37         // 使用 jsoup 提供的默认的
38         Safelist relaxedSafelist = Safelist.relaxed();
39         // 富文本编辑时一些样式是使用 style 来进行实现的
40         // 比如红色字体 style="color:red;", 所以需要给所有标签添加 style 属性
41         // 注意:style 属性会有注入风险 <img STYLE="background-image:url(javascript:alert('XSS'))">
42         relaxedSafelist.addAttributes(":all", "style", "class");
43         // 保留 a 标签的 target 属性
44         relaxedSafelist.addAttributes("a", "target");
45         // 支持img 为base64
46         relaxedSafelist.addProtocols("img", "src", "data");
47
48         // 保留相对路径, 保留相对路径时,必须提供对应的 baseUri 属性,否则依然会被删除
49         // WHITELIST.preserveRelativeLinks(false);
50
51         // 移除 a 标签和 img 标签的一些协议限制,这会导致 xss 防注入失效,如 <img src=javascript:alert("xss")>
52         // 虽然可以重写 WhiteList#isSafeAttribute 来处理,但是有隐患,所以暂时不支持相对路径
53         // WHITELIST.removeProtocols("a", "href", "ftp", "http", "https", "mailto");
54         // WHITELIST.removeProtocols("img", "src", "http", "https");
55         return relaxedSafelist;
56     }
57
58     @Override
59     public String clean(String html) {
60         return Jsoup.clean(html, baseUri, safelist, new Document.OutputSettings().prettyPrint(false));
61     }
62
63 }
64