【问题标题】:How to protect a http post from Angular 2 to Express Server如何保护从 Angular 2 到 Express Server 的 http 帖子
【发布时间】:2017-04-04 06:17:53
【问题描述】:

如何保护从 angular2 应用程序到 Express 服务器的 post 调用?

在我的 angular2 应用程序中,我有以下 HTTP 帖子。

 const headers = new Headers();
    headers.append('Content-Type', 'application/json');

    const data = {
      email: this.form.value.email
    };

    this.http.post('http://localhost:8080/api/user/email', data, {
      headers: headers
    })

现在我想确保只有我的 angular 2 应用程序可以对用户 api 进行 post 调用。我结合 Express 和 Angular 2 对 csrf 进行了一些研究。在我的 Angular 2 应用程序中,我对 app.module.ts 文件进行了以下实现。

import { HttpModule, XSRFStrategy, CookieXSRFStrategy } from '@angular/http';

providers: [  {
            provide: XSRFStrategy,
            useValue: new CookieXSRFStrategy('csrftoken', 'X-CSRFToken')
        } ]

我认为这是将 XSRFStrategy 实施到 Angular 2 的正确方法?

对于 Express 中的实现,我遵循了一些教程,但没有任何成功。我收到的大部分时间:

ForbiddenError: invalid csrf token

如何在我的 Express api 中实现 CSRF 部分。这是我的 Express 配置:

// call the packages we need
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');

app.use(bodyParser.urlencoded({
  extended: false
}));
app.use(bodyParser.json());

var port = process.env.PORT || 8080; // set our port

// ROUTES FOR OUR API
// =============================================================================
var router = express.Router();
router.use(function (req, res, next) {
  console.log('Something is happening.');
  res.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
  res.setHeader("Access-Control-Allow-Credentials", "true");
  res.setHeader("Access-Control-Allow-Methods", "POST");
  res.setHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
  res.setHeader('Content-Type', 'application/json');
  next();
});

app.use('/api', router);

router.post('/user/email', function (req, res) {
 ..... [how to make sure that this post can only be fired from my angular 2 application ]
}

更新 #1

做了更多研究,在 Angular 2 文档中发现了以下内容:

//By default, Angular will look for a cookie called `'XSRF-TOKEN'`, and set
//* an HTTP request header called `'X-XSRF-TOKEN'` with the value of the cookie on each request,

所以在我的 Express 应用程序中,我添加了以下部分:

const cookieOptions = {
  key: 'XSRF-TOKEN',
  secure: false,
  httpOnly: false,
  maxAge: 3600000
}

var csrfProtection = csrf({
  cookie: cookieOptions
})

在发布路线中,我实施了如下保护:

    router.post('/user/email', csrfProtection, function (req, res) {
      console.log('post incomming');
}):

我收到了以下响应标头

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers
Access-Control-Allow-Methods:POST
Access-Control-Allow-Origin:http://localhost:4200
Connection:keep-alive
Content-Length:1167
Content-Type:text/html; charset=utf-8
Date:Mon, 21 Nov 2016 20:07:12 GMT
set-cookie:XSRF-TOKEN=O4JKkjAZRik2H7ml0DoxDc8s; Max-Age=3600000; Path=/
X-Content-Type-Options:nosniff
X-Powered-By:Express

以及请求头:

Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8,nl;q=0.6
Connection:keep-alive
Content-Length:38
content-type:application/json
Host:localhost:8080
Origin:http://localhost:4200
Referer:http://localhost:4200/profile/users

【问题讨论】:

  • 你能从express server端的浏览器中找到一个名字类似于csrf的cookie吗?
  • 你好祖拜尔。我用收到的回复更新了我的问题。

标签: javascript security express angular csrf


【解决方案1】:

如何使用 Angular2 和 Express 实现 CSRF 保护

默认情况下,Angular 会寻找一个名为 'XSRF-TOKEN' 的 cookie,并设置 一个名为 'X-XSRF-TOKEN' 的 HTTP 请求标头,其中包含每个请求的 cookie 值。

为了确保我们的后端可以设置 XSRF-TOKEN cookie,我们必须将调用代理到在端口 8080 上运行的 api。我们可以使用 proxy.config.json 文件来做到这一点。

{ 
  "/api/*" : {
    "target": "http://localhost:8080",
    "secure": false,
    "logLevel": "debug" 
  }
}

在我们的 package.json 文件中,我们修改 scripts/start 函数以使用我们的 proxy.config.json 文件:

"scripts": {
    "start": "ng serve --proxy-config proxy.config.json",
}

现在每次我们运行 npm start 时,我们对 /api 的调用都会被代理到 localhost:8080。现在我们准备好对我们的 api 服务器进行 post 调用了。

在我们的组件中,我们进行了一个 http post 调用,并将标头设置为使用 content-type application/json。

ourfunction() {
  const headers = new Headers();
  headers.append('Content-Type', 'application/json');
  data = { key:value }

  this.http.post('/api/user/email', data, {
      headers: headers
  }).subscribe( (resp: any) => console.log('resp', resp));

}

这就是我们在 Angular2 方面需要做的一切。现在我们正在实现 Express 端。

var express = require('express'); 
var app = express();
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var cors = require('cors')

我们初始化我们的应用程序并定义一些中间件以在我们的应用程序中使用。

const cookieOptions = {
  key: 'XSRF-TOKEN',
  secure: false,
  httpOnly: false,
  maxAge: 3600
}

const corsOptions = {
  origin: 'http://localhost:4200',
  optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204 
};

这里我们设置用于 csrf 和 cors 中间件的选项。

const port = process.env.PORT || 8080; // set our port
const csrfProtection = csrf({ cookie: cookieOptions })
const router = express.Router();

实施中间件。顺序对于获得正确的结果非常重要。

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use('/api', router);
app.use(cors(corsOptions));
app.use(cookieParser());
app.use(csrfProtection);

router.use(function (req, res, next) {
  res.setHeader('Content-Type', 'application/json');
  next();
});

这就是我们在 Express 方面需要做的所有事情。现在我们可以使用 CSRF 令牌保护我们的 post 调用。

完成快递服务器文件

var express = require('express'); 
var app = express();
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var cors = require('cors')

const cookieOptions = {
  key: 'XSRF-TOKEN',
  secure: false,
  httpOnly: false,
  maxAge: 3600
}

const corsOptions = {
  origin: 'http://localhost:4200',
  optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204 
};

const port = process.env.PORT || 8080; // set our port
const csrfProtection = csrf({ cookie: cookieOptions })
const router = express.Router();


app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use('/api', router);
app.use(cors(corsOptions));
app.use(cookieParser());
app.use(csrfProtection);

router.use(function (req, res, next) {
  res.setHeader('Content-Type', 'application/json');
  next();
});

router.post('/user/email', function (req, res) {
  console.log('post incomming');
  console.log('req', req.body);
  res.send('testing..');
});

app.listen(port);
console.log('Magic happens on port ' + port);

【讨论】:

    猜你喜欢
    • 2015-04-13
    • 2016-04-24
    • 2017-03-10
    • 2018-01-25
    • 2017-11-30
    • 2016-07-09
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    相关资源
    最近更新 更多