zoukankan      html  css  js  c++  java
  • Xss问题解决方案

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

    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 List<MediaType> supportMediaTypes = new ArrayList<MediaType>();
    
    	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<String, String> map) {
    		Set<Entry<String, List<String>>> mapEntrySet = map.entrySet();
    		for (Entry<String, List<String>> mapEntry : mapEntrySet) {
    			mapEntry.setValue(escapeHtml(mapEntry.getValue()));
    		}
    	}
    
    	private List<String> escapeHtml(List<String> values) {
    		List<String> escapeValues = new ArrayList<String>(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();
    		}
    
    	}
    
    }
    
    

    3.web.xml配置

    <filter>
    	<filter-name>httpFormFilter</filter-name>
    	<filter-class>com.jing.springboot.test.HttpContentFormFilter</filter-class>
    </filter>
    
    <filter-mapping>
    	<filter-name>httpFormFilter</filter-name>
    	<url-pattern>/*</url-pattern>
    </filter-mapping>
    

    前端屏蔽

    对上传的数据不作html过滤,对返回的数据呈现在页面上使用html标签过滤,建议采用,写一个专门的公用类即可

    //html标签转义成自定义字符
    function html2Escape(sHtml) { 
        return sHtml.replace(/[<>&"]/g,function(c){
            return {'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c];
        }); 
    }
    

    总结

    xss问题属于被动式攻击,一般很容易被忽略,在项目的安全检测中遇到此问题,在此作下笔记方便以后查阅

  • 相关阅读:
    MySQL 5.7.18 zip 文件安装过程
    Mysql 自定义随机字符串
    JAVA基本类型和引用类型
    初识JSP
    Java导出错误数据
    时序图的使用习惯
    Redis踩坑
    ES踩坑
    代码规范
    Git在公司的使用流程
  • 原文地址:https://www.cnblogs.com/question-sky/p/8644915.html
Copyright © 2011-2022 走看看