需求:
1.防止用户RequestBody里面数据包含XSS Attack代码
2.防止用户RequestURL地址中包含XSS Attack代码
解决方案及思路:
1.写个拦截器拦截用户请求,之后正则表达式去过滤RequestBody和RequestURL部分包含恶意攻击的代码。
2.具体代码如下
/**
* Project Name:
* File Name:SecurityFilter.java
* Description: TODO
* Copyright: Copyright (c) 2017
* Company:
*
* @author
* @date Mar 19, 2019 4:01:44 PM
* @version
* @see
* @since
*/
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apachemons.io.IOUtils;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.stereotype.Component;
/**
* ClassName: SecurityFilter Description: filter all request
*
* @author
* @version
* @see
* @since
*/
@Component
@ServletComponentScan
public class SecurityFilter implements Filter
{
/**
* Title: init Description:
*
* @param filterConfig
* @throws ServletException
* (describe the param)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
/**
* Title: doFilter Description:
*
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
* (describe the param)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse,
* javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletRequest req = new XSSRequestWrapper((HttpServletRequest) request);
HttpServletResponse resp = (HttpServletResponse) response;
//clean xss attack code in reqeuest body
cleanRequestBody(req, resp);
//clean xss attack code in request url
cleanRequsetUrl(req, resp, chain);
}
/**
* Title: destroy Description:(describe the param)
*
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy()
{
}
public class XSSRequestWrapper extends HttpServletRequestWrapper
{
private final byte[] body;
public XSSRequestWrapper(HttpServletRequest request) throws IOException
{
super(request);
body = IOUtils.toString(request.getReader()).getBytes(Charset.forName("UTF-8"));
}
@Override
public BufferedReader getReader() throws IOException
{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException
{
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream()
{
@Override
public int read() throws IOException
{
return bais.read();
}
@Override
public boolean isFinished()
{
return false;
}
@Override
public boolean isReady()
{
return false;
}
@Override
public void setReadListener(ReadListener listener)
{
}
};
}
}
/**
*
* Title: stripXSS Description: replace potential xss attack code with ""
*
* @exception @see
* @since {@inheritDoc}
* @param value
* @return
*/
private String stripXSS(String value)
{
if (null != value && !value.isEmpty())
{
// Avoid anything between script tags
Pattern scriptPattern = Patternpile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Patternpile("src=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome </script> tag
scriptPattern = Patternpile("</script>", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
scriptPattern = Patternpile("alert\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
value = scriptPattern.matcher(value).replaceAll("");
// Remove any lonesome <script ...> tag
scriptPattern = Patternpile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid eval(...) expressions
scriptPattern = Patternpile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid expression(...) expressions
/*
* scriptPattern = Patternpile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE |
* Pattern.DOTALL); value = scriptPattern.matcher(value).replaceAll("");
*/
// Avoid javascript:... expressions
scriptPattern = Patternpile("javascript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern = Patternpile("vbscript:", Pattern.CASE_INSENSITIVE);
value = scriptPattern.matcher(value).replaceAll("");
// Avoid onload= expressions
scriptPattern = Patternpile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
value = scriptPattern.matcher(value).replaceAll("");
}
return value;
}
/**
*
* Title: cleanRequsetUrl Description: clean xss attack code of request url.
*
* @exception @see
* @since {@inheritDoc}
* @param req
* @param resp
* @param chain
* @throws IOException
* @throws ServletException
*/
private void cleanRequsetUrl(HttpServletRequest req, HttpServletResponse resp, FilterChain chain)
throws IOException, ServletException
{
StringBuffer sb = new StringBuffer();
String uri = req.getRequestURI();
String queryString = req.getQueryString();
String url = uri;
if (null != queryString && !queryString.isEmpty())
{
url = sb.append(uri).append(SecurityConstants.QUESTION_MARK).append(queryString).toString();
}
String cleanUrl = stripXSS(url);
if (null != cleanUrl && !cleanUrl.equals(url))
{
req.getRequestDispatcher(cleanUrl).forward(req, resp);
}
else
{
chain.doFilter(req, resp);
}
}
/**
*
* Title: cleanRequestBody Description: clean XSS Attack code of request body
*
* @exception @see
* @since {@inheritDoc}
* @param req
* @param resp
* @throws IOException
*/
private String cleanRequestBody(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
Reader reader = req.getReader();
String payload = IOUtils.toString(reader);
String body = stripXSS(payload);
System.out.println("body is\n" + body);
resp.getWriter().write(body);
return body;
}
}
遇到的问题:
1.The request was rejected because the URL was not normalized
原因:
1.1 是因为请求地址里面包含"//"
解决方案:
1.2 使用该方法获取请求地址:String uri = req.getRequestURI();而不用req.getRequestURL()。之后我们使用相对路径重新发一个请求即可:req.getRequestDispatcher(cleanUrl).forward(req, resp);
2.为什么不适用resp.sendRedirect(cleanUrl);
原因:
2.1 该方法一般情况下只能重新发一个GET请求,不能发POST或者PUT. 想用该方法发POST请求出去可以自己用JSP实现一个表格,较为麻烦。
解决方案:
用req.getRequestDispatcher(cleanUrl).forward(req, resp); 替换它。
PS:除了过滤用户输入的数据处理XSS以外,还可以 只要遇到XSS Code直接抛错出去,具体怎么处理需要根据需求来。
更多推荐
防止XSS Attack攻击的解决方案
发布评论