使用AngularJS和Express的错误CSRF令牌

时间:2014-12-09 23:06:44

标签: angularjs cookies express csrf passport.js

我想在我的app中添加一个使用MEAN堆栈的CSRF保护。

我尝试了某人已经给出的答案:CSRF Protection in ExpressJS

但这是旧款快递版,所以我做了一些改动:

app.use(cookieParser(config.cookieSecret, { httpOnly: true }));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({ secret: config.sessionSecret, resave: false, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(csrf({value: function(req) {
        var token = (req.body && req.body._csrf)
            || (req.query && req.query._csrf)
            || (req.headers['x-csrf-token'])
            || (req.headers['x-xsrf-token']);
        return token;
    }
}));
app.use(function(req, res, next) {
  res.cookie('XSRF-TOKEN', req.csrfToken());
  next();
});

我可以看到名为XSRF-TOKEN的令牌在我的应用上生成(使用Chrome检查)。

但是当我发布一个表单(Angular frontend)时,我有一个关于令牌的错误:

{"message":"invalid csrf token","error":{"expose":true,"code":"EBADCSRFTOKEN","statusCode":403,"status":403}}

我错过了什么吗?我想知道req.csrfToken()是否会生成Angular给出的好令牌......

编辑:

我看到AngularJS在XSRF-TOKEN次请求中使用了$http。所以我想我必须在我的表单中添加一个隐藏的输入来发布csrf值,由Express检查,但是如何?

3 个答案:

答案 0 :(得分:12)

最后我能够发送好的令牌值。这是完整的答案。

AngularJS在使用$http服务发出请求期间使用CSRF保护(Angular称为XSRF)。

  

执行 XHR 请求时, $ http 服务会从中读取令牌   cookie(默认情况下为 XSRF-TOKEN )并将其设置为HTTP标头   (的 X-XSRF-TOKEN )。由于只有在您的域上运行的JavaScript才可以   读取cookie,您的服务器可以放心XHR来自   您的域上运行的JavaScript。标题不会设置为   跨域请求。

有很多帖子解释了如何使用 ExpressJS 3.xx 发送XSRF-TOKEN,但有些内容随 4.xx版本而变化。 Connect中间件不再包含在内。 Express使用自己的middelware:cookie-parserbody-parserexpress-sessioncsurf

1 - 发送XSRF-TOKEN cookie

第一步是将cookie从后端发送到前端(Express to Angular):

var express         = require('express');
var app             = express();
var cookieParser    = require('cookie-parser');
var bodyParser      = require('body-parser');
var session         = require('express-session');
var config          = require('./lib/config'); //config.js file with hard-coded options.
var csrf            = require('csurf');

app.use(cookieParser(config.cookieSecret, { httpOnly: true }));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({ 
    name: 'sessionID', 
    secret: config.sessionSecret, 
    cookie: {
        path: '/',
        httpOnly: true,
        secure: false,
        maxAge: 3600000
    },
    rolling: true, 
    resave: false, 
    saveUninitialized: true 
}));
app.use(csrf());
app.use(function(req, res, next) {
    res.cookie('XSRF-TOKEN', req.csrfToken());
    next();
});

现在,Angular能够在 $ http 请求期间设置其HTTP标头(X-XSRF-TOKEN)。示例:

<body ng-app="testApp">
    <div ng-controller="LoginCtrl">
        <form role="form" ng-submit="login()" >
           <input type="email" ng-model="user.email" />
           <input type="password" ng-model="user.password" />
           <input type="submit" value="Log In" />
        </form>
        <p style="color:red">{{loginMsg}}</p>
    </div>
</body>

<script>
    var app = angular.module('testApp', ['ngResource']);
    app.controller('LoginCtrl', function ($scope, $http) {
        $scope.user = {};
        $scope.loginMsg = '';
        $scope.login = function () {
             $http.post('/login', $scope.user).success(function () {
                  $window.location.href='/profile';
             }).error(function () {
                  $scope.loginMsg = 'Wrong credentials, try again.';
             });
        };
    });
</script>

2 - 以非Angular形式添加_csrf输入

这是我的问题,我不知道如何添加此输入。最后,我创建了一个名为$csrf的新Angular服务:

    app.factory('$csrf', function () {
        var cookies = document.cookie.split('; ');
        for (var i=0; i<cookies.length; i++) {
          var cookie = cookies[i].split('=');
          if(cookie[0].indexOf('XSRF-TOKEN') > -1) {
            return cookie[1];
          }
        }
        return 'none';
    });

我在Plunker上做了一个例子:http://plnkr.co/edit/G8oD0dDJQmjWaa6D0x3u

希望我的回答能有所帮助。

答案 1 :(得分:1)

如果有人收到“csurf配置错误”,请尝试:

app.use( csrf( { cookie: true } ));

答案 2 :(得分:0)

我创建了可以直接使用的存储库。

节点

https://github.com/nil4you/node-csrf-and-http-only-cookie-with-spa

角度

https://github.com/nil4you/angular-csrf-and-httponly-cookie-demo

在此处提出任何评论,因为我看不到太多的编码问题,而全都是关于正确的设置问题。