#javascript #node.js #ecmascript-6
#javascript #node.js #ecmascript-6
Вопрос:
По какой-то причине я получаю
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
из обоих аргументов в crypto.timingSafeEqual(a, b)
.
Я тоже пробовал
const a = Buffer.from(signature, 'utf8').toString('base64');
const b = Buffer.from(expectedSignature, 'utf8').toString('base64');
и я получаю ту же ошибку.
Вопрос
Кто-нибудь может понять, почему аргументы не являются буферами?
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}`));
Комментарии:
1. Я не думаю, что ошибка из
timingSafeEqual
, я думаю, что это изBuffer.from
. (Вы получите точно такую же ошибку, если вы это сделаетеBuffer.from(undefined)
.) Это говорит мне, чтоrequest.headers["X-Hub-Signature-256"]
этоundefined
так.2. @T.J.Crowder Когда я
console.log
этоconst signature = request.headers["x-hub-signature-256"];
получаюsha256=01df1ffc00107ab2e8782ba7983bb7245df79b6b414d4e89f8357144d61613cb
, значит, я получаю данные?
Ответ №1:
Я вижу две проблемы:
- Первый и основной заключается в том, что
isSigOk
предполагается, что для заголовка будет значение"X-Hub-Signature-256"
:const signature = request.headers["X-Hub-Signature-256"]; const a = Buffer.from(signature);
Этот
Buffer.from
вызов выдаст ошибку, которую вы указали,signature
undefined
потому что заголовка там нет. Вероятно, вы захотите вернутьсяfalse
в этом случае (и, вероятно, пропустить накладные расходы на разработку ожидаемой подписи, немного изменив порядок вещей), см.***
Комментарии и связанные строки: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); };
- Значение заглавных букв имеет значение. Согласно Node.js документация (
Requset
объект Express наследуется от Node.js ‘sIncomingMessage
), названия заголовков вheaders
строчных буквах. Такrequest.headers["X-Hub-Signature-256"]
и должно бытьrequest.headers["x-hub-signature-256"]
. (В комментарии вы говорите, что получаете значение, но в комментарии используются все строчные буквы, тогда как в коде используется смешанный регистр.) Итак: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 amp;amp; crypto.timingSafeEqual(a, b); };
Обратите внимание на эту
a.length === b.length amp;amp;
часть.timingSafeEqual
выдаст ошибку, если буферы разной длины, но вместо этого мы хотим вернуть false в этой ситуации.
Комментарии:
1. Лучше сравните байтовую длину в возвращаемом like
return Buffer.byteLength(a) === Buffer.byteLength(b) amp;amp; crypto.timingSafeEqual(a, b);
, иначе это может привестиRangeError
к появлению nodejs, если два буфера имеют разную длину.2. @ikhvjs — Хороший улов, спасибо! Я удивлен
false
, что в этом случае он не просто возвращается, но документы подтверждают то, что вы сказали: он выдает ошибку. 🙂3. Спасибо — это очень четкий ответ и отличный код.