Ir al contenido

NextPDF Gotenberg: seguridad y operaciones

Este puente envía por la red, a un servicio externo, los documentos que conserva su aplicación. Eso lo convierte en una superficie de solicitudes del lado del servidor y también en una superficie de seguridad de transporte. El paquete implementa controles específicos y verificables en ambas superficies. Por sí solo, no vuelve seguro el sistema. Los controles solo son eficaces si se combinan con la forma en que se despliega y opera el servicio Gotenberg. Esta página describe los controles implementados y las obligaciones operativas que los completan.

Ningún control descrito aquí se presenta como garantía. Cada uno es un comportamiento definido, cubierto por pruebas y con límites declarados.

El puente aplica dos políticas de seguridad distintas, cada una en una capa diferente:

  • Política de transporte (GotenbergSecurityPolicy): aplicación del esquema de la URL, detección de falsificación de solicitudes del lado del servidor (SSRF), defensa frente a la reasignación de DNS (DNS-rebind), límites de tamaño de entrada y filtrado de nombres de archivo. Esta es la capa que se documenta en detalle a continuación.
  • Política de análisis de HTML: una política de contenido en la capa de análisis que, por defecto, usa la política predeterminada del núcleo de NextPDF y se aplica antes de que el contenido pueda llegar a un renderizador. Es complementaria a la política de transporte e independiente de ella. Esta página se centra en la política de transporte.

Detección de falsificación de solicitudes del lado del servidor (SSRF)

Sección titulada «Detección de falsificación de solicitudes del lado del servidor (SSRF)»

La URL de la API configurada se examina antes de que salga del proceso cualquier byte. El control consta de tres partes.

Aplicación del esquema. Solo se acepta https (sin distinguir mayúsculas de minúsculas). Una URL simple http:// se rechaza. Por tanto, la seguridad de la capa de transporte (TLS) es obligatoria para cada conversión y para la sonda de estado.

Examen de la dirección. Si el host es una IP literal, se rechaza cuando pertenece a un rango privado o reservado. Si el host es un nombre, se resuelven todos sus registros A y AAAA, y la solicitud se rechaza si cualquiera de las direcciones resueltas es privada o reservada. Resolver el conjunto completo de registros, en lugar de una sola dirección, es el control que neutraliza a un atacante que oculta una dirección privada tras un nombre que también devuelve una pública. Este es el enfoque que la guía de prevención de SSRF de OWASP describe como obtener todas las direcciones IP detrás del nombre de dominio (registros A y AAAA, para IPv4 e IPv6) y validar cada una frente a una lista de permitidos (OWASP Cheat Sheet Series, prevención de SSRF, defensa en la capa de aplicación; fijado en el RAG sidecar de la página).

Reverificación de tiempo-de-comprobación/tiempo-de-uso (TOCTOU). El conjunto de direcciones capturado durante la validación se vuelve a resolver y se compara inmediatamente antes de la solicitud. Si aparece una dirección nueva, la solicitud se aborta con un error de reasignación de DNS. Esto cierra la ventana entre la comprobación de validación y la conexión que, de otro modo, explotaría un ataque de reasignación.

Cuando el puente usa su transporte con fijación mediante cURL, el conjunto de direcciones validado se vincula con la conexión mediante CURLOPT_RESOLVE, de modo que el núcleo se conecta a la dirección verificada en lugar de a la que pudiera devolver una nueva búsqueda de DNS en el momento de la conexión. El seguimiento de redirecciones está deshabilitado en ese transporte (CURLOPT_FOLLOWLOCATION desactivado, CURLOPT_MAXREDIRS a cero), por lo que una respuesta 3xx no puede enviar la solicitud de forma silenciosa a un host no verificado. En su lugar, la respuesta se propaga a la capa de políticas.

Consecuencia operativa. La protección frente a SSRF rechaza las direcciones privadas y reservadas por diseño. Si Gotenberg se ejecuta en una red privada, no se puede apuntar el puente a su dirección privada. Debe exponerse a través de una dirección que la protección acepte y proteger esa ruta con segmentación de red y autenticación, como se describe en el apartado de despliegue más adelante.

Seguridad de transporte y fijación de clave pública

Sección titulada «Seguridad de transporte y fijación de clave pública»

La verificación del par y del host en TLS está siempre activada en el transporte con fijación mediante cURL (CURLOPT_SSL_VERIFYPEER en true, CURLOPT_SSL_VERIFYHOST en 2). Además de la validación estándar de la cadena, el puente admite la fijación de SubjectPublicKeyInfo (SPKI).

Cada fijación es un hash SHA-256 de la SubjectPublicKeyInfo del servidor, expresado como sha256/<base64>. El puente acepta un certificado cuyo hash de SPKI coincide con cualquier fijación del conjunto combinado de primarias y de respaldo. Este modelo de fijación de respaldo sigue la RFC 7469 §4.3, que identifica una fijación de respaldo —una huella de un par de claves secundario aún no desplegado— como la forma principal de recuperarse de un fallo involuntario en la validación de fijación, y la §2.5, que exige que el conjunto fijado incluya al menos una fijación no presente en la cadena de certificados actual (RFC 7469 §4.3 y §2.5; fijado en el RAG sidecar de la página). El código del puente declara la RFC 7469 §2.1 y §2.6 para la semántica de «al menos una fijación de respaldo» y de intersección del conjunto combinado. La fijación es opcional: sin fijaciones configuradas, se aplica la validación estándar de la cadena y la fijación no se exige.

Una fijación que no se pueda analizar correctamente provoca un error de configuración antes de cualquier solicitud. Un certificado activo cuya SPKI no coincide con ninguna fijación configurada provoca el fallo de la solicitud en el transporte, por diseño.

Una rotación mal hecha deja al puente bloqueado fuera del servicio. Para rotar sin interrumpir el servicio:

  1. Antes de cambiar la clave del servidor, generar la fijación de SPKI para la clave nueva y añadirla a la lista de fijaciones de respaldo. Desplegar esa configuración. El puente acepta ahora tanto la clave actual como la futura.
  2. Cambiar el certificado o la clave del servidor por la clave nueva.
  3. Confirmar que las conversiones siguen teniendo éxito (la clave nueva ahora coincide con la fijación de respaldo).
  4. Mover la fijación nueva de la lista de respaldo a la lista primaria y eliminar la fijación de la clave retirada. Desplegar.
  5. Generar y preparar la fijación para la próxima rotación como nuevo respaldo, de modo que el conjunto lleve siempre un repuesto utilizable.

Mantener la lista de respaldo separada de la lista primaria permite preparar y validar la siguiente fijación sin tocar la activa.

Cuando apiKey no está vacío, se envía como una cabecera Authorization: Bearer en la solicitud de conversión. El campo está marcado como #[\SensitiveParameter], de modo que el valor se oculta en las trazas de pila. El puente no obtiene el secreto automáticamente; debe suministrarse desde un gestor de secretos al iniciar el proceso y nunca incluirse en el control de versiones. El token no se escribe en el registro de solicitudes: la entrada de depuración registrada contiene únicamente la URL, el nombre de archivo, el formato y la longitud del contenido.

Una respuesta se acepta solo cuando el estado es 200, el Content-Type contiene application/pdf y el cuerpo comienza con la firma %PDF. La comprobación de la firma de bytes existe porque un tipo de contenido declarado por sí solo no establece qué representan los bytes: es el mismo razonamiento que el estándar WHATWG MIME Sniffing formaliza en su algoritmo de detección de tipo MIME, que deriva un tipo calculado a partir de la coincidencia de los patrones de bytes iniciales, y no del tipo suministrado. La guía de carga de archivos de OWASP enuncia el principio de aplicación correspondiente: validar el tipo de archivo y no confiar en la cabecera Content-Type declarada, porque puede falsificarse (WHATWG MIME Sniffing §6.2.3; OWASP Cheat Sheet Series, validación de carga de archivos; ambos fijados en el RAG sidecar de la página). El puente aplica la comprobación equivalente de forma defensiva en la entrada: una discrepancia provoca una excepción tipada y los bytes nunca se devuelven como resultado.

Este límite es también la razón por la que el contrato de PSR-18 resulta relevante aquí. Un cliente PSR-18 lanza una excepción únicamente cuando no puede enviar la solicitud o no puede analizar la respuesta en un objeto PSR-7; no lanza una excepción ante un código de estado de error. Una respuesta 4xx/5xx bien formada se devuelve al llamante con normalidad (PSR-18, «Exceptions»; fijado en el RAG sidecar de la página). Por tanto, el puente inspecciona por sí mismo el estado, el tipo y la firma en lugar de suponer que una respuesta devuelta es satisfactoria. La semántica HTTP para una violación de la restricción de content-type —un rechazo 415 (Unsupported Media Type), en el que un servidor rechaza contenido en un formato no admitido— es el modelo que refleja la comprobación entrante (RFC 9110 §15.5.16; fijado en el RAG sidecar de la página).

El único límite de recursos dentro del proceso es maxFileSize (predeterminado: 52 428 800 bytes = 50 MiB), aplicado antes de la solicitud, de modo que una entrada de tamaño excesivo nunca llega al servicio. No hay un límite de concurrencia, límite de tasa ni tope de tamaño de salida integrados en el puente. Esas son responsabilidades del despliegue y del llamante (consulte /integrations/gotenberg/production-usage/). Establecer maxFileSize en el valor más pequeño que requieran los documentos reales: un tope más ajustado es un control más barato frente a la denegación de servicio.

Despliegue y protección del servicio Gotenberg

Sección titulada «Despliegue y protección del servicio Gotenberg»

El puente solo es tan seguro como el servicio al que llama. Ese servicio queda bajo responsabilidad operativa del despliegue; las obligaciones siguientes completan los controles anteriores.

  • Terminar TLS delante de Gotenberg. El contenedor de Gotenberg habla HTTP simple de forma predeterminada. El puente requiere HTTPS, así que Gotenberg debe colocarse detrás de un proxy inverso, un ingress o una malla de servicios que termine TLS, y el puente debe apuntar al extremo HTTPS. Fijar la SPKI del proxy si se habilita la fijación.
  • No exponer Gotenberg públicamente. Gotenberg realiza la conversión de documentos con motores de la clase de LibreOffice y Chromium, y no es un servicio orientado a Internet. Restringir el tráfico de entrada a los hosts de aplicación que lo llaman, mediante política de red o cortafuegos.
  • Exigir autenticación en la ruta. El puente envía un token de portador (bearer) cuando está configurado; aplicarlo (o aplicar TLS mutuo) en el proxy para que una solicitud no autenticada no pueda llegar al motor de conversión.
  • Fijar una versión concreta del servicio. El puente asume exactamente dos rutas de servicio: /forms/libreoffice/convert y /health. Fijar la imagen de Gotenberg a una etiqueta de parche concreta, verificar esas dos rutas frente a la versión que se despliega y volver a verificarlas en cada actualización.
  • Dimensionar la capacidad de conversión de forma deliberada. Cada conversión retiene a un trabajador durante toda la solicitud. Dimensionar el despliegue de Gotenberg para la tasa máxima de conversiones concurrentes y limitar las conversiones en curso del lado del llamante para que coincidan. La capacidad es una propiedad del despliegue, no de este paquete.
  • Tratar las entradas de conversión como no confiables. Los documentos que se procesan en la conversión los manejan motores complejos. Restringir maxFileSize, aislar el despliegue de Gotenberg (su propio segmento de red, salida mínima, sin acceso a servicios internos) y mantener el motor actualizado con parches.
  • No es «seguro de forma predeterminada»: los controles son reales, pero dependen de un despliegue y una configuración correctos.
  • No hace que la conversión sea «a prueba de manipulaciones» ni que la salida esté «certificada». Valida el transporte y la forma de la respuesta; no atestigua el contenido del documento.
  • No proporciona firma, marca de tiempo ni validación a largo plazo. Esas son cuestiones de posprocesamiento. La compatibilidad con PAdES de la edición Pro es únicamente la línea base B-B y no incluye B-T, B-LT ni B-LTA; nada en este puente implica una capacidad de marca de tiempo o de LTV.
  • No admite «todos los archivos de Office». Admite los seis formatos enumerados y rechaza todo lo demás antes de cualquier solicitud.
  • /integrations/gotenberg/configuration/: las reglas de selección de transporte y el modelo completo de fijación.
  • /integrations/gotenberg/production-usage/: reintentos, tiempos de espera, concurrencia y observabilidad.
  • /integrations/gotenberg/troubleshooting/: cada excepción de seguridad y su desencadenante.
  • /integrations/gotenberg/overview/: el flujo de conversión y el modelo de dependencias.