1 了解CSRF的定義
CSRF(Cross-site request forgery)跨站請(qǐng)求偽造,也被稱(chēng)為“One Click Attack”或者Session Riding,通??s寫(xiě)為CSRF或者XSRF,是一種對(duì)網(wǎng)站的惡意利用。盡管聽(tīng)起來(lái)像跨站腳本(XSS),但它與XSS非常不同,XSS利用站點(diǎn)內(nèi)的信任用戶(hù),而CSRF則通過(guò)偽裝來(lái)自受信任用戶(hù)的請(qǐng)求來(lái)利用受信任的網(wǎng)站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對(duì)其進(jìn)行防范的資源也相當(dāng)稀少)和難以防范,所以被認(rèn)為比XSS更具危險(xiǎn)性。
攻擊通過(guò)在授權(quán)用戶(hù)訪(fǎng)問(wèn)的頁(yè)面中包含鏈接或者腳本的方式工作。例如:一個(gè)網(wǎng)站用戶(hù)Bob可能正在瀏覽聊天論壇,而同時(shí)另一個(gè)用戶(hù)Alice也在此論壇中,并且后者剛剛發(fā)布了一個(gè)具有Bob銀行鏈接的圖片消息。設(shè)想一下,Alice編寫(xiě)了一個(gè)在Bob的銀行站點(diǎn)上進(jìn)行取款的form提交的鏈接,并將此鏈接作為圖片src。如果Bob的銀行在cookie中保存他的授權(quán)信息,并且此cookie沒(méi)有過(guò)期,那么當(dāng)Bob的瀏覽器嘗試裝載圖片時(shí)將提交這個(gè)取款form和他的cookie,這樣在沒(méi)經(jīng)Bob同意的情況下便授權(quán)了這次事務(wù)。
2 在項(xiàng)目中如何解決csrf的攻擊
我們以用戶(hù)登錄這段代碼來(lái)舉例說(shuō)明:
2.1 首先項(xiàng)目里面引入CSRFTokenManager.java,這個(gè)里面主要是產(chǎn)生一個(gè)csrftoken session的代碼。
2.2 在用戶(hù)進(jìn)入項(xiàng)目,還沒(méi)有跳轉(zhuǎn)到登錄頁(yè)面之前,我們通過(guò)CSRFTokenManager代碼產(chǎn)生一個(gè)token,然后把它傳入登錄頁(yè)面,給它定義成csrf。
2.3 在登錄頁(yè)面里面,通過(guò)隱藏域來(lái)獲取剛剛傳入的csrf,這樣當(dāng)用戶(hù)提交form表單的時(shí)候,這里的csrf就會(huì)一起被提交到后臺(tái)的代碼。
2.4 在后臺(tái)代碼里面,我們通過(guò)頁(yè)面?zhèn)魅氲膖oken和已經(jīng)產(chǎn)生的token session進(jìn)行對(duì)比,如果兩個(gè)相同,那么這些操作就認(rèn)為是用戶(hù)自己在操作,如果頁(yè)面?zhèn)魅氲暮彤a(chǎn)生的token不相同那么這就是其他人員通過(guò)模擬用戶(hù)進(jìn)行了這樣的操作,那么我們就要對(duì)它進(jìn)行處理,讓它跳轉(zhuǎn)到登錄頁(yè)面。
3 了解XSS的定義
跨站腳本攻擊(Cross Site Scripting),為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫(xiě)混淆,故將跨站腳本攻擊縮寫(xiě)為XSS。惡意攻擊者往Web頁(yè)面里插入惡意Script代碼,當(dāng)用戶(hù)瀏覽該頁(yè)之時(shí),嵌入其中Web里面的Script代碼會(huì)被執(zhí)行,從而達(dá)到惡意攻擊用戶(hù)的目的。XSS攻擊分成兩類(lèi),一類(lèi)是來(lái)自?xún)?nèi)部的攻擊,主要指的是利用程序自身的漏洞,構(gòu)造跨站語(yǔ)句,如:dvbbs的showerror.asp存在的跨站漏洞。另一類(lèi)則是來(lái)自外部的攻擊,主要指的自己構(gòu)造XSS跨站漏洞網(wǎng)頁(yè)或者尋找非目標(biāo)機(jī)以外的有跨站漏洞的網(wǎng)頁(yè)。如當(dāng)我們要滲透一個(gè)站點(diǎn),我們自己構(gòu)造一個(gè)有跨站漏洞的網(wǎng)頁(yè),然后構(gòu)造跨站語(yǔ)句,通過(guò)結(jié)合其它技術(shù),如社會(huì)工程學(xué)等,欺騙目標(biāo)服務(wù)器的管理員打開(kāi)。
4 在項(xiàng)目中如何解決XSS的攻擊
4.1 首先項(xiàng)目導(dǎo)入XSSStringEncoder.java,這個(gè)里面主要就是把傳入字符串的特殊字符進(jìn)行html轉(zhuǎn)碼,例如> < )="" (="" '="" '="" %="" ;="" &="">
4.2 對(duì)每一個(gè)代碼傳入的字符串調(diào)用這里面的encodeXSSString進(jìn)行轉(zhuǎn)碼,然后把轉(zhuǎn)碼后的字符串返回回來(lái)
附,CSRFTokenManager,XSSStringEncoder內(nèi)容:
1 CSRFTokenManager.java
package com.claridy.common.util;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
*
* A manager for the CSRF token for a given session. The
* {@link #getTokenForSession(HttpSession)} should used to
*
* obtain the token value for the current session (and this should be the only
* way to obtain the token value).
*
* ***/
publicfinalclass CSRFTokenManager {
/**
*
* The token parameter name
*/
staticfinal String CSRF_PARAM_NAME = 'CSRFToken';
/**
*
* The location on the session which stores the token
*/
publicstaticfinal String CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CSRFTokenManager.class.getName() + '.tokenval';
publicstatic String getTokenForSession(HttpSession session) {
String token = null;
synchronized (session) {
token = (String) session.getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);
if (null == token) {
token = UUID.randomUUID().toString();
session.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME, token);
}
}
return token;
}
/**
*
* Extracts the token value from the session
*
*
*
* @param request
*
* @return
*/
publicstatic String getTokenFromRequest(HttpServletRequest request) {
return request.getParameter(CSRF_PARAM_NAME);
}
private CSRFTokenManager() {
};
}
2 XSSStringEncoder.java
package com.claridy.common.util;
publicclass XSSStringEncoder {
/**
* 排除XSS(Cross Site Scripting)和SQL injection攻擊字元
*
* @param data
* */
publicstatic String encodeXSSString(String data) {
if (data == null || ''.equals(data)) {
return data;
}
final StringBuffer buf = new StringBuffer();
finalchar[] chars = data.toCharArray();
for (int i = 0; i < chars.length;="" i++)="">
// > < )="" (="" '="" '="" %="" ;="" &="">
if ((int) chars[i] == 62 || (int) chars[i] == 60 || (int) chars[i] == 41 || (int) chars[i] == 40 || (int) chars[i] == 34 || (int) chars[i] == 39
|| (int) chars[i] == 37 || (int) chars[i] == 59 || (int) chars[i] == 38 || (int) chars[i] == 43) {
buf.append('' + (int) chars[i]);
} else {
buf.append((char) chars[i]);
}
}
return buf.toString();
}
}
聯(lián)系客服