Unicco
Estoy tratando de crear una integración entre API de webhook de WooCommerce y mi servidor Node.js. Sin embargo, realmente no puedo entender cómo se supone que debo usar el secreto para autenticar la solicitud.
secret:
una clave secreta opcional que se utiliza para generar un HMAC-SHA256
hash del cuerpo de la solicitud para que el receptor pueda verificar la autenticidad del webhook.
X-WC-Webhook-Signature:
un hash HMAC-SHA256 codificado en Base64 de la carga útil.
Back-end de WooCommerce:
(Hemmelighed = “Secreto”)
Back-end de Nodejs:
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
router.post("https://stackoverflow.com/", function (req, res) {
var secret="ciPV6gjCbu&efdgbhfgj&¤"#&¤GDA";
var signature = req.header("x-wc-webhook-signature");
var hash = CryptoJS.HmacSHA256(req.body, secret).toString(CryptoJS.enc.Base64);
if(hash === signature){
res.send('match');
} else {
res.send("no match");
}
});
Fuente: https://github.com/woocommerce/woocommerce/pull/5941
Fuente API REST de WooCommerce
El hash y la firma no coinciden. ¿Qué está mal?
Actualizar:
console.log
devuelve estos valores:
hash
: pU9kXddJPY9MG9i2ZFLNTu3TXZA++85pnwfPqMr0dg0=
signature
: PjKImjr9Hk9MmIdUMc+pEmCqBoRXA5f3Ac6tnji7exU=
hash (without .toString(CryptoJS.enc.Base64))
: a54f645dd7493d8f4c1bd8b66452cd4eedd35d903efbce699f07cfa8caf4760d
gokcand
La firma debe verificarse con el cuerpo y no con el JSON que contiene. es decir los bytes sin procesar del req.body.
Modificar el bodyParser
primero:
const rawBodySaver = (req, res, buf, encoding) => {
if (buf && buf.length) {
req.rawBody = buf.toString(encoding || 'utf8');
}
};
app.use(bodyParser.json({ verify: rawBodySaver }));
app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' }));
y luego, usando cripto (se distribuye con un nodo que no necesita npm install
cualquier cosa.)
import crypto from 'crypto'; //Let's try with built-in crypto lib instead of cryptoJS
router.post("https://stackoverflow.com/", function (req, res) {
const secret="ciPV6gjCbu&efdgbhfgj&¤"#&¤GDA";
const signature = req.header("X-WC-Webhook-Signature");
const hash = crypto.createHmac('SHA256', secret).update(req.rawBody).digest('base64');
if(hash === signature){
res.send('match');
} else {
res.send("no match");
}
});
-
Gracias. Necesitas cambiar req.header[“”] a req.header(“”). Lo siento, pero la firma y el hash no coinciden. Estas son las salidas después de implementar el búfer: hash: pU9kXddJPY9MG9i2ZFLNTu3TXZA++85pnwfPqMr0dg0= firma: 2Od/YW7laO4EtqdsO3CvOcXPTIeFCY5qVZdKdWSJcKU=
– Unicco
10 de enero de 2018 a las 8:40
-
Si elimino bodyparser, el req.body está vacío. Intenté cambiar la clave secreta privada a algo más simple, y esto tampoco ayuda. Creo que se requiere bodyparser para acceder al cuerpo; sin embargo, no estoy seguro de cómo puedo acceder a él de manera diferente.
– Unicco
10 de enero de 2018 a las 11:51
-
@Unicco Sí, es cierto que necesitamos bodyParser para acceder a req.body. He actualizado la respuesta, ¿puedes verificarla de nuevo? Especialmente, intente la segunda forma.
– gokcand
10 de enero de 2018 a las 13:10
-
Gracias. Probaré estos enfoques lo antes posible y te lo haré saber.
– Unicco
10 de enero de 2018 a las 14:49
Espero que a continuación le ahorre tiempo a alguien.
// Make sure to add a WISTIA_SECRET_KEY in your Environment Variables
// See https://docs.pipedream.com/environment-variables/
const secret = process.env.SELF_AUTOMATE_KEY;
const signature = event.headers["x-wc-webhook-signature"];
const body = steps.trigger.raw_event["body_b64"];
const clean_Body = body.replace("body_b64: ", "");
//const body = steps.trigger.raw_event;
console.log(event.headers["x-wc-webhook-signature"]);
console.log("Print Body", clean_Body);
if (process.env.SELF_AUTOMATE_KEY === undefined) {
$end("No WISTIA_SECRET_KEY environment variable defined. Exiting.")
}
if (!("x-wc-webhook-signature" in event.headers)) {
$end("No x-wc-webhook-signature header present in the request. Exiting.")
}
// Once we've confirmed we have a signature, we want to
// validate it by generating an HMAC SHA-256 hexdigest
const crypto = require('crypto');
const hash = crypto.createHmac('sha256',
secret).update(JSON.stringify(clean_Body), 'base64').digest('base64');
console.log(hash);
// $end() ends the execution of a pipeline, presenting a nice message in the "Messages"
// column in the inspector above. See https://docs.pipedream.com/notebook/code/#end
if (hash !== signature) {
$end("The correct secret key was not passed in the event. Exiting!")
}
¿Estás tal vez usando
bodyParser
?req.body
no es necesariamente una cadena.– dedo
9 de enero de 2018 a las 16:09
@fingeron Sí, estoy usando bodyParser. He actualizado el codenippet. Probé var body = req.body.toString(‘utf8’); también, pero no ayuda.
– Unicco
9 de enero de 2018 a las 17:56
@Unicco ¿Agregarías console.log() tanto para el hash como para la firma? (hash sin toString() agregar con toString() )
– gokcand
9 de enero de 2018 a las 19:47
@gokcan y actualicé la pregunta.
– Unicco
09/01/2018 a las 20:39
@gokcand Perdón por la demora. Todavía no he tenido tiempo de comprobarlo. Implementé su solución ayer, pero recibí algunos errores. No tuve tiempo de arreglar esto. Examinaré más profundamente tu respuesta hoy. ¿Lo has probado tú mismo?
– Unicco
12 de enero de 2018 a las 11:01