詳解java解決XSS攻擊常用方法總結(jié)
在項(xiàng)目驗(yàn)收階段,通常會(huì)對(duì)待驗(yàn)收項(xiàng)目做一些安全漏洞的測(cè)試,比如接口攻擊,并發(fā)測(cè)試,XSS注入,SQL惡意注入測(cè)試,安全越權(quán)等操作,這時(shí),就是考驗(yàn)項(xiàng)目的安全方面是否做的足夠健壯的時(shí)候,本篇對(duì)XSS腳本攻擊在實(shí)際WEB項(xiàng)目中的處理辦法,提供2種可實(shí)行的方法
xss攻擊XSS攻擊通常指的是通過(guò)利用網(wǎng)頁(yè)開(kāi)發(fā)時(shí)留下的漏洞,通過(guò)巧妙的方法注入惡意指令代碼到網(wǎng)頁(yè),使用戶(hù)加載并執(zhí)行攻擊者惡意制造的網(wǎng)頁(yè)程序。這些惡意網(wǎng)頁(yè)程序通常是JavaScript,但實(shí)際上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻擊成功后,攻擊者可能得到包括但不限于更高的權(quán)限(如執(zhí)行一些操作)、私密網(wǎng)頁(yè)內(nèi)容、會(huì)話和cookie等各種內(nèi)容
簡(jiǎn)單說(shuō)就是說(shuō),通過(guò)在輸入框輸入一些js代碼,如在賬號(hào)密碼輸入框中輸入
<video src=1 onerror=alert(/xss/)/>
或者
<script>alert('@@') </script>
這樣點(diǎn)擊提交的時(shí)候就會(huì)觸發(fā)alert彈窗,分別彈出 xss 和 @@ 的內(nèi)容,這里只是做個(gè)簡(jiǎn)單的演示,彈了個(gè)窗口,還能存儲(chǔ)病毒下載地址到服務(wù)端,進(jìn)入的時(shí)候自動(dòng)下載,或者修改你的cookie啥的,這里感興趣可以百度查查xss攻擊
解決方式一:強(qiáng)制修改html敏感標(biāo)簽內(nèi)容這是一種相對(duì)容易理解的方式,解決思路就是,當(dāng)惡意注入的字段中,包含了類(lèi)似<script>alert(ooo)</script>這種html標(biāo)簽時(shí),后臺(tái)程序代碼中強(qiáng)制替換或更改標(biāo)簽內(nèi)容,這樣存入數(shù)據(jù)庫(kù)的內(nèi)容再次返回至頁(yè)面時(shí),就不會(huì)以html的形式進(jìn)行執(zhí)行了
下面提供一個(gè)工具類(lèi)
/** * xss特殊字符攔截與過(guò)濾 * * @author zhangcy * @date 2021-04016 */public class XssStrUtils { /** * 濾除content中的危險(xiǎn) HTML 代碼, 主要是腳本代碼, 滾動(dòng)字幕代碼以及腳本事件處理代碼 * @param content 需要濾除的字符串 * @return 過(guò)濾的結(jié)果 */ public static String replaceHtmlCode(String content) {if (null == content) return null;if (0 == content.length()) return '';// 需要濾除的腳本事件關(guān)鍵字String[] eventKeywords = {'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'onmousemove', 'onclick', 'ondblclick','onkeypress', 'onkeydown', 'onkeyup', 'ondragstart', 'onerrorupdate', 'onhelp', 'onreadystatechange','onrowenter', 'onrowexit', 'onselectstart', 'onload', 'onunload', 'onbeforeunload', 'onblur','onerror', 'onfocus', 'onresize', 'onscroll', 'oncontextmenu', 'alert'};content = replace(content, '<script', '<script', false);content = replace(content, '</script', '</script', false);content = replace(content, '<marquee', '<marquee', false);content = replace(content, '</marquee', '</marquee', false);content = replace(content, '’', '_', false);// 將單引號(hào)替換成下劃線content = replace(content, ''', '_', false);// 將雙引號(hào)替換成下劃線// 濾除腳本事件代碼for (int i = 0; i < eventKeywords.length; i++) { content = replace(content, eventKeywords[i], '_' + eventKeywords[i], false); // 添加一個(gè)'_', 使事件代碼無(wú)效}return content; } /** * 將字符串 source 中的 oldStr 替換為 newStr, 并以大小寫(xiě)敏感方式進(jìn)行查找 * * @param source 需要替換的源字符串 * @param oldStr 需要被替換的老字符串 * @param newStr 替換為的新字符串 */ private static String replace(String source, String oldStr, String newStr) {return replace(source, oldStr, newStr, true); } /** * 將字符串 source 中的 oldStr 替換為 newStr, matchCase 為是否設(shè)置大小寫(xiě)敏感查找 * * @param source 需要替換的源字符串 * @param oldStr 需要被替換的老字符串 * @param newStr 替換為的新字符串 * @param matchCase 是否需要按照大小寫(xiě)敏感方式查找 */ private static String replace(String source, String oldStr, String newStr,boolean matchCase) {if (source == null) return null;// 首先檢查舊字符串是否存在, 不存在就不進(jìn)行替換if (source.toLowerCase().indexOf(oldStr.toLowerCase()) == -1) return source;int findStartPos = 0;int a = 0;while (a > -1) { int b = 0; String str1, str2, str3, str4, strA, strB; str1 = source; str2 = str1.toLowerCase(); str3 = oldStr; str4 = str3.toLowerCase(); if (matchCase) {strA = str1;strB = str3; } else {strA = str2;strB = str4; } a = strA.indexOf(strB, findStartPos); if (a > -1) {b = oldStr.length();findStartPos = a + b;StringBuffer bbuf = new StringBuffer(source);source = bbuf.replace(a, a + b, newStr) + '';// 新的查找開(kāi)始點(diǎn)位于替換后的字符串的結(jié)尾findStartPos = findStartPos + newStr.length() - b; }}return source; }}
我們用一個(gè)實(shí)際的接口做一下簡(jiǎn)單的測(cè)試
@PostMapping('/getAccName') public String getAccName(@RequestBody NameParams params){String s = XssStrUtils.replaceHtmlCode(params.getName());return s; }
使用接口工具調(diào)一下,
使用這種方式,即使前端惡意注入了某些非法的html標(biāo)簽,經(jīng)過(guò)后端的過(guò)濾處理,返回的內(nèi)容就不會(huì)執(zhí)行html的相關(guān)操作事件了
解決方式二:利用過(guò)濾器過(guò)濾非法html標(biāo)簽第二種思路,考慮在過(guò)濾器中添加對(duì)所有請(qǐng)求接口的參數(shù)進(jìn)行參數(shù)的攔截過(guò)濾,即程序認(rèn)為的不合法標(biāo)簽都會(huì)自動(dòng)做過(guò)濾,至于過(guò)濾的規(guī)則,可以借助現(xiàn)有的第三方組件,比如spring框架的htmlUtil類(lèi),這里使用hutool工具集提供的相關(guān)API做處理
導(dǎo)入依賴(lài)
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.5.9</version></dependency>
1、添加自定義過(guò)濾器增強(qiáng)包裝類(lèi)
public class XssHttpRequestWrapper extends HttpServletRequestWrapper { public XssHttpRequestWrapper(HttpServletRequest request) {super(request); } @Override public String getParameter(String name) {String value = super.getParameter(name);if(!StringUtils.isEmpty(value)){ value = HtmlUtil.filter(value);}return value; } @Override public String[] getParameterValues(String name) {String[] values = super.getParameterValues(name);if(values!=null){ for(int i=0;i<values.length;i++){String value = values[i];if(!StringUtils.isEmpty(value)){ value = HtmlUtil.filter(value);}values[i]=value; }}return values; } @Override public Map<String, String[]> getParameterMap() {Map<String, String[]> parameters = super.getParameterMap();Map<String, String[]> map = new LinkedHashMap<>();if(parameters !=null){ for(String key : parameters.keySet()){String[] values = parameters.get(key);for(int i=0;i<values.length;i++){ String value = values[i]; if(!StringUtils.isEmpty(value)){value = HtmlUtil.filter(value); } values[i]=value;}map.put(key,values); }}return map; } @Override public String getHeader(String name) {String value = super.getHeader(name);if(!StringUtils.isEmpty(value)){ value = HtmlUtil.filter(value);}return value; } @Override public ServletInputStream getInputStream() throws IOException {InputStream in = super.getInputStream();InputStreamReader reader = new InputStreamReader(in, Charset.forName('UTF-8'));BufferedReader buffer = new BufferedReader(reader);StringBuffer body = new StringBuffer();String line = buffer.readLine();while (line !=null){ body.append(line); line = buffer.readLine();}buffer.close();reader.close();in.close();Map<String,Object> map = JSONUtil.parseObj(body.toString());Map<String,Object> result = new LinkedHashMap<>();for(String key : map.keySet()){ Object val = map.get(key); if(val instanceof String){if(!StringUtils.isEmpty(val.toString())){ result.put(key,HtmlUtil.filter(val.toString()));} }else {result.put(key,val); }}String json = JSONUtil.toJsonStr(result);ByteArrayInputStream bain = new ByteArrayInputStream(json.getBytes());return new ServletInputStream() { @Override public boolean isFinished() {return false; } @Override public boolean isReady() {return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException {return bain.read(); }}; }}
可以理解為,在自定義過(guò)濾器中添加上面的增強(qiáng)類(lèi),那么所有請(qǐng)求后端的接口都將先走改類(lèi)的邏輯,參數(shù)進(jìn)行過(guò)濾
2、自定義過(guò)濾器并注入全局bean
public class XssFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest)servletRequest;XssHttpRequestWrapper requestWrapper = new XssHttpRequestWrapper(request);filterChain.doFilter(requestWrapper,servletResponse); } @Override public void destroy() { }}
@Configurationpublic class XSSFilterRegister { @Bean public FilterRegistrationBean<XssFilter> RegistTest1(){//通過(guò)FilterRegistrationBean實(shí)例設(shè)置優(yōu)先級(jí)可以生效FilterRegistrationBean<XssFilter> bean = new FilterRegistrationBean<XssFilter>();bean.setFilter(new XssFilter());//注冊(cè)自定義過(guò)濾器bean.setName('flilter');//過(guò)濾器名稱(chēng)bean.addUrlPatterns('/*');//過(guò)濾所有路徑return bean; }}
仍然使用上面的接口做一下測(cè)試
@PostMapping('/getAccName') public String getAccName(@RequestBody NameParams params){return 'name is : '+ params.getName(); }
通過(guò)這種方式,直接將注入的敏感標(biāo)簽符號(hào)去掉,這樣確保了入庫(kù)的數(shù)據(jù)的安全性,返回給頁(yè)面的數(shù)據(jù)就不存在非法html標(biāo)簽問(wèn)題了
到此這篇關(guān)于詳解java解決XSS攻擊常用方法總結(jié)的文章就介紹到這了,更多相關(guān)java XSS攻擊 內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. 讀大數(shù)據(jù)量的XML文件的讀取問(wèn)題2. Xml簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理3. ASP實(shí)現(xiàn)加法驗(yàn)證碼4. 秒殺場(chǎng)景的緩存、隊(duì)列、鎖使用Redis優(yōu)化設(shè)計(jì)方案5. ASP腳本組件實(shí)現(xiàn)服務(wù)器重啟6. 輕松學(xué)習(xí)XML教程7. XHTML 1.0:標(biāo)記新的開(kāi)端8. 匹配模式 - XSL教程 - 49. ASP基礎(chǔ)知識(shí)Command對(duì)象講解10. CSS Hack大全-教你如何區(qū)分出IE6-IE10、FireFox、Chrome、Opera
