坏CSRF令牌AngularJS和Ex preSS令牌、CSRF、AngularJS、preSS

2023-09-13 02:40:27 作者:玖初.

我想补充我的应用程序,它使用的平均堆栈CSRF保护。

I would like to add a CSRF protection in my app which uses a MEAN stack.

我已经试过有人给出了答案:CSRF保护防爆pressJS

I tried the answer already given by someone : CSRF Protection in ExpressJS

但它是对于上了年纪的前preSS版本,所以我做了一些改变:

But it was for the older express version, so I made some changes :

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检查)我的应用程序很好生成的。

I can see the token named XSRF-TOKEN is well generated on my app (using Chrome inspection).

但是,当我张贴的形式(角前端),我对标记的错误:

But when I post a form (Angular frontend), I have an error about the token :

{消息:无效的CSRF令牌,错误:{揭露:真实的,code:EBADCSRFTOKEN,状态code: 403,状态:403}}

我错过了什么?我想知道如果 req.csrfToken()产生由角给出良好的令牌...

Did I miss something ? I'm wondering if req.csrfToken() generates the good token given by Angular...

编辑:

我只看到 XSRF-TOKEN $ HTTP 使用AngularJS请求的仅。所以我觉得我必须在我的窗体中添加一个隐藏的输入后与CSRF值,由前preSS进行检查,但如何?

I just see the XSRF-TOKEN is used by AngularJS in $http requests only. So I think I have to add a hidden input in my form to post with csrf value, to be checked by Express, but how ?

推荐答案

最后,我能够给我良好的令牌值。下面是完整的答案。

Finally I was able to send the good token value. Here's the complete answer.

AngularJS 使用带有 $ HTTP 服务。

在执行 XHR 的要求,在 $ HTTP 服务读取从令牌  饼干(默认情况下, XSRF-TOKEN ),并将它作为一个HTTP头  ( X-XSRF-TOKEN )。因为只有在您的域中运行的JavaScript可以  读取cookie,您的服务器可以放心,从XHR来  在域上运行的JavaScript。头将不会对被设置  跨域请求。

When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript that runs on your domain could read the cookie, your server can be assured that the XHR came from JavaScript running on your domain. The header will not be set for cross-domain requests.

有这解释了如何发送XSRF-TOKEN是防爆pressJS的3.xx 很多帖子,但有些东西是的4.xx版本更改。 连接中间件都不再包括在内。 防爆preSS 使用其自己的middelware:的 cookie的解析器,身体解析器,的前preSS-会议和的 csurf 。

There are many posts which explained how to send XSRF-TOKEN with ExpressJS 3.xx, but some things change with 4.xx version. Connect middlewares are not included anymore. Express uses its own middelware : cookie-parser, body-parser, express-session, and csurf.

第一步是送饼干,从后端到前端(前preSS到角):

The first step is to send the cookie, from the backend to the frontend (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();
});

现在是角能够在 $ HTTP 的要求来设置它的HTTP标头(X-XSRF令牌)。例如:

Now Angular is able to set its HTTP header (X-XSRF-TOKEN) during $http requests. Example :

<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 - 添加_csrf输入无棱角的形式

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

    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

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

Hope my answer will help.