跨站请求伪造 CSRF
Cross-site request forgery,跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。这种信任是由于请求成功发送了浏览器Cookie。
Cookie
浏览器Cookie分Third-party Cookie
和 Session Cookie
。
Third-party Cookie
Third-party Cookie
是服务器Set-Cookie
时指定Expire
时间,只有到Expire
时间到后Cookie
才会生效,所以这种Cookie会保存在本地;
Session Cookie
Session Cookie
没有指定Expire
时间,当浏览器关闭后,Session Cookie
就会失效。
下面以express-session
为例。
没有设置Expire
app.use(session({
secret: 'keyboard cat'
}));
登录成功后浏览器Cookie
值
关闭浏览器后重新打开页面
发现Cookie
值已经改变,之前设置的Cookie
值已失效。
设置Expire
app.use(session({
secret: 'keyboard cat',
cookie: {
expires: 60000 // 1分钟
}
}));
登录后的 Cookie
值。
关闭浏览器重新打开后
Cookie
保持不变,保持登录状态。
CSRF 攻击
CSRF 利用网站对用户网页浏览器的信任(Cookie),会恶意删除重要数据。
例如:一个购物系统,正常登陆的用户提供删除购物车接口/deleteShoppingCart
。
// session状态拦截
app.use(function (req, res, next) {
if (req.session.userAccount) {
// 已登陆状态
next();
} else {
// 未登录
let isLogin = req.url.search(/login/i) >=0 ? true : false;
if(isLogin){
next(); // 如果是登陆接口请求,可以进入系统
}else{
res.redirect("/loginPage"); // 跳转登陆页面
}
}
});
用户在登陆状态下是可以执行/deleteShoppingCart
现在有一恶意攻击页面evil.html,里面的img src指向/deleteShoppingCart
接口。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<img src="http://192.168.31.235:3000/deleteShoppingCart">
</body>
</html>
后台记录当前浏览器的用户已经登陆,即浏览器发起的请求后台都认为是合法的。用户不小心打开恶意攻击页面,页面会请求http://192.168.31.235:3000/deleteShoppingCart
, 删除购物车接口会执行。
以上攻击是攻击者利用网站对浏览器的信任,在用户不知情的情况下,伪造恶意请求。
CSRF 防御
验证码
验证码被认为是对抗CSRF攻击最简洁有效的防御方法.
CSRF攻击往往是在用户不知情的情况下造成的网络请求,如上述例子,添加验证码验证能很好地遏制CSRF攻击。
验证码的缺点就是网站不能所有操作(请求)都加上验证码,它是防御CSRF攻击的辅助手段。
Referer check
web服务端检测请求头 referer
是否来自合法的“源”,如果是合法请求源,允许请求。
比如从http://192.168.31.235:3000/ 页面发起的请求。
// req.headers.referer
referer: 'http://192.168.31.235:3000/'
缺点就是不是所有浏览器请求头都会发送Referer。
CSRF Token
防止CSRF攻击的另一种方法是在服务端生成Token,放在Html节点(表单、标签属性等)、Javascript全局变量或者http响应时写在Cookie + Ajax请求。