NextPDF Gotenberg : sécurité et exploitation
En un coup d’œil
Section intitulée « En un coup d’œil »Ce pont transmet à un service externe, sur le réseau, des documents détenus par ton application. Il devient donc à la fois une surface de requêtes côté serveur et une surface de sécurité du transport. Le paquet applique des contrôles précis et vérifiables sur ces deux surfaces. À lui seul, il ne rend pas le système sûr. Ces contrôles ne sont efficaces que s’ils s’inscrivent dans la manière dont tu déploies et exploites le service Gotenberg. Cette page décrit les contrôles mis en œuvre et les obligations opérationnelles qui les complètent.
Aucun contrôle décrit ici n’est présenté comme une garantie. Chacun correspond à un comportement défini, couvert par des tests, avec des limites explicites.
Les deux couches de politique
Section intitulée « Les deux couches de politique »Le pont applique deux politiques de sécurité distinctes, situées à des couches différentes :
- Politique de transport (
GotenbergSecurityPolicy) — application stricte du schéma d’URL, filtrage des falsifications de requête côté serveur (SSRF), défense contre le rebind DNS, limites de taille des entrées et filtrage des noms de fichiers. C’est la couche documentée en détail ci-dessous. - Politique d’analyse HTML — une politique de contenu appliquée lors de l’analyse, qui correspond par défaut à la politique par défaut du cœur NextPDF et intervient avant que le contenu n’atteigne un moteur de rendu. Elle est complémentaire de la politique de transport et indépendante de celle-ci. Cette page porte sur la politique de transport.
Filtrage des falsifications de requête côté serveur (SSRF)
Section intitulée « Filtrage des falsifications de requête côté serveur (SSRF) »L’URL d’API configurée est filtrée avant que le moindre octet ne quitte le processus. Ce contrôle comporte trois volets.
Application stricte du schéma. Seul https est accepté (sans distinction de casse). Une simple URL en http:// est rejetée. Le chiffrement TLS (Transport Layer Security) est donc obligatoire pour chaque conversion et pour la sonde de santé.
Filtrage des adresses. Si l’hôte est une adresse IP littérale, il est rejeté dès qu’il appartient à une plage privée ou réservée. Si l’hôte est un nom, il est résolu en tous ses enregistrements A et AAAA, et la requête est rejetée si l’une des adresses résolues est privée ou réservée. Résoudre l’ensemble complet des enregistrements, plutôt qu’une seule adresse, est le contrôle qui met en échec un attaquant dissimulant une adresse privée derrière un nom qui renvoie aussi une adresse publique. C’est l’approche que les recommandations OWASP de prévention SSRF décrivent comme consistant à récupérer chaque adresse IP derrière le nom de domaine (enregistrements A et AAAA, pour IPv4 et IPv6) et à valider chacune par rapport à une liste d’autorisation (OWASP Cheat Sheet Series, prévention SSRF, défense en couche applicative ; épinglé dans le sidecar RAG de la page).
Revérification entre le contrôle et l’utilisation (TOCTOU). L’ensemble d’adresses capturé lors de la validation est de nouveau résolu et comparé juste avant la requête. Si une nouvelle adresse apparaît, la requête est interrompue avec une erreur de rebind DNS. Cela referme la fenêtre entre le contrôle de validation et la connexion qu’une attaque par rebind exploiterait sinon.
Lorsque le pont utilise son transport épinglé via cURL, l’ensemble d’adresses validé est associé à la connexion par CURLOPT_RESOLVE, de sorte que le noyau se connecte à l’adresse vérifiée plutôt qu’à ce que renverrait une nouvelle résolution DNS au moment de la connexion. Le suivi des redirections est désactivé sur ce transport (CURLOPT_FOLLOWLOCATION désactivé, CURLOPT_MAXREDIRS à zéro), de sorte qu’une réponse 3xx ne peut pas envoyer silencieusement la requête vers un hôte non vérifié. La réponse remonte plutôt à la couche de politique.
Conséquence opérationnelle. La protection SSRF rejette par conception les adresses privées et réservées. Si ton Gotenberg s’exécute sur un réseau privé, tu ne peux pas faire pointer le pont vers son adresse privée. Expose-le via une adresse que la protection accepte et protège cette voie d’accès par segmentation réseau et authentification, comme décrit dans la section déploiement ci-dessous.
Sécurité du transport et épinglage de clé publique
Section intitulée « Sécurité du transport et épinglage de clé publique »La vérification TLS du pair et de l’hôte est toujours active dans le transport épinglé via cURL (CURLOPT_SSL_VERIFYPEER à true, CURLOPT_SSL_VERIFYHOST à 2). En plus de la validation de chaîne standard, le pont prend en charge l’épinglage du SubjectPublicKeyInfo (SPKI).
Chaque pin est un hachage SHA-256 du SubjectPublicKeyInfo du serveur, exprimé sous la forme sha256/<base64>. Le pont accepte un certificat dont le hachage SPKI correspond à l’un des pins de l’ensemble combiné « principal plus secours ». Ce modèle de pin de secours suit la RFC 7469 §4.3, qui désigne un pin de secours — l’empreinte d’une paire de clés secondaire pas encore déployée — comme le principal moyen de récupération après un échec involontaire de validation de pin, ainsi que le §2.5, qui exige que l’ensemble épinglé comporte au moins un pin absent de la chaîne de certificats courante (RFC 7469 §4.3 et §2.5 ; épinglé dans le sidecar RAG de la page). Le code du pont s’appuie sur la RFC 7469 §2.1 et §2.6 pour la sémantique de l’« au moins un pin de secours » et de l’intersection de l’ensemble combiné. L’épinglage est facultatif : sans aucun pin configuré, la validation de chaîne standard s’applique et l’épinglage n’est pas imposé.
Un pin impossible à analyser déclenche une erreur de configuration avant toute requête. Un certificat en service dont le SPKI ne correspond à aucun pin configuré fait échouer la requête au niveau du transport — par conception.
Procédure de rotation des pins
Section intitulée « Procédure de rotation des pins »Une rotation ratée verrouille l’accès du pont au service. Effectue la rotation sans interruption de service :
- Avant de changer la clé du serveur, génère le pin SPKI de la nouvelle clé et ajoute-le à la liste des pins de secours. Déploie cette configuration. Le pont accepte désormais à la fois la clé actuelle et la clé future.
- Bascule le certificat ou la clé du serveur vers la nouvelle clé.
- Confirme que les conversions réussissent toujours (la nouvelle clé correspond maintenant au pin de secours).
- Déplace le nouveau pin de la liste de secours vers la liste principale et retire le pin de la clé mise hors service. Déploie.
- Génère et prépare le pin de la prochaine rotation comme nouveau secours, afin que l’ensemble dispose toujours d’une réserve utilisable.
Conserver la liste de secours séparée de la liste principale te permet de préparer et de valider le prochain pin sans toucher au pin actif.
Authentification
Section intitulée « Authentification »Lorsque apiKey n’est pas vide, il est envoyé sous forme d’en-tête Authorization: Bearer dans la requête de conversion. Le champ est marqué #[\SensitiveParameter] afin que sa valeur soit masquée dans les traces de pile. Le pont ne récupère pas le secret à ta place ; fournis-le depuis un gestionnaire de secrets au démarrage du processus et ne l’enregistre jamais dans le dépôt. Le jeton n’est pas écrit dans le journal des requêtes — l’entrée de débogage enregistrée ne contient que l’URL, le nom du fichier, le format et la longueur du contenu.
Limite de confiance de la réponse
Section intitulée « Limite de confiance de la réponse »Une réponse n’est acceptée que lorsque le statut est 200, que le Content-Type contient application/pdf et que le corps commence par la signature %PDF. La vérification de la signature octet par octet existe parce qu’un type de contenu déclaré ne suffit pas à établir la nature réelle des octets — c’est le raisonnement que la norme WHATWG MIME Sniffing formalise dans son algorithme de reniflage de type MIME, qui dérive un type calculé à partir des motifs présents dans les premiers octets plutôt qu’à partir du type fourni. Les recommandations OWASP sur l’envoi de fichiers énoncent le principe correspondant côté application : valide le type du fichier et ne te fie pas à l’en-tête Content-Type déclaré, car il peut être falsifié (WHATWG MIME Sniffing §6.2.3 ; OWASP Cheat Sheet Series, validation des envois de fichiers ; les deux épinglés dans le sidecar RAG de la page). Le pont applique le contrôle équivalent de façon défensive côté entrant : toute discordance déclenche une exception typée et les octets ne sont jamais renvoyés comme résultat.
Cette limite explique aussi pourquoi le contrat PSR-18 a son importance ici. Un client PSR-18 ne lève une exception que lorsqu’il ne peut pas envoyer la requête ou ne peut pas analyser la réponse en objet PSR-7 — il ne lève pas d’exception sur un code de statut d’erreur. Une réponse 4xx/5xx bien formée est renvoyée à l’appelant normalement (PSR-18, « Exceptions » ; épinglé dans le sidecar RAG de la page). Le pont inspecte donc lui-même le statut, le type et la signature plutôt que de supposer qu’une réponse renvoyée est une réponse réussie. La sémantique HTTP d’une violation de contrainte de type de contenu — un rejet 415 (Unsupported Media Type), lorsqu’un serveur refuse un contenu dans un format non pris en charge — est le modèle que reproduit le contrôle entrant (RFC 9110 §15.5.16 ; épinglé dans le sidecar RAG de la page).
Limites de ressources
Section intitulée « Limites de ressources »La seule limite de ressource appliquée dans le processus est maxFileSize (52 428 800 octets par défaut = 50 Mio), appliquée avant la requête, de sorte qu’une entrée surdimensionnée n’atteint jamais le service. Le pont ne comporte pas de limite de concurrence, de limite de débit ni de plafond intégré pour la taille de sortie. Ce sont des responsabilités du déploiement et de l’appelant (voir /integrations/gotenberg/production-usage/). Règle maxFileSize à la plus petite valeur qu’exigent tes documents réels — un plafond plus strict est un contrôle anti-déni de service moins coûteux.
Déployer et sécuriser le service Gotenberg
Section intitulée « Déployer et sécuriser le service Gotenberg »Le pont n’est jamais plus sûr que le service qu’il appelle. C’est à toi d’exploiter le service ; les obligations ci-dessous complètent les contrôles ci-dessus.
- Termine le TLS devant Gotenberg. Le conteneur de Gotenberg parle HTTP en clair par défaut. Le pont exige HTTPS ; place donc Gotenberg derrière un proxy inverse, un ingress ou un maillage de services qui termine le TLS, et fais pointer le pont vers le point de terminaison HTTPS. Épingle le SPKI du proxy si tu actives l’épinglage.
- N’expose pas Gotenberg publiquement. Il effectue la conversion de documents avec des moteurs de la classe LibreOffice et Chromium et n’est pas un service à exposer à internet. Restreins l’accès entrant aux hôtes applicatifs qui l’appellent, par politique réseau ou pare-feu.
- Exige une authentification sur le chemin. Le pont envoie un jeton porteur lorsqu’il est configuré ; impose-le (ou un TLS mutuel) au niveau du proxy afin qu’une requête non authentifiée ne puisse pas atteindre le moteur de conversion.
- Épingle une version précise du service. Le pont suppose exactement deux chemins de service —
/forms/libreoffice/convertet/health. Épingle l’image Gotenberg sur un tag de correctif précis, vérifie ces deux chemins par rapport à la version que tu déploies, et revérifie à chaque montée de version. - Dimensionne délibérément la capacité de conversion. Chaque conversion mobilise un worker pendant toute la durée de la requête. Dimensionne le déploiement Gotenberg pour ton pic de conversions simultanées attendu et borne les conversions en cours côté appelant en conséquence. La capacité est une propriété de ton déploiement, pas de ce paquet.
- Considère les entrées de conversion comme non fiables. Les documents envoyés en conversion sont traités par des moteurs complexes. Restreins
maxFileSize, isole le déploiement Gotenberg (son propre segment réseau, une sortie minimale, aucun accès aux services internes) et maintiens le moteur à jour avec ses correctifs.
Ce que ce paquet ne prétend pas
Section intitulée « Ce que ce paquet ne prétend pas »- Il n’est pas « sécurisé par défaut » : les contrôles sont réels mais dépendent d’un déploiement et d’une configuration corrects.
- Il ne rend pas la conversion « inviolable » ni la sortie « certifiée ». Il valide le transport et la forme de la réponse ; il n’atteste pas le contenu du document.
- Il ne fournit ni signature, ni horodatage, ni validation à long terme. Ce sont des préoccupations de post-traitement. La prise en charge PAdES de l’édition Pro se limite au profil de base B-B et n’inclut ni B-T, ni B-LT, ni B-LTA ; rien dans ce pont ne suppose une capacité d’horodatage ou de LTV.
- Il ne prend pas en charge « tous les fichiers Office ». Il prend en charge les six formats énumérés et rejette tout le reste avant toute requête.
Voir aussi
Section intitulée « Voir aussi »- /integrations/gotenberg/configuration/ — les règles de sélection du transport et le modèle de pins complet.
- /integrations/gotenberg/production-usage/ — relances, délais d’expiration, concurrence, observabilité.
- /integrations/gotenberg/troubleshooting/ — chaque exception de sécurité et son déclencheur.
- /integrations/gotenberg/overview/ — le flux de conversion et le modèle de dépendances.