admin管理员组

文章数量:1323729

This is a classic tale of "if it ain't broke, don't fix it"

I had created a relatively simple HTTP request handler using Node.js. I am authenticating the request by matching the SHA-1 of the request body to a signature that es as a request header:

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);

This worked fine, except everything is ugly and there were other features of Express.js I wanted to implement anyways. I rewrote the code as follows:

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);

Of course, the crypto method wouldn't run because req.body is now neither a string or a Buffer. But how do I fix this?

I included some middleware:

app.use(bodyParser.json());

Then used JSON.stringify to convert the result in to a string. This allows the crypto method to run, however, the hash and the signature did not match!

Is it possible that Express is doing something else to the request body when using middleware like body-parser? This doesn't make any sense to me, but perhaps I am missing something.

This is a classic tale of "if it ain't broke, don't fix it"

I had created a relatively simple HTTP request handler using Node.js. I am authenticating the request by matching the SHA-1 of the request body to a signature that es as a request header:

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);

This worked fine, except everything is ugly and there were other features of Express.js I wanted to implement anyways. I rewrote the code as follows:

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);

Of course, the crypto method wouldn't run because req.body is now neither a string or a Buffer. But how do I fix this?

I included some middleware:

app.use(bodyParser.json());

Then used JSON.stringify to convert the result in to a string. This allows the crypto method to run, however, the hash and the signature did not match!

Is it possible that Express is doing something else to the request body when using middleware like body-parser? This doesn't make any sense to me, but perhaps I am missing something.

Share Improve this question edited Dec 5, 2018 at 22:46 KyleFarris 17.6k5 gold badges42 silver badges41 bronze badges asked Jul 9, 2015 at 22:59 djfdevdjfdev 6,0374 gold badges22 silver badges39 bronze badges 1
  • This is a classic tale of "if it ain't broke, don't fix it" If only we'd all learned our lessons by now. But I suspect that I never will. – Codebling Commented Sep 16, 2020 at 15:14
Add a ment  | 

3 Answers 3

Reset to default 3

With body parser

var options = {
  inflate: true,
  limit: '100kb',
  type: 'application/octet-stream'
};

app.use(bodyParser.raw(options));

Then you can use

app.post(routeName, (req, res) => {
  let body = '';
  req.on('data', (data) => {
    body += data;
    console.log(data)
  });
  req.on('end', () => {
    fs.appendFile(`./${fileName}.log`, '\n' + body, (err) => {
      if (err) throw err;
    });
  });
  res.end();
})

Found a solution. I just created a custom body parser.

function(req, res, next) {
    req.setEncoding('utf8');
    req.rawBody = '';
    req.on('data', function(chunk) {
        req.rawBody += chunk;
    });
    req.on('end', function(){
        next();
    });
}

I still don't understand why bodyParser.text() doesn't work the same way!

what are you sending in the body of the POST request?

I have signed this string: nodejs with your algorithm and the result was: 92FCFCFBCDB06B40F76FEE4E6271EFC2554290FD

Then I consume the server with curl:

curl --header "x-signature: 92FCFCFBCDB06B40F76FEE4E6271EFC2554290FD" --data "something=nodejs" http://localhost:4040

This is my server file:

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');
});

If the signature is not valid, you will see a message that says: you do not have permission but if you send a valid signature you will be able to consume the POST route /.

本文标签: javascriptNodejs HTTP streaming request vs Expressjs request objectStack Overflow