Comment utiliser Buffer.from() avec crypto.timingSafeEqual() ?

Pour une raison quelconque, je reçois

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined

des deux arguments à crypto.timingSafeEqual(a, b).

j'ai aussi essayé

const a = Buffer.from(signature, 'utf8').toString('base64');
const b = Buffer.from(expectedSignature, 'utf8').toString('base64');

et j'obtiens la même erreur.

Question

Quelqu'un peut-il comprendre pourquoi les arguments ne sont pas des tampons ?

const express = require("express");
const bodyParser = require("body-parser");
const crypto = require('crypto');
const secret = "x";
const app = express();
const PORT = 8080;
app.use(bodyParser.json());
function isSigOk(request, secret) {
// calculate the signature
const expectedSignature = "sha256=" +
crypto.createHmac("sha256", secret)
.update(JSON.stringify(request.body))
.digest("hex");
// compare the signature against the one in the request
const signature = request.headers["X-Hub-Signature-256"];
const a = Buffer.from(signature);
const b = Buffer.from(expectedSignature);
return crypto.timingSafeEqual(a, b);
};
app.post("/", (req, res) => {
if (isSigOk(req, secret)) {
// Do stuff here
} else {
console.log('Error: Signatures does not match. Return res.status(401)');
};
res.status(200).end();
});
// Start express on the defined port
app.listen(PORT, () => console.log(`Github wekhook listening on port ${PORT}`));


Solution du problème

Je vois deux problèmes:

  • Le premier et le principal est qu'il isSigOksuppose qu'il y aura une valeur pour l' "X-Hub-Signature-256"en-tête :

    const signature = request.headers["X-Hub-Signature-256"];
    const a = Buffer.from(signature);

    Cet Buffer.fromappel lancera l'erreur que vous avez citée si signaturec'est undefinedparce que l'en-tête n'est pas là. Vous voudrez probablement revenir falsedans ce cas (et probablement éviter la surcharge de travail sur la signature attendue en réorganisant un peu les choses), voir les ***commentaires et les lignes associées :

    function isSigOk(request, secret) {
    // *** get the signature on this message, if any
    const signature = request.headers["X-Hub-Signature-256"];
    if (!signature) {
    // *** none
    return false;
    }
    // calculate the signature
    const expectedSignature = "sha256=" +
    crypto.createHmac("sha256", secret)
    .update(JSON.stringify(request.body))
    .digest("hex");
    // compare the signature against the one in the request
    const a = Buffer.from(signature);
    const b = Buffer.from(expectedSignature);
    return crypto.timingSafeEqual(a, b);
    };


  • La capitalisation compte. Selon la documentation de Node.js (l'objet d'Express Requsethérite de celui de Node.js IncomingMessage), les noms d'en-tête headerssont en minuscules. Alors request.headers["X-Hub-Signature-256"]devrait être request.headers["x-hub-signature-256"]. (Dans un commentaire, vous avez dit que vous obteniez une valeur, mais le commentaire utilisait toutes les minuscules, alors que le code utilise une casse mixte.) Donc :

    function isSigOk(request, secret) {
    // *** get the signature on this message, if any
    const signature = request.headers["x-hub-signature-256"]; // *** Lowercase
    if (!signature) {
    // *** none
    return false;
    }
    // calculate the signature
    const expectedSignature = "sha256=" +
    crypto.createHmac("sha256", secret)
    .update(JSON.stringify(request.body))
    .digest("hex");
    // compare the signature against the one in the request
    const a = Buffer.from(signature);
    const b = Buffer.from(expectedSignature);
    return a.length === b.length && crypto.timingSafeEqual(a, b);
    };

    Notez la a.length === b.length &&partie de cela. timingSafeEquallancera une erreur si les tampons n'ont pas la même longueur, mais nous voulons plutôt retourner false dans cette situation.

  • Commentaires

    Posts les plus consultés de ce blog

    Comment signer la connexion OKEx API version 5 avec websockets ?

    La fonction GCP Cloud pour écrire des données dans BigQuery s'exécute avec succès, mais les données n'apparaissent pas dans la table BigQuery

    Erreur Symfony : "Une exception a été levée lors du rendu d'un modèle"