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);
|
}
|
}
|