I am trying to use Dropbox's API, and I got it to successfully send me alerts via webhooks, but now I want to verify the signatures every time they send me an alert.
From dropbox's documentation, they write:
"Every notification request will include a header called X-Dropbox-Signature that includes an HMAC-SHA256 signature of the request body, using your app secret as the signing key. This lets your app verify that the notification really came from Dropbox."
So I successfully catch that signature, and I use NodeJS built in crypto module to try to create my own signature with HMAC SHA256 and then compare my signature against the signature Dropbox sends me.
Here is my code for doing so:
var sign = req.get("X-Dropbox-Signature");
console.log(sign);
var hmac = crypto.createHmac(algorithm, secret);
hmac.update(JSON.stringify(req.body));
hash = hmac.digest('hex');
console.log(hash);
Where algorithm is just 'sha256' and secret is my secret key that I got from my dropbox apps page. I have to use JSON.stringify(req.body) because req.body is an object and hmac.update takes a string. I am wondering if that is where my error comes from?
I console log the sign which is the signature from dropbox, and then I console log the signature which I created using hmac, but it is a different signature.
Any suggestions to what I may be doing wrong?
Greg is right. You need to use the raw body request to check the ingredients of the message. The following code employs the body-parser library to extract the raw body.
var bodyParser = require("body-parser");
app.use(bodyParser.json({verify:function(req,res,buf){req.rawBody=buf}}))
Then for the post method:
app.post('/webhooks', function(req, res) {
const retrievedSignature = req.get("X-header-Integrity")
//send this body string for validation with secret
const bodyString = Buffer.from(req.rawBody, 'utf8')
let check = integrityCheck(retrievedSignature, bodyString, "secret")
});
The following snippet is a basic example for calculating an HMAC of a request body using Node's native HTTP server. The same concepts can be very easily (and more cleanly) applied in an Express middleware.
const http = require('http');
const crypto = require('crypto');
const APP_SECRET = 'prozr59vkis4454';
const REQUEST_BODY = '{"list_folder": {"accounts": ["dbid:AABL4QRrY7tB9viLgPUqmjkzE6Fe5ujlnlE"]}, "delta": {"users": [22575230]}}';
const SIGNATURE = 'aa2508fb90b757aa382edb0815c7f7df0ce1943c53f28fae96e1dc9eb7f677b1';
const server = http
.createServer((req, res) => {
const hmac = crypto.createHmac('sha256', APP_SECRET).setEncoding('hex');
req
.pipe(hmac)
.on('finish', () => {
console.log('signature from header:', req.headers['x-dropbox-signature']);
console.log('calculated signature: ', hmac.read());
res.writeHead(204);
res.end();
});
})
.listen(1313, () => {
const request = http.request({
host: 'localhost',
port: 1313,
method: 'POST',
}, () => {
server.close();
});
request.setHeader('x-dropbox-signature', SIGNATURE);
request.write(REQUEST_BODY);
request.end();
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With