Proceso de Verificación Detallado (Su Lado)
Para validar la autenticidad de una notificación, su sistema debe realizar los siguientes pasos.
Es recomendable obtener y almacenar en caché su clave pública para no tener que solicitarla en cada verificación.
Paso 1: Obtener su Clave Pública
La verificación de la firma se realiza utilizando su clave pública. Esta clave es la contraparte de la clave privada que SyPago utiliza para firmar las notificaciones en su nombre.
Para obtenerla, debe realizar una petición GET al siguiente endpoint, asegurándose de incluir su JWT de autenticación en la cabecera Authorization.
GET /api/v1/user/key
Respuesta Exitosa (200 OK): El endpoint retornará su clave pública en formato PEM.
{
"public_key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9hXXl4g886loHmI10dLrJWFHEB8r\ncyqD1hBdIM3ekQkb5YTpOShAu+7xk0fyL/0IBjLEKwSd7rsKrYGtIgJj0w==\n-----END PUBLIC KEY-----\n"
}
Debe almacenar esta clave de forma segura para utilizarla en el paso de verificación.
Paso 2: Extraer los Componentes de la Notificación
Cuando su endpoint de webhook recibe una notificación de SyPago, debe extraer los siguientes tres componentes:
1-El payload: Es el cuerpo JSON completo de la solicitud HTTP POST.
2-La cabecera X-Signature: Contiene la firma digital codificada en Base64.
3-La cabecera X-Signature-Nonce: Contiene el nonce utilizado para generar la firma.
Paso 3: Reconstruir el Mensaje a Verificar
Con todos los componentes listos, proceda con la verificación criptográfica:
1-Decodificar la Firma: tome el valor de la cabecera X-Signature y decodifíquelo de Base64 a bytes.
2-Realizar la Verificación: utilizando una biblioteca criptográfica compatible con ECDSA, use su clave pública (obtenida en el Paso 1) para verificar que la firma decodificada corresponde al hash SHA-256 de la cadena stringToSign que reconstruyó en el Paso 3.
Concatene el payload (exactamente como lo recibió), el nonce de la cabecera y su operation_secret, separados por puntos.
stringToSign = "{payload}.{nonce}.{operationSecret}"
Importante: El payload debe ser la cadena de texto cruda del cuerpo de la solicitud, sin ninguna modificación o re-serialización, ya que cualquier cambio, incluso de espacios en blanco, invalidará la firma.
Paso 4: Verificar la Firma
Con todos los componentes listos, proceda con la verificación criptográfica:
1-Decodificar la Firma: Tome el valor de la cabecera X-Signature y decodifíquelo de Base64 a bytes.
2-Realizar la Verificación: Utilizando una biblioteca criptográfica compatible con ECDSA, use su clave pública (obtenida en el Paso 1) para verificar que la firma decodificada corresponde al hash SHA-256 de la cadena stringToSign que reconstruyó en el Paso 3.
Ejemplo Conceptual (pseudocódigo):
publicKey = "-----BEGIN PUBLIC KEY-----\n..." // Obtenida del endpoint /api/v1/user/key
signatureB64 = request.headers['X-Signature']
nonce = request.headers['X-Signature-Nonce']
payload = request.body.raw_string
operationSecret = database.getSecretForTransaction(payload.transaction_id)
stringToSign = $"{payload}.{nonce}.{operationSecret}"
isValid = ECDSA.verify(publicKey, stringToSign, Base64.decode(signatureB64), "SHA256")
if (isValid) {
// La notificación es auténtica. Procesar el pago.
} else {
// La notificación es inválida. Descartar y registrar el intento.
}
Si la función de verificación devuelve true, puede estar seguro de que la notificación es auténtica, proviene de SyPago y no ha sido modificada. Si devuelve false, debe descartar la notificación, ya que podría ser fraudulenta, y es recomendable registrar el evento para su revisión.