CSRF跨域访问攻击是什么呢?
一个网页通常会通过POST/PUT/DELETE请求更改对应用户账户的信息。但是浏览器并不会限制其它网站对你网站的访问。如果在其它网站中有一个链接叫“抽奖”,用户点了,该链接正是调用你网站的支付接口,那么用户就会莫名奇妙的损失了钱财。
CSRF的解决方案是什么呢?
关键是保证后端只能接受自己的前端放送过来的POST/PUT/DELET这些增删改的接口。为什么不屏蔽GET呢。嘿嘿,当然我们需要通过别的网站的链接也能访问到自己的网站啦。屏蔽了外网站的GET也就屏蔽了网站外链接,那么用户也没发通过搜索或者导航网站网站了呀,得不偿失。
如果保证呢后端只接受本网站前端发出的请求呢?
其中一个有效的策略就是由后端生成一个随即字符串,保存在session,我们根据用途给这个随即字符串起个名字叫csrf_token。并在用户第一个访问网页的时候,保存在HTML/JS中,以后前端发送POST/PUT/DELETE的时候,都要加上csrf_token,否则后端接口会拒绝响应,抛出异常。
上代码
后端NodeJS中生成csrf_token随即字符串:
- 1.后端NodeJS安装csurf包和ejs包
npm install csurf --save
npm install ejs --save
- 2.后端NodeJS中使用csurf生成csrf_token, 使用ejs在index.html注入token
在NodeJS的入口文件中加入下面的代码
var csrf = require('csurf');
//指定ejs模版文件的名字仍然为.html
//请求过来,仍然默认返回index.html,nodejs可以往index.html写变量拉
app.engine('.html', require('ejs').__express);
app.set('views', path.resolve(publicDir));
app.set('view engine', 'html');
var csrfProtection = csrf({ cookie: true });
app.get(appPath, csrfProtection, function (req, res){
// 把生成的csrfToken写入到index.html中去
res.render('index', { csrfToken: req.csrfToken() })
});
index.html
<!doctype html>
<html class="bootstrap3 legacyfalse chrometwo">
<head>
<meta content="<%= csrfToken %>" name="csrf-token">
...
- 3.前端发送POST中加入csrf_token
在前端中取出csrf_token的值,我是在angular中,利用jQuery取值
$scope.csrfToken = $('meta[name=csrf-token]').attr('content');
在表单请求中加入csrf_token
<form method="post" action="/changevalue" class="ng-pristine ng-valid">
<input value="value" name="input1">
<input value="value2" name="input2">
<input type="hidden" value="{{ csrfToken }}" name="_csrf">
<button type="submit">submit</button>
</form>
- 4.在后端NodeJS接口中验证csrf_token
app.post("changevalue" , parseForm, csrfProtection, function (req, res) {
res.send("response");
});
完毕!