Verifying in Node.js
This guide demonstrates verifying HTTP message signatures in Node.js using the native crypto
library.
Verifier
In Node.js, you can create a verifier callback function using the native crypto
library. The following example shows how to create a verifyHmac
callback function that can be used with the verify()
function to verify HTTP message signatures.
import crypto from 'crypto';
import getAccount from './accounts';
export async function verifyHmac(data, signature, params) {
const account = await getAccount(params.keyid);
const hmac = crypto.createHmac('sha256', account.secretKey);
hmac.update(data);
if (signature !== hmac.digest()) {
throw new Error("Invalid signature");
}
return account
}
Now you have a verifyHmac
callback that can be used with the verify()
function to verify HTTP message signatures.
Consider using crypto.timingSafeEqual()
to compare signatures, if you’re worried about timing attacks.
Verifying a message
To verify a request or response in Node.js, use the verify()
function with the verifyHmac
callback.
import { verify } from '@ltonetwork/http-message-signatures';
import { verifyMac } from './verify-mac';
const request = {
method: 'POST',
url: 'https://example.com/api/data',
headers: {
'Content-Type': 'application/json',
'Digest': 'SHA-256=sGb8nTkaRMkAaN1MwoyfztzCOkUo8rwSlzSFNt6aA74=',
'Signature': 'sig1="base64signature"',
'Signature-Input': 'sig1=("@method" "@path" "@authority" "content-type" "digest");created=1618884475;keyid="test-key";alg="hmac-sha256"'
}
};
(async () => {
try {
const account = await verify(request, verifyHmac);
// ... Process the verified request
} catch (err)
// ... Handle the failed verification
}
})();
Express
If you’re using Express or NestJS, you can pass the Express request object to the verify()
method.
This example shows how to create a NestJS middleware class verifying an Express request.
import { Injectable, NestMiddleware, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { verify } from '@ltonetwork/http-message-signatures';
import { verifyMac } from './verify-mac';
@Injectable()
export class VerifySignatureMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
try {
request['signer'] = await verify(request, verifyHmac);
} catch (err) {
throw new HttpException(err.message, HttpStatus.FORBIDDEN);
}
next();
}
}
Verifying the Digest
When the Digest
or Content-Digest
header is present in an HTTP message, it’s crucial to verify it to ensure the integrity of the message body. The following example shows how to verify the Digest
header in Node.js using the crypto
library.
- Calculate the hash of the received message body using the same hashing algorithm as in the
Digest
header. - Encode the hash in Base64 format.
- Compare the calculated hash with the hash in the
Digest
header.
import crypto from 'crypto';
const receivedBody = '{"hello":"world"}';
const receivedDigestHeader = 'SHA-256=sGb8nTkaRMkAaN1MwoyfztzCOkUo8rwSlzSFNt6aA74=';
const [algorithm, receivedDigest] = digestHeader.split('=');
if (algorithm !== 'SHA-256') throw new Error('Unsupported digest algorithm');
const hash = crypto.createHash('sha256');
hash.update(receivedBody);
const calculatedDigest = hash.digest('base64');
if (receivedDigest !== calculatedDigest) throw new Error('Invalid digest');
This chapter demonstrates how to verify the Digest
header in Node.js. If the isValidDigest
variable is true
, the message body integrity is confirmed. Otherwise, the message body may have been tampered with during transit.