CSRF(Cross-site request forgery)跨站請(qǐng)求偽造,也被稱為"One Click Attack"(一鍵攻擊)或者"Session Riding"(會(huì)話控制),是一種對(duì)網(wǎng)站的惡意利用。與傳統(tǒng)的XSS攻擊(跨站腳本攻擊)相比,CSRF攻擊更加難以防范,被認(rèn)為更具危險(xiǎn)性。CSRF攻擊可以在用戶不知情的情況下,以用戶的名義偽造請(qǐng)求發(fā)送給攻擊頁面,從而在用戶未授權(quán)的情況下執(zhí)行受到權(quán)限保護(hù)的操作。
場景講解
例如,一個(gè)用戶Andy登錄銀行站點(diǎn)服務(wù)器準(zhǔn)備進(jìn)行轉(zhuǎn)賬操作。在Andy的用戶信息有效期內(nèi),Andy被誘導(dǎo)查看了一個(gè)黑客惡意網(wǎng)站。該網(wǎng)站獲取了Andy登錄后的瀏覽器與銀行網(wǎng)站之間尚未過期的Session信息。由于Andy瀏覽器的cookie中含有Andy銀行賬戶的認(rèn)證信息,黑客可以以Andy的合法身份偽裝訪問Andy的銀行賬戶,并進(jìn)行非法操作。
CSRF攻擊的防御策略
驗(yàn)證HTTP Referer字段:驗(yàn)證請(qǐng)求來源頁面的Referer字段,確保請(qǐng)求來自同一站點(diǎn),但該方法并不可靠,因?yàn)镽eferer字段可能被偽造或者被瀏覽器禁用。
在請(qǐng)求地址中添加Token并驗(yàn)證:在每個(gè)頁面中嵌入一個(gè)隨機(jī)生成的Token,并將其添加到請(qǐng)求地址的參數(shù)中,后端服務(wù)器在接收到請(qǐng)求時(shí)驗(yàn)證Token的有效性。
在HTTP頭中自定義屬性并驗(yàn)證:在每個(gè)請(qǐng)求中添加自定義的HTTP頭屬性,例如"X-Requested-With"或"X-CSRF-Token",后端服務(wù)器在接收到請(qǐng)求時(shí)驗(yàn)證該屬性的值。
以Spring Security安全框架中的CSRF防御功能來講解:
-
disable(): 關(guān)閉Spring Security默認(rèn)開啟的CSRF防御功能。 -
csrfTokenRepository(CsrfTokenRepository csrfTokenRepository): 指定要使用的CsrfTokenRepository(Token令牌持久化倉庫)。默認(rèn)是由LazyCsrfTokenRepository包裝的HttpSessionCsrfTokenRepository。 -
requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher): 指定針對(duì)什么類型的請(qǐng)求應(yīng)用CSRF防護(hù)功能。默認(rèn)設(shè)置是忽略GET、HEAD、TRACE和OPTIONS請(qǐng)求,而處理并防御其他所有請(qǐng)求。
- CSRF防護(hù)功能關(guān)閉的配置,但直接關(guān)閉CSRF防御的方式簡單粗暴,不太推薦使用,如果強(qiáng)行關(guān)閉后網(wǎng)站可能會(huì)面臨CSRF攻擊的危險(xiǎn),適合在開發(fā)過程中測試使用。
@Override
protected void configure(HttpSecurity http
) throws Exception {
http
.csrf()
.disable()
// ...其他配置
}
Spring Boot整合Spring Security進(jìn)行CSRF防御的示例
- 針對(duì)Form表單數(shù)據(jù)修改請(qǐng)求的CSRF Token配置:
在表單中添加攜帶CSRF Token信息的隱藏域:
<form method="post">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<!-- 其他表單字段 -->
<input type="submit" value="Submit" />
</form>
- 針對(duì)Ajax數(shù)據(jù)修改請(qǐng)求的CSRF Token配置:
在頁面的<head>標(biāo)簽中添加<meta>標(biāo)簽設(shè)置CSRF Token信息,并在具體的Ajax請(qǐng)求中獲取相應(yīng)的Token值,并將其添加到請(qǐng)求的HTTP header中進(jìn)行驗(yàn)證。
<head>
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
<!-- 其他頭信息 -->
</head>
<body>
<!-- 具體頁面內(nèi)容 -->
<script type="text/javascript">
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader($("meta[name='_csrf_header']").attr("content"), $("meta[name='_csrf']").attr("content"));
});
// 其他Ajax請(qǐng)求
</script>
</body>
希望通過以上的講解,能讓大家更深入的了解CSRF(跨站請(qǐng)求偽造)攻擊及防御策略。