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

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

    Détecter les appuis sur les touches fléchées en JavaScript

    Une chaîne vide donne "Des erreurs ont été détectées dans les arguments de la ligne de commande, veuillez vous assurer que tous les arguments sont correctement définis"