1:xss攻擊原理說明
這里不再詳細參數,簡單說一下,就是前端提交了可執行的js等腳本,存儲到數據庫,頁面再次加載時獲取到該腳本執行了腳本內容就發生了腳本注入。
2:處理辦法
轉義提交字符
3:代碼邏輯原理
利用過濾器,重寫參數獲取方法,對參數進行轉義。
4:代碼
4.1 xss轉義包裝類(重寫getParameter、getParameterValues、getParameterMap)
package com.zxy.product.system.web.converter; import cn.hutool.core.util.EscapeUtil; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.safety.Whitelist; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { public static final String HEADER_XSS_FILTER = "xssFilter"; public static final String[] EMPTY_STRING_ARRAY = new String[0]; /** * 安全xss處理,不影響普通標簽輸出。 */ public static final String XSS_FILTER_FULL_ANGLE = "1"; /** * html轉義 */ public static final String XSS_FILTER_ESCAPE_HTML = "2"; /** * Constructs a request object wrapping the given request. * * @param request The request to wrap * @throws IllegalArgumentException if the request is null */ public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); } /** * 全角字符轉義 * * @param str 待轉義 * @return 轉義結果 * @author wulingming * @date 2021/9/9 17:07 **/ public static String escapeFullAngle(String str) { if (str == null || str.length() == 0) { return str; } else { return str.replace("<", "《").replace(">", "》"); } } public static String escapeHtml4(String str) { if (str == null || str.length() == 0) { return str; } else { return EscapeUtil.escapeHtml4(str); } } private static String escape(String value) { return escape(value, null); } private static String escape(String value, String headerXssFilter) { if (XSS_FILTER_ESCAPE_HTML.equals(headerXssFilter)) { //html轉義 return escapeHtml4(value); } else { //使用Jsoup防止XSS攻擊。還有一種方式是hutol(優缺點,部分字符可能不輸出) return clean(value); } } @Override public String getParameter(String name) { String value = super.getParameter(name); if (value == null || value.length() == 0) { return null; } String headerXssFilter = super.getHeader(HEADER_XSS_FILTER); return escape(value, headerXssFilter); } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values == null || values.length == 0) { return values; } String headerXssFilter = super.getHeader(HEADER_XSS_FILTER); return Stream.of(values).map(value -> escape(value, headerXssFilter)).collect(Collectors.toList()) .toArray(EMPTY_STRING_ARRAY); } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> parameterMap = super.getParameterMap(); if (parameterMap == null || parameterMap.isEmpty()) { return parameterMap; } String headerXssFilter = super.getHeader(HEADER_XSS_FILTER); return parameterMap.keySet().stream().filter(Objects::nonNull) .collect(Collectors.toMap(key -> key, key -> { String[] values = parameterMap.get(key); if (values == null || values.length == 0) { return EMPTY_STRING_ARRAY; } else { return Stream.of(values).map(value -> escape(value, headerXssFilter)) .collect(Collectors.toList()).toArray(EMPTY_STRING_ARRAY); } })); } /** * 使用自帶的basicWithImages 白名單 * 允許的便簽有a,b,blockquote,br,cite,code,dd,dl,dt,em,i,li,ol,p,pre,q,small,span, * strike,strong,sub,sup,u,ul,img * 以及a標簽的href,img標簽的src,align,alt,height,width,title屬性 */ private static final Whitelist whitelist = Whitelist.relaxed(); /** * 配置過濾化參數,不對代碼進行格式化 */ private static final Document.OutputSettings outputSettings = new Document.OutputSettings() .prettyPrint(false); static { // 富文本編輯時一些樣式是使用style來進行實現的,比如紅色字體 style="color:red;" whitelist.addAttributes(":all", "style"); //使用相對路徑,比如:img標簽 whitelist.preserveRelativeLinks(true); } /** * 安全xss處理,不影響普通標簽輸出。 * * @param text 原始文本 * @return 清理后的文本 * @author wulingming **/ public static String clean(String text) { //baseUri可以隨便填寫,因為使用了相對路徑 preserveRelativeLinks(true) return Jsoup.clean(text, "https://ilearning.csair.com/", whitelist, outputSettings); } }
4.2 xss過濾器配置
/** * xss攻擊防范處理 * @author wulingming * @date 2021/9/9 16:32 **/ @WebFilter(urlPatterns = "/*", filterName = "xssFilter") public class XssFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { XssHttpServletRequestWrapper req=new XssHttpServletRequestWrapper((HttpServletRequest)request); chain.doFilter(req,response); } }
4.3 springboot 啟動類配置過濾器掃描
@ServletComponentScan
getParameter
