xss跨站脚本攻击问题最主要是呈现在html页面的脚本被执行导致的结果,可分为两个方便作屏蔽
后台屏蔽
在前端上传的各个参数后,对其进行转义后再保存至数据库,属于暴力式转义,一般不建议。下面是写的例子
- 创建HttpServletRequest新对象,覆盖其中的
getParameterMap()方法,其会被ServletModelAttributeMethodProcessor处理方法参数时被调用,具体的读者可自行分析
package com.jing.springboot.test;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.springframework.util.MultiValueMap;
public class FormHttpRequestWrapper extends HttpServletRequestWrapper {
// 采用spring的MultiValueMap集合
private MultiValueMap<String, String> paramsMap;
public FormHttpRequestWrapper(HttpServletRequest request) {
super(request);
}
public FormHttpRequestWrapper(HttpServletRequest request, MultiValueMap<String, String> paramMap) {
super(request);
this.paramsMap = paramMap;
}
@Override
public String getParameter(String name) {
String param = super.getParameter(name);
return param == null ? paramsMap.getFirst(name) : param;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> paramterMap = super.getParameterMap();
Set<Entry<String, List<String>>> mapSets = paramsMap.entrySet();
for (Entry<String, List<String>> mapSet : mapSets) {
String key = mapSet.getKey();
List<String> values = mapSet.getValue();
paramterMap.put(key, values.toArray(new String[values.size()]));
}
return paramterMap;
}
@Override
public Enumeration<String> getParameterNames() {
return super.getParameterNames();
}
@Override
public String[] getParameterValues(String name) {
List<String> multiValues = paramsMap.get(name);
String[] oldValues = super.getParameterValues(name);
Set<String> trueValues = new HashSet<String>(oldValues.length + multiValues.size());
for (String multi : multiValues) {
trueValues.add(multi);
}
for (String old : oldValues) {
trueValues.add(old);
}
return trueValues.toArray(new String[trueValues.size()]);
}
}- 创建filter类过滤器,对每次的POST请求或者PUT请求作下拦截
```java
package com.jing.springboot.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.HtmlUtils;
/**
- 参数拦截过滤器
- @author jtj
-
*/
public class HttpContentFormFilter extends OncePerRequestFilter {private List
supportMediaTypes = new ArrayList (); private FormHttpMessageConverter messageConverter = new AllEncompassingFormHttpMessageConverter();
public HttpContentFormFilter() {
supportMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
}@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String method = request.getMethod();
String contentType = request.getContentType();if (methodEqual(method) && mediaEqual(contentType)) { HttpInputMessage httpInputMessage = new FormHttpInputMessage(request); // 采用FormHttpMessageConverter对象读取参数集合 MultiValueMap<String, String> springMultiValueMap = messageConverter.read(null, httpInputMessage); // 使用spring自带的HtmlUtils工具类来转义html标签 useSpringHtmlEscape(springMultiValueMap); // 重新构造request对象,将转义后的参数存进去 FormHttpRequestWrapper httpRequestWrapper = new FormHttpRequestWrapper(request, springMultiValueMap); filterChain.doFilter(httpRequestWrapper, response); } else { filterChain.doFilter(request, response); }}
private boolean methodEqual(String reqMethod) {
if (reqMethod.equals("POST") || reqMethod.equals("PUT")) {
return true;
}return false;}
private boolean mediaEqual(String mediaType) {
boolean isSupport = false;
for (MediaType type : supportMediaTypes) {
isSupport = type.includes(new MediaType(mediaType));
if (isSupport) {
break;
}
}return isSupport;}
private void useSpringHtmlEscape(MultiValueMap
map) {
Set<Entry<String, List>> mapEntrySet = map.entrySet();
for (Entry<String, List> mapEntry : mapEntrySet) {
mapEntry.setValue(escapeHtml(mapEntry.getValue()));
}
}private List
escapeHtml(List values) {
ListescapeValues = new ArrayList (values.size());
for (String value : values) {
escapeValues.add(HtmlUtils.htmlEscape(value));
}return escapeValues;}
private class FormHttpInputMessage implements HttpInputMessage {
private HttpServletRequest request; public FormHttpInputMessage(HttpServletRequest request) { this.request = request; } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String headerValue = request.getHeader(name); headers.add(headerNames.nextElement(), headerValue); } return headers; } @Override public InputStream getBody() throws IOException { return request.getInputStream(); }}
}
```
- web.xml配置
```xmlhttpFormFilter com.jing.springboot.test.HttpContentFormFilter
```
前端屏蔽
对上传的数据不作html过滤,对返回的数据呈现在页面上使用html标签过滤,建议采用,写一个专门的公用类即可
//html标签转义成自定义字符
function html2Escape(sHtml) {
return sHtml.replace(/[<>&"]/g,function(c){
return {'<':'<','>':'>','&':'&','"':'"'}[c];
});
}总结
xss问题属于被动式攻击,一般很容易被忽略,在项目的安全检测中遇到此问题,在此作下笔记方便以后查阅