houzhongyi
2024-07-11 e7c1260db32209a078a962aaa0ad5492c35774fb
提交 | 用户 | 时间
e7c126 1 package com.iailab.framework.xss.core.json;
H 2
3 import com.iailab.framework.common.util.servlet.ServletUtils;
4 import com.iailab.framework.xss.config.XssProperties;
5 import com.iailab.framework.xss.core.clean.XssCleaner;
6 import com.fasterxml.jackson.core.JsonParser;
7 import com.fasterxml.jackson.core.JsonToken;
8 import com.fasterxml.jackson.databind.DeserializationContext;
9 import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
10 import lombok.AllArgsConstructor;
11 import lombok.extern.slf4j.Slf4j;
12 import org.springframework.util.PathMatcher;
13
14 import javax.servlet.http.HttpServletRequest;
15 import java.io.IOException;
16
17 /**
18  * XSS 过滤 jackson 反序列化器。
19  * 在反序列化的过程中,会对字符串进行 XSS 过滤。
20  *
21  * @author Hccake
22  */
23 @Slf4j
24 @AllArgsConstructor
25 public class XssStringJsonDeserializer extends StringDeserializer {
26
27     /**
28      * 属性
29      */
30     private final XssProperties properties;
31     /**
32      * 路径匹配器
33      */
34     private final PathMatcher pathMatcher;
35
36     private final XssCleaner xssCleaner;
37
38     @Override
39     public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
40         // 1. 白名单 URL 的处理
41         HttpServletRequest request = ServletUtils.getRequest();
42         if (request != null) {
43             String uri = ServletUtils.getRequest().getRequestURI();
44             if (properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, uri))) {
45                 return p.getText();
46             }
47         }
48
49         // 2. 真正使用 xssCleaner 进行过滤
50         if (p.hasToken(JsonToken.VALUE_STRING)) {
51             return xssCleaner.clean(p.getText());
52         }
53         JsonToken t = p.currentToken();
54         // [databind#381]
55         if (t == JsonToken.START_ARRAY) {
56             return _deserializeFromArray(p, ctxt);
57         }
58         // need to gracefully handle byte[] data, as base64
59         if (t == JsonToken.VALUE_EMBEDDED_OBJECT) {
60             Object ob = p.getEmbeddedObject();
61             if (ob == null) {
62                 return null;
63             }
64             if (ob instanceof byte[]) {
65                 return ctxt.getBase64Variant().encode((byte[]) ob, false);
66             }
67             // otherwise, try conversion using toString()...
68             return ob.toString();
69         }
70         // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
71         if (t == JsonToken.START_OBJECT) {
72             return ctxt.extractScalarFromObject(p, this, _valueClass);
73         }
74
75         if (t.isScalarValue()) {
76             String text = p.getValueAsString();
77             return xssCleaner.clean(text);
78         }
79         return (String) ctxt.handleUnexpectedToken(_valueClass, p);
80     }
81 }
82