引入owasp库
<dependency>
<groupId>org.owasp.esapi</groupId>
<artifactId>esapi</artifactId>
<version>2.2.0.0</version>
</dependency>
编写过滤器
import org.owasp.esapi.ESAPI;
import org.owasp.esapi.codecs.HTMLCodec;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class XssFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
throw new ServletException("XssFilter just supports HTTP requests");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String path = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
if (path != null) {
// 对请求参数进行过滤,这里引用了自定义类
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(httpRequest);
chain.doFilter(xssRequest, response);
// 对响应内容进行转义,这里引用了自定义类
XssHttpServletResponseWrapper xssResponse = new XssHttpServletResponseWrapper(httpResponse);
chain.doFilter(request, xssResponse);
String content = xssResponse.getResponseData();
if (content != null) {
HTMLCodec codec = new HTMLCodec();
String safeContent = codec.encode(content);
httpResponse.getWriter().write(safeContent);
} else {
chain.doFilter(request, response);
}
} else {
chain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
}
以下为自定义XssHttpServletRequestWrapper的源码:
import org.owasp.esapi.ESAPI;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.regex.Pattern;
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private static final Pattern SCRIPT_PATTERN = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value != null) {
value = ESAPI.encoder().canonicalize(value);
value = SCRIPT_PATTERN.matcher(value).replaceAll("");
}
return value;
}
}
以下为自定义XssHttpServletResponseWrapper的源码:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class XssHttpServletResponseWrapper extends HttpServletResponseWrapper {
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private PrintWriter writer;
public XssHttpServletResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
};
}
@Override
public PrintWriter getWriter() throws IOException {
if (writer == null) {
writer = new PrintWriter(new OutputStreamWriter(outputStream, getCharacterEncoding()), true);
}
return writer;
}
public String getResponseData() {
try {
return outputStream.toString(getCharacterEncoding());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
以上准备就绪,编写spring boot的配置类,实现对上面编写的过滤器的加载使用:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<XssFilter> xssFilterRegistrationBean() {
FilterRegistrationBean<XssFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new XssFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
}
下面是另外一个不依赖第三方组件包的实现方案
1.编写一个不依赖第三方组件的过滤器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class XSSFilter extends HttpServletRequestWrapper {
public XSSFilter(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
return cleanXSS(value);
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values == null) {
return null;
}
for (int i = 0; i < values.length; i++) {
values[i] = cleanXSS(values[i]);
}
return values;
}
private String cleanXSS(String value) {
if (value == null) {
return null;
}
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "(").replaceAll("\\)", ")");
value = value.replaceAll("'", "'");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
return value;
}
}
2.编写拦截器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class XSSInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpServletRequest filteredRequest = new XSSFilter(request);
request.setAttribute("XSSFilteredRequest", filteredRequest);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
}
}
3.让拦截器生效
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private XSSInterceptor xssInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(xssInterceptor);
}
}
这样就行了,这个就是不依赖第三方组件库的xss拦截实现方案。