1 瞭解CSRF的定義
CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS非常不同,XSS利用站點內的信任用戶,而CSRF則通過偽裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認為比XSS更具危險性。
攻擊通過在授權用戶訪問的頁面中包含鏈接或者腳本的方式工作。例如:一個網站用戶Bob可能正在瀏覽聊天論壇,而同時另一個用戶Alice也在此論壇中,並且後者剛剛發佈了一個具有Bob銀行鏈接的圖片消息。設想一下,Alice編寫了一個在Bob的銀行站點上進行取款的form提交的鏈接,並將此鏈接作為圖片src。如果Bob的銀行在cookie中保存他的授權信息,並且此cookie沒有過期,那麼當Bob的瀏覽器嘗試裝載圖片時將提交這個取款form和他的cookie,這樣在沒經Bob同意的情況下便授權了這次事務。
2 在項目中如何解決csrf的攻擊
我們以用戶登錄這段代碼來舉例說明:
2.1 首先項目裡面引入CSRFTokenManager.java,這個裡面主要是產生一個csrftoken session的代碼。
2.2 在用戶進入項目,還沒有跳轉到登錄頁面之前,我們通過CSRFTokenManager代碼產生一個token,然後把它傳入登錄頁面,給它定義成csrf。
2.3 在登錄頁面裡面,通過隱藏域來獲取剛剛傳入的csrf,這樣當用戶提交form表單的時候,這裡的csrf就會一起被提交到後臺的代碼。
2.4 在後臺代碼裡面,我們通過頁面傳入的token和已經產生的token session進行對比,如果兩個相同,那麼這些操作就認為是用戶自己在操作,如果頁面傳入的和產生的token不相同那麼這就是其他人員通過模擬用戶進行了這樣的操作,那麼我們就要對它進行處理,讓它跳轉到登錄頁面。
3 瞭解XSS的定義
跨站腳本攻擊(Cross Site Scripting),為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS。惡意攻擊者往Web頁面裡插入惡意Script代碼,當用戶瀏覽該頁之時,嵌入其中Web裡面的Script代碼會被執行,從而達到惡意攻擊用戶的目的。XSS攻擊分成兩類,一類是來自內部的攻擊,主要指的是利用程序自身的漏洞,構造跨站語句,如:dvbbs的showerror.asp存在的跨站漏洞。另一類則是來自外部的攻擊,主要指的自己構造XSS跨站漏洞網頁或者尋找非目標機以外的有跨站漏洞的網頁。如當我們要滲透一個站點,我們自己構造一個有跨站漏洞的網頁,然後構造跨站語句,通過結合其它技術,如社會工程學等,欺騙目標服務器的管理員打開。
4 在項目中如何解決XSS的攻擊
4.1 首先項目導入XSSStringEncoder.java,這個裡面主要就是把傳入字符串的特殊字符進行html轉碼,例如> < ) ( " ' % ; & +,這些特殊字符很有可能就是被注入的代碼。
4.2 對每一個代碼傳入的字符串調用這裡面的encodeXSSString進行轉碼,然後把轉碼後的字符串返回回來
附,CSRFTokenManager,XSSStringEncoder內容:
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();
}
}