Validator - API Keys y Firmas
Cómo manejamos la seguridad en el validador
Validator: API Keys
Los API Keys de Validator son diferentes que tus API Keys de otros productos de Shinkansen.
Validator: Firmas
Las peticiones de validación que envías a Shinkansen están protegidas por API Keys y por el transporte TLS. No debes firmarlas.
Las respuestas a las validaciones son enviadas a un webhook de tu aplicación con una cabecera Shinkansen-Validator-Signature
que contiene una firma HMAC del contenido de la respuesta. Para verificar esa firma debes:
-
Tener almacenado de manera segura el secreto compartido de Shinkansen para el producto Validator.
-
Calcular la firma HMAC SHA256 del contenido de la respuesta usando el algoritmo SHA-256 y el secreto compartido. Es muy importante que calcules la firma HMAC desde el contenido raw del body HTTP. Si parseas el body como JSON y luego lo vuelves a convertir en string, el parser puede cambiar el orden de los campos y la firma no va a coincidir.
-
Llevar el valor de la firma HMAC a hexadecimal (base 16).
-
Comparar el resultado con el valor enviado en la cabecera
Shinkansen-Validator-Signature
(normalizando a mayúsculas o minúsculas).
Ejemplos de código para validar HMAC 256 en formato hexadecimal
Via https://github.com/danharper/hmac-examples/
var crypto = require("crypto");
var key = "the shared secret key here";
var message = "the message to hash here";
var hash = crypto.createHmac("sha256", key).update(message);
// to lowercase hexits
hash.digest("hex");
const key = "the shared secret key here";
const message = "the message to hash here";
const getUtf8Bytes = (str) =>
new Uint8Array(
[...unescape(encodeURIComponent(str))].map((c) => c.charCodeAt(0)),
);
const keyBytes = getUtf8Bytes(key);
const messageBytes = getUtf8Bytes(message);
const cryptoKey = await crypto.subtle.importKey(
"raw",
keyBytes,
{ name: "HMAC", hash: "SHA-256" },
true,
["sign"],
);
const sig = await crypto.subtle.sign("HMAC", cryptoKey, messageBytes);
// to lowercase hexits
[...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, "0")).join("");
require 'openssl'
require 'base64'
key = 'the shared secret key here'
message = 'the message to hash here'
# to lowercase hexits
OpenSSL::HMAC.hexdigest('sha256', key, message)
import hashlib
import hmac
import base64
message = bytes('the message to hash here', 'utf-8')
secret = bytes('the shared secret key here', 'utf-8')
hash = hmac.new(secret, message, hashlib.sha256)
# to lowercase hexits
hash.hexdigest()
using System;
using System.Security.Cryptography;
using System.Text;
class MainClass {
public static void Main (string[] args) {
string key = "the shared secret key here";
string message = "the message to hash here";
byte[] keyByte = new ASCIIEncoding().GetBytes(key);
byte[] messageBytes = new ASCIIEncoding().GetBytes(message);
byte[] hashmessage = new HMACSHA256(keyByte).ComputeHash(messageBytes);
// to lowercase hexits
String.Concat(Array.ConvertAll(hashmessage, x => x.ToString("x2")));
}
}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import javax.xml.bind.DatatypeConverter;
class Main {
public static void main(String[] args) {
try {
String key = "the shared secret key here";
String message = "the message to hash here";
Mac hasher = Mac.getInstance("HmacSHA256");
hasher.init(new SecretKeySpec(key.getBytes(), "HmacSHA256"));
byte[] hash = hasher.doFinal(message.getBytes());
// to lowercase hexits
DatatypeConverter.printHexBinary(hash);
}
catch (NoSuchAlgorithmException e) {}
catch (InvalidKeyException e) {}
}
}
<?php
$key = 'the shared secret key here';
$message = 'the message to hash here';
// to lowercase hexits
hash_hmac('sha256', $message, $key);
Updated about 1 year ago