Saltar al contenido principal

Cifrado de campos de referencia PSE (JWE)

¿Qué es y para qué sirve?

Cuando realizas transacciones a través de PSE, puedes enviar los campos reference-one, reference-two y reference-three como parte del objeto payment-method. Estos campos pueden contener información sensible dependiendo de la actividad económica de tu comercio (por ejemplo, direcciones IP, números de documento o fechas de apertura de productos financieros).

Para proteger esta información, Wompi te ofrece la posibilidad de cifrar estos campos usando JWE (JSON Web Encryption). Esto es completamente opcional: si tu comercio no requiere cifrado, puedes seguir enviando los valores en texto plano como siempre. Wompi detecta automáticamente si un campo viene cifrado o no, y lo procesa de forma transparente.

¿Cuándo deberías usar cifrado?

Considera cifrar los campos de referencia si:

  • Tu comercio pertenece a la categoría de Servicios Financieros y envías datos sensibles del usuario en estos campos.
  • Quieres agregar una capa adicional de seguridad a la información que viaja en la transacción.
  • Tu política interna de seguridad requiere que los datos sensibles se transmitan cifrados.

Si ninguno de estos casos aplica para ti, puedes seguir enviando los campos en texto plano sin ningún problema.

¿Cómo funciona?

El proceso es sencillo:

  1. Descargas la llave pública de Wompi desde esta página de documentación.
  2. Cifras los campos reference-one, reference-two y/o reference-three usando esa llave pública.
  3. Envías los valores cifrados en tu transacción, ya sea a través del Widget, Web Checkout o directamente por API.
  4. Wompi detecta que los campos vienen cifrados, los descifra internamente y procesa la transacción normalmente.

Puedes cifrar todos los campos de referencia, solo algunos, o ninguno. Cada campo se evalúa de forma independiente, así que es perfectamente válido enviar reference-one en texto plano y reference-two cifrado en la misma transacción.

Paso 1: Obtén la llave pública

La llave pública RSA que necesitas para cifrar está disponible directamente desde esta página. Cópiala o descárgala usando el botón:

LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUFwWVVEMW9wclRteUFyWVJ6d3k3SgpzM1EyRXhPN1ZEY0ViT256RVpBTzBtZlA5YWY3OU9ObEpzQ1JzWkl1bjhuZW5kenR0UHlEWE1Qak0zWTAxMzhtCmUyb3Erb05UY1pkY1pLaGFGYTBiVjdTOC9TaWlpS2VsczFnTG5nQUszbWx0bmJKTGFKMGwrOFA2THc5bHZXbVYKQ1NBUUk5WFJNaWdtdkxLa2JJT1lSY0tOdkpIekJMQkNxNzh1L01KZCsxZWJ1bGx5ZzN2VmZuZ1RBZUJRcVFkawp3aGxQY2Z4Z2dteWlKbTdmajRXcUFGTzdQalMrTUd0RDZRNklBRUZYa28zS0N0OVhxWkJnRER4ZERxL01qNklYCmhxNUd6MFJYU2tKVStYcTFiS2hGOTErM0x2VUwrZmVwS2R3aDd6cnFPa2I3d2ZwODVHcVo4dkRVU2ZOMlR4THUKZXFlVm5JOWJjT3BsUXlsTTlxckY4TDBleTZxR24wMERQb0NCRGNiL1NJNnF3blhtdjNoUW9NWWlOR0pTejAvbApIUmx0UGpJWFplMUZTNWVwbndmcVVMaC92SEhmWllrVDVaazVzUG9QNlVSTzJrZGtjVmpaMWNUUHRvRTNqemN5Ck9KWnQ5eDNUWVcrbXNhMGFndjlyUXNPazlkRFFTNTFaUVZtLzM4UmV3Ly9Sc0x3YVk4RVV3WE1NR2lBc2ZZb0wKOEJjR1I1bXB0ZVJFcGEwZTJvZGNyYVh5dGo3UndwZTZPWFRMTlA3VWN1RENwOHBUM202ODMxWFlxUXk0LzdhSAp4WTJaNUNncklOT00zeUQ0VkdNQzhKVVc3L3BqTnI2bHJjNytYRldrODhyYlBzMWhucVhkZk5HNUdiOHg3WHBjCjBEYWpwa3RDdlRFU3JBTGtZOHJzaVMwQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=

Te recomendamos almacenar esta llave en una variable de entorno o en la configuración de tu aplicación, y renovarla periódicamente en caso de que Wompi rote las llaves.

Paso 2: Cifra los campos de referencia

El cifrado utiliza el estándar JWE (JSON Web Encryption) en formato compact serialization. Los algoritmos que debes usar son:

ParámetroValorDescripción
alg (Key Management)RSA-OAEPAlgoritmo para envolver la clave simétrica efímera usando la llave pública RSA
enc (Content Encryption)A256GCMAlgoritmo de cifrado del contenido (AES-256-GCM)

El resultado del cifrado es un string con 5 segmentos separados por puntos:

BASE64URL(Header).BASE64URL(EncryptedKey).BASE64URL(IV).BASE64URL(Ciphertext).BASE64URL(AuthTag)

Ejemplo con jose v2 (Node.js)

Si tu proyecto usa jose versión 2:

npm install jose@^2.0.7
const { JWE, JWK } = require('jose');

// 1. Carga la llave pública que descargaste desde la documentación de Wompi
const publicKey = JWK.asKey(PUBLIC_KEY_PEM);

// 2. Cifra el valor del campo de referencia
const referenceOneCifrado = JWE.encrypt(
'192.168.1.1', // El valor que quieres cifrar
publicKey,
{ alg: 'RSA-OAEP', enc: 'A256GCM' }
);

// referenceOneCifrado ahora es un string JWE listo para enviar
console.log(referenceOneCifrado);
// eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.abc123...

Ejemplo con jose v4+ / v5 (Node.js)

Si tu proyecto usa jose versión 4 o superior:

npm install jose@^5.0.0
const { importSPKI, CompactEncrypt } = require('jose');

async function cifrarReferencia(valor, llavePublicaPem) {
// 1. Importa la llave pública
const publicKey = await importSPKI(llavePublicaPem, 'RSA-OAEP');

// 2. Cifra el valor
const encoder = new TextEncoder();
const jwe = await new CompactEncrypt(encoder.encode(valor))
.setProtectedHeader({ alg: 'RSA-OAEP', enc: 'A256GCM' })
.encrypt(publicKey);

return jwe;
}

// Uso
const referenceOneCifrado = await cifrarReferencia('192.168.1.1', PUBLIC_KEY_PEM);

Paso 3: Envía los campos cifrados en tu transacción

Una vez cifrados los campos, envíalos exactamente como enviarías los valores en texto plano. Wompi detecta automáticamente el formato JWE y los descifra antes de procesar la transacción. No necesitas indicar de ninguna forma que los campos vienen cifrados: el sistema lo identifica por sí solo.

En el Widget o Web Checkout

Usa los campos reference-one, reference-two y reference-three dentro del objeto payment-method como lo harías normalmente. La única diferencia es que el valor será el string JWE cifrado en lugar del texto plano:

<form>
<script
src="https://checkout.wompi.co/widget.js"
data-render="button"
data-public-key="pub_test_X0zDA9xoKdePzhd8a0x9HAez7HgGO2fH"
data-currency="COP"
data-amount-in-cents="4950000"
data-reference="MI-REFERENCIA-UNICA"
data-signature:integrity="TU_FIRMA_DE_INTEGRIDAD"
data-payment-method:reference-one="eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ..."
data-payment-method:reference-two="eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ..."
data-payment-method:reference-three="eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ..."
></script>
</form>
Tip

Los atributos data-payment-method:reference-* aceptan tanto texto plano como valores cifrados JWE. Puedes migrar gradualmente sin cambiar la estructura de tu integración.

Vía API

Si integras directamente con el API de Wompi, envía los valores cifrados en el cuerpo de la petición dentro del objeto payment_method. El campo acepta el string JWE completo:

{
"payment_method": {
"type": "PSE",
"reference_one": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ...",
"reference_two": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ...",
"reference_three": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ..."
}
}
Nota

Puedes mezclar campos cifrados y en texto plano en la misma transacción. Por ejemplo, enviar reference_one cifrado y reference_two en texto plano es perfectamente válido.


## Ejemplo completo

Este ejemplo muestra cómo obtener la llave pública, cifrar los tres campos de referencia y enviar la transacción:

```javascript
const { importSPKI, CompactEncrypt } = require('jose');

async function crearTransaccionConCifrado() {
// 1. Usa la llave pública que descargaste desde la documentación de Wompi
const llavePublicaPem = process.env.WOMPI_PUBLIC_KEY; // Almacénala en una variable de entorno

// 2. Importa la llave pública
const publicKey = await importSPKI(llavePublicaPem, 'RSA-OAEP');
const encoder = new TextEncoder();

// 3. Función helper para cifrar un campo
const cifrar = async (valor) => {
return new CompactEncrypt(encoder.encode(valor))
.setProtectedHeader({ alg: 'RSA-OAEP', enc: 'A256GCM' })
.encrypt(publicKey);
};

// 4. Cifra los campos de referencia
const referenceOne = await cifrar('192.168.1.1');
const referenceTwo = await cifrar('20230115');
const referenceThree = await cifrar('123456789');

// 5. Envía la transacción con los campos cifrados
// Los campos cifrados se usan igual que los de texto plano,
// Wompi los detecta y descifra automáticamente.
}

Cosas importantes que debes saber

  • Es opcional. El cifrado es una capa adicional de seguridad. Si no lo necesitas, sigue enviando los campos en texto plano.
  • Puedes mezclar. Es válido enviar algunos campos cifrados y otros en texto plano en la misma transacción. Cada campo se evalúa de forma independiente.
  • Tolerante a errores. Si por alguna razón el descifrado falla (llave incorrecta, token corrupto, etc.), el campo pasa tal cual al procesamiento. Wompi no rechaza la transacción por un error de descifrado.
  • Usa siempre la llave pública de Wompi. No generes tu propio par de llaves. La llave pública que necesitas está disponible para descargar en esta página.
  • Rota periódicamente. Te recomendamos consultar la llave pública con cierta frecuencia para asegurarte de que estás usando la más reciente, en caso de que Wompi la rote.
  • Solo aplica para PSE. Este cifrado está disponible únicamente para los campos de referencia del medio de pago PSE en Colombia.

Cifra siempre en tu servidor
Al igual que con la firma de integridad, te recomendamos realizar el cifrado en tu backend y nunca en el frontend. Aunque la llave pública no es un secreto, exponer la lógica de cifrado en el cliente podría facilitar ataques de ingeniería inversa.