Node.js HTTP 流请求与 Express.js 请求对象

djf*_*dev 5 javascript sha1 node.js express

这是一个“如果它没有坏,就不要修理它”的经典故事

我使用 Node.js 创建了一个相对简单的 HTTP 请求处理程序。我通过将请求正文的 SHA-1 与作为请求标头的签名进行匹配来验证请求:

var http = require('http');
var crypto = require('crypto');
var secret = process.env.MY_SECRET;

var requestListener = function(req, res) {
    if (req.method === 'POST') {
        var body = '';
        req.on('data', function(data) {
            body += data;
        });
        req.on('end', function() {
            var signature = req.headers['x-signature'];
            var hash = crypto.createHmac('sha1', secret)
                .update(body)
                .digest('hex')
                .toUpperCase();
            if (signature === hash) {
                // request is authorized
            }
        });
    }
};

var server = http.createServer(requestListener);
server.listen(3000);
Run Code Online (Sandbox Code Playgroud)

这工作得很好,除了一切都很丑陋,而且我还是想实现 Express.js 的其他功能。我重写了代码如下:

var crypto = require('crypto');
var express = require('express');
var app = express();
var secret = process.env.MY_SECRET;

app.use(function(req, res, next) {
    var signature = req.get('x-signature');

    var hash = crypto.createHmac('sha1', secret)
        .update(req.body)
        .digest('hex')
        .toUpperCase();

    if (signature === hash) {
        next();
    } else {
        // unauthorized
    }    
});

app.post('/', function(req, res) {
    // request is authorized
});

app.listen(3000);
Run Code Online (Sandbox Code Playgroud)

当然,加密方法不会运行,因为req.body现在既不是字符串也不是缓冲区。但我该如何解决这个问题呢?

我包含了一些中间件:

app.use(bodyParser.json());
Run Code Online (Sandbox Code Playgroud)

然后用于JSON.stringify将结果转换为字符串。这允许加密方法运行,但是,哈希和签名不匹配!

当使用像 body-parser 这样的中间件时,Express 是否有可能对请求正文做其他事情?这对我来说没有任何意义,但也许我错过了一些东西。

Wil*_*son 0

您在 POST 请求正文中发送什么?

我已经nodejs用你的算法签署了这个字符串:结果是:92FCFCFBCDB06B40F76FEE4E6271EFC2554290FD

然后我用curl 使用服务器:

curl --header "x-signature: 92FCFCFBCDB06B40F76FEE4E6271EFC2554290FD" --data "something=nodejs" http://localhost:4040
Run Code Online (Sandbox Code Playgroud)

这是我的服务器文件:

var express = require('express');
var app = express();

var bodyParser = require('body-parser');

var secret = 'something';
var crypto = require('crypto');

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

app.use(function(req, res, next) {
  var signature = req.get('x-signature');
  var hash = crypto
    .createHmac('sha1', secret)
    .update(req.body.something)
    .digest('hex')
    .toUpperCase();

  if (signature === hash) {
    next();
  } else {
    res.send('you do not have permission');
  }
});

app.post('/', function(req, res) {
  res.send('hey');
});

app.listen(4040, function() {
  console.log('server up and running at 4040 port');
});
Run Code Online (Sandbox Code Playgroud)

如果签名无效,您将看到一条消息:you do not have permission但如果您发送有效签名,您将能够使用 POST 路由/