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問題屬於被動式攻擊,一般很容易被忽略,在項目的安全檢測中遇到此問題,在此作下筆記方便以后查閱


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM