上一篇我們說(shuō)了用腳本注入去公雞小熊哥的博文評(píng)論莱找。普通的腳本注入很容易就被前端后臺(tái)全方位的腳本過(guò)濾給處理掉酬姆,完全沒(méi)有殺傷力。一般來(lái)說(shuō)遇到<, > , =" 等等可能加載執(zhí)行腳本的用戶輸入宋距,轉(zhuǎn)換為< ; & gt ; 等等即可作為數(shù)據(jù)打印到 DOM 中轴踱,而不是作為腳本執(zhí)行。詳細(xì)情況參考上一篇文章 谚赎。我敢保證淫僻,@Swanky 肯定是受了我的蠱惑去 POST 了 三萬(wàn)多條評(píng)論導(dǎo)致被 @簡(jiǎn)書首席封號(hào)官 封號(hào)了。
偽造請(qǐng)求的過(guò)程
這次來(lái)說(shuō)說(shuō)偽造公雞(Cross Site Request Forgery)的事情壶唤。通俗點(diǎn)講就是 有人給你發(fā)送了一個(gè)鏈接雳灵,然后你手賤點(diǎn)開,是看起來(lái)很正常的網(wǎng)頁(yè)(A.com/index.html)闸盔,結(jié)果暗中被發(fā)送了一個(gè)指向 招商銀行轉(zhuǎn)賬服務(wù)(B.com/transfer) 的POST請(qǐng)求悯辙,這個(gè)請(qǐng)求是攻擊者在A.com/index.html 腳本中偽造的,因此請(qǐng)求的發(fā)送方屬于A.com域迎吵,而不屬于B.com/transfer 的域躲撰, 所以叫做 跨站偽造請(qǐng)求
// attack.html. 為了在這個(gè)偽造的網(wǎng)頁(yè)中自動(dòng)發(fā)送請(qǐng)求并且?guī)?受害用戶的cookie,
// 一般都會(huì)在hidden iframe中加載一份正規(guī)網(wǎng)站的頁(yè)面击费,而且攻擊表單也是隱藏的拢蛋。
// 表面上這個(gè)偽造網(wǎng)頁(yè)是很正規(guī)的,并無(wú)異常蔫巩。
<form id="thisForm" method="POST" target="_blank" action="http://www.bank.com/transfer">
<input type="text" name="name" value="csrf_Attack2!!!">
</form>
<iframe name="tab" src="http://www.bank.com" style="display:none;">
</iframe>
XSRF 原理
XSRF的關(guān)鍵就是 假如正規(guī)網(wǎng)站(B.com)的服務(wù)器端沒(méi)有防御機(jī)制谆棱,只是對(duì)于發(fā)來(lái)的請(qǐng)求做用戶身份驗(yàn)證,那么偽造請(qǐng)求就可以借用受害者瀏覽器自動(dòng)發(fā)送的cookie蒙混過(guò)關(guān)圆仔,實(shí)行惡意攻擊垃瞧。其中有幾個(gè)問(wèn)題需要明確:
- 用戶身份信息一般通過(guò)Http Request 的頭部cookie 字段的值來(lái)傳遞,cookie中往往包含sessionid 這樣的用戶會(huì)話信息坪郭,服務(wù)器通過(guò)比對(duì)服務(wù)端內(nèi)存或數(shù)據(jù)庫(kù)(Redis等)中維持的session就可以知道是哪個(gè)用戶在發(fā)請(qǐng)求个从,Session有無(wú)過(guò)期。 這一過(guò)程一般不驗(yàn)證請(qǐng)求發(fā)送方的 域歪沃。
- 跨站偽造請(qǐng)求成功的前提是 B.com 提供了可供跨域調(diào)用的服務(wù)信姓。因?yàn)槲覀冎来蟛糠譃g覽器和服務(wù)器都禁止腳本請(qǐng)求跨域資源,這種行為一般不太安全绸罗。但是我非得請(qǐng)求呢意推?? 所以除了用JSONP 來(lái)GET跨域資源珊蟀,更有采用CORS(Cross-origin resource sharing菊值,跨域資源共享是W3C標(biāo)準(zhǔn))來(lái)實(shí)現(xiàn)POST外驱,PUT請(qǐng)求跨域的。 CORS的詳細(xì)介紹可以參考這里.
通常情況下腻窒,假如服務(wù)器端開啟CORS配置允許任何來(lái)源的請(qǐng)求昵宇,就很難分辨接收到的請(qǐng)求是用戶自主發(fā)送的(往往是和B.com同一個(gè)域下的網(wǎng)頁(yè)),還是攻擊者冒充用戶身份偽造的攻擊請(qǐng)求(往往不同域儿子,例如A.com)瓦哎。
XSRF防御——Token
經(jīng)過(guò)上面的介紹,其實(shí)防御的辦法大概都可以推斷出來(lái)了柔逼。關(guān)鍵就是區(qū)分來(lái)自于各種域的請(qǐng)求蒋譬,哪些是合法用戶發(fā)送的,哪些是被借用了身份發(fā)送來(lái)的愉适。
- 配置服務(wù)器的CORS犯助,只允許白名單的域發(fā)來(lái)請(qǐng)求,這樣最直接维咸。只要白名單的網(wǎng)站不被攻擊注入惡意腳本就基本安全了剂买。以nodejs和express為例,配置如下:
app.all('*', function(req, res, next) {
// 如果用"*", 表示接受任何域發(fā)來(lái)的請(qǐng)求, 這里只配置一個(gè)域名
res.header("Access-Control-Allow-Origin", "www.icbc.com");
res.header("Access-Control-Allow-Headers", "X-Requested-With, accept, origin, content-type");
res.header("Access-Control-Allow-Methods", "PUT,POST,OPTIONS");
next();
}
2.bank.com 的服務(wù)器端和客戶端通力合作癌蓖,協(xié)商一個(gè)除了Session之外的二次身份驗(yàn)證——Token瞬哼。
Token驗(yàn)證的原理是:每次用戶登陸成功,就根據(jù)SessionID和特定算法生成一個(gè)Token租副,發(fā)回客戶端(動(dòng)態(tài)添加到一個(gè)隱藏域中坐慰,例如<input> 或者JS變量中),合法客戶端在隨后的請(qǐng)求中加入Token作為數(shù)據(jù)體附井,服務(wù)器端每次接受請(qǐng)求都要去驗(yàn)證SessionID 和 Token,雙保險(xiǎn)两残。以nodejs為例永毅,一休哥自制服務(wù)端關(guān)鍵代碼:
// 當(dāng)用戶登錄驗(yàn)證成功時(shí),隨即生成與該用戶Session綁定的Token
req.session.key = (Math.random()* Math.pow(10, 17));
var crsfToken = generateToken(parseInt(req.session.key).toString());
// 返回token給客戶端人弓,客戶端將token動(dòng)態(tài)添加至DOM或者變量中
res.send({"status": returnData, "refreshpage": redirectpage, "token": crsfToken});
// return Hex string as token.
// 加密算法遠(yuǎn)比這個(gè)復(fù)雜沼死。這里只是演示,這樣也很難猜出token
function generateToken(sess) {
var tk = "", a = 0.834415, b = 1.214414, c = 1.83121;
for(var i=0; i < sess.length; i++){
var baseNum = parseInt(sess[i]);
tk += (a * Math.pow(baseNum, b) + c).toFixed(0);
}
var tkNum = parseInt(tk);
return tkNum.toString(16);
}
// 當(dāng)收到請(qǐng)求后崔赌,除了驗(yàn)證session意蛀,再根據(jù)session計(jì)算一次token,比對(duì)客戶端發(fā)來(lái)的是否一致健芭。
// check Token to prevent XSRF...
function checkToken(session, params) {
var validToken = generateToken(session.name);
if (params.token && params.token == validToken) {
return true;
} else {
console.error("CSRF Token not valid! Attack Found !!");
return false;
}
}
再補(bǔ)充一點(diǎn)县钥,因?yàn)槊俺渖矸莸恼?qǐng)求一般都是趁受害者處于登錄狀態(tài)了,所以DOM中沒(méi)有Token慈迈,而經(jīng)過(guò)合法登錄后才會(huì)有Token存在若贮。這樣就較好地防御了跨站偽造請(qǐng)求攻擊。
寫在最后
現(xiàn)如今,網(wǎng)絡(luò)安全形勢(shì)越來(lái)越嚴(yán)峻谴麦,作為一個(gè)Web前端工程師蠢沿,之前很少注意這一點(diǎn)。至此已經(jīng)更新了兩篇 跟前端工程師相關(guān)的網(wǎng)絡(luò)安全 筆記了匾效。希望大家喜歡本文舷蟀,有所收獲。
傳送門:注意安全第一篇 XSS 跨站腳本注入
另外一篇很棒的英文參考 CSRF Attacks, XSRF or Sea-Surf – What They Are and How to Defend Against Them