对比新文件 |
| | |
| | | package com.iailab.framework.xss.core.json; |
| | | |
| | | import com.iailab.framework.common.util.servlet.ServletUtils; |
| | | import com.iailab.framework.xss.config.XssProperties; |
| | | import com.iailab.framework.xss.core.clean.XssCleaner; |
| | | import com.fasterxml.jackson.core.JsonParser; |
| | | import com.fasterxml.jackson.core.JsonToken; |
| | | import com.fasterxml.jackson.databind.DeserializationContext; |
| | | import com.fasterxml.jackson.databind.deser.std.StringDeserializer; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.util.PathMatcher; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * XSS 过滤 jackson 反序列化器。 |
| | | * 在反序列化的过程中,会对字符串进行 XSS 过滤。 |
| | | * |
| | | * @author Hccake |
| | | */ |
| | | @Slf4j |
| | | @AllArgsConstructor |
| | | public class XssStringJsonDeserializer extends StringDeserializer { |
| | | |
| | | /** |
| | | * 属性 |
| | | */ |
| | | private final XssProperties properties; |
| | | /** |
| | | * 路径匹配器 |
| | | */ |
| | | private final PathMatcher pathMatcher; |
| | | |
| | | private final XssCleaner xssCleaner; |
| | | |
| | | @Override |
| | | public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { |
| | | // 1. 白名单 URL 的处理 |
| | | HttpServletRequest request = ServletUtils.getRequest(); |
| | | if (request != null) { |
| | | String uri = ServletUtils.getRequest().getRequestURI(); |
| | | if (properties.getExcludeUrls().stream().anyMatch(excludeUrl -> pathMatcher.match(excludeUrl, uri))) { |
| | | return p.getText(); |
| | | } |
| | | } |
| | | |
| | | // 2. 真正使用 xssCleaner 进行过滤 |
| | | if (p.hasToken(JsonToken.VALUE_STRING)) { |
| | | return xssCleaner.clean(p.getText()); |
| | | } |
| | | JsonToken t = p.currentToken(); |
| | | // [databind#381] |
| | | if (t == JsonToken.START_ARRAY) { |
| | | return _deserializeFromArray(p, ctxt); |
| | | } |
| | | // need to gracefully handle byte[] data, as base64 |
| | | if (t == JsonToken.VALUE_EMBEDDED_OBJECT) { |
| | | Object ob = p.getEmbeddedObject(); |
| | | if (ob == null) { |
| | | return null; |
| | | } |
| | | if (ob instanceof byte[]) { |
| | | return ctxt.getBase64Variant().encode((byte[]) ob, false); |
| | | } |
| | | // otherwise, try conversion using toString()... |
| | | return ob.toString(); |
| | | } |
| | | // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML) |
| | | if (t == JsonToken.START_OBJECT) { |
| | | return ctxt.extractScalarFromObject(p, this, _valueClass); |
| | | } |
| | | |
| | | if (t.isScalarValue()) { |
| | | String text = p.getValueAsString(); |
| | | return xssCleaner.clean(text); |
| | | } |
| | | return (String) ctxt.handleUnexpectedToken(_valueClass, p); |
| | | } |
| | | } |
| | | |