xss跨站脚本攻击问题最主要是呈现在html页面的脚本被执行导致的结果,可分为两个方便作屏蔽
后台屏蔽
在前端上传的各个参数后,对其进行转义后再保存至数据库,属于暴力式转义,一般不建议。下面是写的例子
1.创建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 MultiValueMapparamsMap; public FormHttpRequestWrapper(HttpServletRequest request) { super(request); } public FormHttpRequestWrapper(HttpServletRequest request, MultiValueMap 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 getParameterMap() { Map paramterMap = super.getParameterMap(); Set >> mapSets = paramsMap.entrySet(); for (Entry > mapSet : mapSets) { String key = mapSet.getKey(); List values = mapSet.getValue(); paramterMap.put(key, values.toArray(new String[values.size()])); } return paramterMap; } @Override public Enumeration getParameterNames() { return super.getParameterNames(); } @Override public String[] getParameterValues(String name) { List multiValues = paramsMap.get(name); String[] oldValues = super.getParameterValues(name); Set trueValues = new HashSet (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()]); }}
2.创建参数拦截filter类过滤器,对每次的POST请求或者PUT请求作下拦截
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;public class HttpContentFormFilter extends OncePerRequestFilter { private ListsupportMediaTypes = 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 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 >> mapEntrySet = map.entrySet(); for (Entry > mapEntry : mapEntrySet) { mapEntry.setValue(escapeHtml(mapEntry.getValue())); } } private List escapeHtml(List values) { List escapeValues = 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 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(); } }}
3.web.xml配置
httpFormFilter com.jing.springboot.test.HttpContentFormFilter httpFormFilter /*
前端屏蔽
对上传的数据不作html过滤,对返回的数据呈现在页面上使用html标签过滤,建议采用,写一个专门的公用类即可
//html标签转义成自定义字符function html2Escape(sHtml) { return sHtml.replace(/[<>&"]/g,function(c){ return {'<':'<','>':'>','&':'&','"':'"'}[c]; }); }
总结
xss问题属于被动式攻击,一般很容易被忽略,在项目的安全检测中遇到此问题,在此作下笔记方便以后查阅