Proceso de seguridad

La API implementa diferentes niveles de seguridad:

  1. Servicios planos (sin firma ni cifrado) Usados principalmente en ambientes de desarrollo/pruebas.

  2. Servicios con firma digital (JWS)

    • Garantizan integridad, autenticidad y no repudio.

    • Requieren intercambio de certificados y uso de llaves privadas/públicas.

  3. (Opcional) Tramas cifradas Según requerimientos del proyecto.

Adicionalmente:

  • La comunicación se realiza sobre HTTPS.

  • Se recomienda uso de VPN entre la Entidad Financiera Recaudadora y el comercio.

Servicios planos (sin seguridad)

Para agilizar el desarrollo de la integración se dispone de endpoints de prueba sin firma ni cifrado:

  • Generar QR (imagen Base64) https://<URL-TEST>/ws-qr-service/qr/simple/encript64

  • Bloquear QR https://<URL-TEST>/ws-qr-service/qr/simple/bloqued

  • Consultar QR https://<URL-TEST>/ws-qr-service/qr/simple/details

En producción se recomienda utilizar la capa de seguridad con firma digital JWS.

Firma digital JWS

La capa de seguridad utiliza el estándar JWS (JSON Web Signature) para firmar digitalmente las tramas JSON.


Flujo general

  1. Generar par de llaves

    • Llave privada y certificado digital (X.509 en formato PEM).

  2. Intercambio de certificados públicos

    • El comercio envía su certificado público a Tesabiz.

    • Tesabiz envía su certificado público al comercio.

  3. Construcción de la trama JSON normal

    • Según los esquemas descritos en los endpoints (por ejemplo, infoTx + qrCobro).

  4. Firma JWS

    • El comercio firma la trama con su llave privada usando una librería JWS (ej. algoritmo RS256).

  5. Construcción del payload para seguridad

{
  "code": "CODIGOCOMERCIO",
  "payload": "<TRAMA_FIRMADA_JWS>"
}
  • code: código de empresa en el sistema QR-Comercio (provisto por Tesabiz).

  • payload: cadena JWS resultante de firmar el JSON.

  1. Consumo de servicios seguros

  • Generar QR (texto hash) https://<URL-TEST>/tesabiz-ws-security/sc/jws/encript

  • Generar QR (imagen Base64) https://<URL-TEST>/tesabiz-ws-security/sc/jws/encript64

Respuesta de servicios seguros

La respuesta tiene la forma:

{
  "codReturn": "0",
  "txtReturn": "SUCCESS",
  "payload": "<TRAMA_FIRMADA_JWS_RESPUESTA>"
}
  • El comercio debe validar la firma del campo payload usando el certificado público de Tesabiz y luego decodificar la trama para obtener el JSON real (equivalente a las respuestas descritas en la sección de endpoints).


Confirmación de pago con JWS

Para el servicio Recibir Pago QR, el comercio debe:

  1. Exponer un endpoint que reciba:

    {
      "payload": "<TRAMA_FIRMADA_JWS>"
    }
  2. Validar la firma con el certificado público de Tesabiz.

  3. Parsear el contenido (que tendrá el mismo formato que qrPagado descrito en la documentación de endpoints).

  4. Responder:

    {
      "codReturn": "0",
      "txtReturn": "SUCCESS",
      "payload": "<TRAMA_FIRMADA_JWS_RESPUESTA>"
    }

Generación de firma

Con el equipo de QRPay se tiene que compartir su certificado, para esto generamos de esta manera usando openssl

openssl genrsa -out private.key 2048
openssl rsa -in private.key -pubout -out public.key
openssl req -new -key private.key -out request.csr
openssl x509 -req -days 365 -in request.csr -signkey private.key -out certificate.pem

El certificate.pem será el que se tiene compartir con el equipo de QRPay

Ejemplo para enviar el payload firmado

NodeJS

 const jwtPrivate = this.configService.get<string>('JWT_PRIVATE');

    const bodyEncrypted = jwt.sign({{PAYLOAD_BODY}}, {{PIVATE.KEY}}, {
      algorithm: 'RS256',
      noTimestamp: true, // IMPORTANTE
    });

    try {
      const response = await axios.post(
        `${URL_QRPAY}/tesabiz-ws-security/sc/jws/encript64`,
        {
          code: 'B89',
          payload: bodyEncrypted,
        },
      );

Tabla importante

CAMPO
DESCRIPCIÓN

noTimestamp

enviarle como verdadero

code

Código de su empresa registrada en Plataforma QRPay - pedir al encargado

body

El cuerpo encriptado

Validación de firma para el cliente

const qrpayPublicKey =
          this.configService.get<string>('QRPAY_PUBLIC_KEY');

const decoded = jwt.verify({{PAYLOAD_RESPONSE_ENCRYPTED}}, {{PUBLIC_KEY_QRPAY}}, {
  algorithms: ['RS256'],
});

Tabla importante

CAMPO
DESCRIPCIÓN

QRPAY_PUBLIC_KEY

La llave publica compartida por el equipo de QRPAY

Last updated