SpringBoot實(shí)現(xiàn)防止XSS攻擊的示例詳解
XSS
跨站腳本工具(cross 斯特scripting),為不和層疊樣式表(cascading style sheets,CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS。惡意攻擊者往web頁面里插入惡意ScriptScript代碼,當(dāng)用戶瀏覽該頁之時(shí),嵌入其中Web里面的Script代碼會(huì)被執(zhí)行,從而達(dá)到惡意攻擊用戶的目的。防止XSS攻擊簡單的預(yù)防就是對Request請求中的一些參數(shù)去掉一些比較敏感的腳本命令。原本是打算通過SpringMVC的HandlerInterceptor機(jī)制來實(shí)現(xiàn)的,通過獲取request然后對request中的參數(shù)進(jìn)行修改,結(jié)果雖然值修改了,但在Controller中獲取的數(shù)值還是沒有修改的。沒辦法就是要Filter來完成。簡單來說就是創(chuàng)建一個(gè)新的HttpRequest類XssHttpServletRequestWrapper,然后重寫一些get方法(獲取參數(shù)時(shí)對參數(shù)進(jìn)行XSS判斷預(yù)防)
流程梳理
包裝request->創(chuàng)建過濾器->添加過濾器
1.創(chuàng)建包裝request的類 XssHttpServletRequestWrapper
import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sysware.framework.exceptions.SyswareRuntimeException; import com.sysware.framework.file.service.impl.FileGridServiceImpl; public class XssHttpServletRequestWraper extends HttpServletRequestWrapper { private Logger log = LoggerFactory.getLogger(FileGridServiceImpl.class); public XssHttpServletRequestWraper() { super(null); } public XssHttpServletRequestWraper(HttpServletRequest httpservletrequest) { super(httpservletrequest); } //過濾springmvc中的 @RequestParam 注解中的參數(shù) public String[] getParameterValues(String s) { String str[] = super.getParameterValues(s); if (str == null) { return null; } int i = str.length; String as1[] = new String[i]; for (int j = 0; j < i; j++) { //System.out.println("getParameterValues:"+str[j]); as1[j] = cleanXSS(cleanSQLInject(str[j])); } log.info("XssHttpServletRequestWraper凈化后的請求為:==========" + as1); return as1; } //過濾request.getParameter的參數(shù) public String getParameter(String s) { String s1 = super.getParameter(s); if (s1 == null) { return null; } else { String s2 = cleanXSS(cleanSQLInject(s1)); log.info("XssHttpServletRequestWraper凈化后的請求為:==========" + s2); return s2; } } //過濾請求體 json 格式的 @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ()); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } public String inputHandlers(ServletInputStream servletInputStream){ StringBuilder sb = new StringBuilder(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (servletInputStream != null) { try { servletInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return cleanXSS(sb.toString ()); } public String cleanXSS(String src) { String temp = src; src = src.replaceAll("<", "<").replaceAll(">", ">"); src = src.replaceAll("\\(", "(").replaceAll("\\)", ")"); src = src.replaceAll("'", ""); src = src.replaceAll(";", ""); /**-----------------------start--------------------------*/ src = src.replaceAll("<", "& lt;").replaceAll(">", "& gt;"); src = src.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41"); src = src.replaceAll("eval\\((.*)\\)", ""); src = src.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); // src = src.replaceAll("script", ""); // src = src.replaceAll("link", ""); // src = src.replaceAll("frame", ""); /**-----------------------end--------------------------*/ Pattern pattern = Pattern.compile("(eval\\((.*)\\)|script)", Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(src); src = matcher.replaceAll(""); pattern = Pattern.compile("[\\\"\\'][\\s]*javascript:(.*)[\\\"\\']", Pattern.CASE_INSENSITIVE); matcher = pattern.matcher(src); src = matcher.replaceAll("\"\""); // 增加腳本 src = src.replaceAll("script", "").replaceAll(";", "") /*.replaceAll("\"", "").replaceAll("@", "")*/ .replaceAll("0x0d", "").replaceAll("0x0a", ""); // if (!temp.equals(src)) { // // System.out.println("輸入信息存在xss攻擊!"); // // System.out.println("原始輸入信息-->" + temp); // // System.out.println("處理后信息-->" + src); // // log.error("xss攻擊檢查:參數(shù)含有非法攻擊字符,已禁止繼續(xù)訪問??!"); // log.error("原始輸入信息-->" + temp); // // throw new SyswareRuntimeException("xss攻擊檢查:參數(shù)含有非法攻擊字符,已禁止繼續(xù)訪問??!"); // } return src; } //輸出 public void outputMsgByOutputStream(HttpServletResponse response, String msg) throws IOException { ServletOutputStream outputStream = response.getOutputStream(); //獲取輸出流 response.setHeader("content-type", "text/html;charset=UTF-8"); //通過設(shè)置響應(yīng)頭控制瀏覽器以UTF-8的編碼顯示數(shù)據(jù),如果不加這句話,那么瀏覽器顯示的將是亂碼 byte[] dataByteArr = msg.getBytes("UTF-8");// 將字符轉(zhuǎn)換成字節(jié)數(shù)組,指定以UTF-8編碼進(jìn)行轉(zhuǎn)換 outputStream.write(dataByteArr);// 使用OutputStream流向客戶端輸出字節(jié)數(shù)組 } // 需要增加通配,過濾大小寫組合 public String cleanSQLInject(String src) { String lowSrc = src.toLowerCase(); String temp = src; String lowSrcAfter = lowSrc.replaceAll(" insert ", "forbidI") .replaceAll(" select ", "forbidS") .replaceAll(" update ", "forbidU") .replaceAll(" delete ", "forbidD").replaceAll(" and ", "forbidA") .replaceAll(" or ", "forbidO").replace("'", ""); if (!lowSrcAfter.equals(lowSrc)) { log.error("sql注入檢查:輸入信息存在SQL攻擊!"); log.error("原始輸入信息-->" + temp); log.error("處理后信息-->" + lowSrc); throw new SyswareRuntimeException("sql注入檢查:參數(shù)含有非法攻擊字符,已禁止繼續(xù)訪問!!"); } return src; } }
注意:
getInputStream()方法的流處理,注解方式獲取數(shù)據(jù)貌似是根據(jù)這個(gè)流取得的數(shù)據(jù)。
因?yàn)閟uper.getInputStream()流只允許讀取一次,所以在getInputStream()方法中處理完流數(shù)據(jù)后返回了一個(gè)新的ServletInputStream。另外替換方法里的替換規(guī)則,也可以根據(jù)實(shí)際業(yè)務(wù)需要進(jìn)行調(diào)整。
2.創(chuàng)建過濾器 XssFilter
@Component public class XssFilter implements Filter { // 忽略權(quán)限檢查的url地址 private final String[] excludeUrls = new String[]{ "/api/item","api/document" }; public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) arg0; HttpServletResponse response = (HttpServletResponse) arg1; String pathInfo = req.getPathInfo() == null ? "" : req.getPathInfo(); //獲取請求url的后兩層 String url = req.getServletPath() + pathInfo; //獲取請求你ip后的全部路徑 String uri = req.getRequestURI(); //注入xss過濾器實(shí)例 XssHttpServletRequestWraper reqW = new XssHttpServletRequestWraper(req); //過濾掉不需要的Xss校驗(yàn)的地址 for (String str : excludeUrls) { if (uri.indexOf(str) >= 0) { //過濾 arg2.doFilter(reqW, response); return; } } arg2.doFilter(arg0, response); } public void destroy() { } public void init(FilterConfig filterconfig1) throws ServletException { } }
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)防止XSS攻擊的示例詳解的文章就介紹到這了,更多相關(guān)SpringBoot防止XSS攻擊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)File轉(zhuǎn)換MultipartFile格式的例子
本文主要介紹了Java實(shí)現(xiàn)File轉(zhuǎn)換MultipartFile格式的例子,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Spring?Boot?中的?@HystrixCommand?注解原理及使用方法
通過使用 @HystrixCommand 注解,我們可以輕松地實(shí)現(xiàn)對方法的隔離和監(jiān)控,從而提高系統(tǒng)的可靠性和穩(wěn)定性,本文介紹了Spring Boot 中的@HystrixCommand注解是什么,其原理以及如何使用,感興趣的朋友跟隨小編一起看看吧2023-07-07Java Bean與Map之間相互轉(zhuǎn)化的實(shí)現(xiàn)方法
這篇文章主要介紹了Java Bean與Map之間相互轉(zhuǎn)化的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Java?Date(日期)對象進(jìn)行格式化的思路詳解
Date類是經(jīng)常會(huì)使用到的一個(gè)用來處理日期、時(shí)間的一個(gè)類。Date類是在java.util包下的Date類,這篇文章主要介紹了Java?Date(日期)對象如何進(jìn)行格式化呢,需要的朋友可以參考下2022-09-09