Zum Inhalt springen

NextPDF Gotenberg: Sicherheit und Betrieb

Diese Bridge sendet Dokumente, die Ihre Anwendung vorhält, über das Netzwerk an einen externen Dienst. Dadurch entsteht sowohl eine serverseitige Anfragefläche als auch eine Transport-Sicherheitsfläche. Das Paket implementiert für beide Flächen konkrete, überprüfbare Kontrollen. Allein macht es das System nicht sicher. Die Kontrollen greifen nur in Kombination mit der Art, wie Sie den Gotenberg-Dienst bereitstellen und betreiben. Diese Seite beschreibt die implementierten Kontrollen und die betrieblichen Pflichten, die sie vervollständigen.

Keine der Kontrollen wird hier als Garantie dargestellt. Jede ist ein definiertes, durch Tests abgedecktes Verhalten mit klar benannten Grenzen.

Die Bridge hat zwei eigenständige Sicherheitsrichtlinien, die auf unterschiedlichen Ebenen greifen:

  • Transportrichtlinie (GotenbergSecurityPolicy) — Durchsetzung des URL-Schemas, Prüfung auf Server-Side Request Forgery (SSRF), Schutz vor DNS-Rebinding, Begrenzung der Eingabegröße und Prüfung von Dateinamen. Diese Ebene wird unten ausführlich dokumentiert.
  • HTML-Parse-Richtlinie — eine Inhaltsrichtlinie auf Parse-Ebene, die standardmäßig die Standardrichtlinie des NextPDF-Kerns verwendet und angewendet wird, bevor Inhalte einen Renderer erreichen. Sie ergänzt die Transportrichtlinie und ist von ihr unabhängig. Diese Seite behandelt die Transportrichtlinie.

Die konfigurierte API-URL wird geprüft, bevor ein einziges Byte den Prozess verlässt. Die Kontrolle besteht aus drei Teilen.

Durchsetzung des Schemas. Nur https wird akzeptiert (ohne Beachtung der Groß-/Kleinschreibung). Eine unverschlüsselte http://-URL wird abgelehnt. Transport Layer Security ist daher für jede Konvertierung und für die Health-Probe verpflichtend.

Adressprüfung. Ist der Host ein IP-Literal, wird er abgelehnt, wenn er in einen privaten oder reservierten Bereich fällt. Ist der Host ein Name, werden alle zugehörigen A- und AAAA-Records aufgelöst, und die Anfrage wird abgelehnt, wenn irgendeine aufgelöste Adresse privat oder reserviert ist. Gerade das Auflösen des vollständigen Record-Satzes statt einer einzelnen Adresse wehrt einen Angreifer ab, der eine private Adresse hinter einem Namen verbirgt, der zugleich eine öffentliche Adresse zurückgibt. Dies ist der Ansatz, den die OWASP-Leitlinie zur SSRF-Prävention beschreibt: jede IP-Adresse hinter dem Domainnamen abzurufen (A- und AAAA-Records, für IPv4 und IPv6) und jede gegen eine Zulassungsliste zu prüfen (OWASP Cheat Sheet Series, SSRF-Prävention, Abwehr auf Anwendungsebene; in der RAG-Sidecar der Seite verankert).

Erneute Prüfung bei Time-of-Check/Time-of-Use (TOCTOU). Der während der Validierung erfasste Adresssatz wird unmittelbar vor der Anfrage erneut aufgelöst und verglichen. Erscheint eine neue Adresse, wird die Anfrage mit einem DNS-Rebinding-Fehler abgebrochen. Dadurch schließt sich das Zeitfenster zwischen der Validierungsprüfung und der Verbindung, das ein Rebinding-Angriff andernfalls ausnutzen würde.

Wenn die Bridge ihren cURL-gepinnten Transport verwendet, wird der validierte Adresssatz mit CURLOPT_RESOLVE an die Verbindung gebunden. Der Kernel verbindet sich dann mit der geprüften Adresse statt mit einer Adresse, die ein neuer DNS-Lookup zur Verbindungszeit zurückgeben könnte. Das Folgen von Weiterleitungen ist auf diesem Transport deaktiviert (CURLOPT_FOLLOWLOCATION aus, CURLOPT_MAXREDIRS null), sodass eine 3xx-Antwort die Anfrage nicht unbemerkt an einen ungeprüften Host senden kann. Die Antwort gelangt stattdessen an die Richtlinienebene.

Betriebliche Konsequenz. Der SSRF-Schutz lehnt private und reservierte Adressen prinzipbedingt ab. Wenn Ihre Gotenberg-Instanz in einem privaten Netzwerk läuft, können Sie die Bridge nicht auf deren private Adresse richten. Stellen Sie sie über eine Adresse bereit, die der Schutz akzeptiert, und sichern Sie diesen Pfad durch Netzwerksegmentierung und Authentifizierung, wie unten im Abschnitt „Bereitstellen und Absichern des Gotenberg-Dienstes“ beschrieben.

Die TLS-Peer- und -Host-Verifizierung ist im cURL-gepinnten Transport stets aktiviert (CURLOPT_SSL_VERIFYPEER true, CURLOPT_SSL_VERIFYHOST 2). Zusätzlich zur standardmäßigen Kettenvalidierung unterstützt die Bridge SubjectPublicKeyInfo-(SPKI-)Pinning.

Jeder Pin ist ein SHA-256-Hash der SubjectPublicKeyInfo des Servers, ausgedrückt als sha256/<base64>. Die Bridge akzeptiert ein Zertifikat, dessen SPKI-Hash mit einem beliebigen Pin im kombinierten Satz aus Primär- und Backup-Pins übereinstimmt. Dieses Backup-Pin-Modell folgt RFC 7469 §4.3, wonach ein Backup-Pin — der Fingerabdruck eines zweiten, noch nicht bereitgestellten Schlüsselpaars — der primäre Weg ist, um sich von einem versehentlichen Fehlschlagen der Pin-Validierung zu erholen, sowie §2.5, der verlangt, dass der gepinnte Satz mindestens einen Pin enthält, der nicht in der aktuellen Zertifikatskette vorhanden ist (RFC 7469 §4.3 und §2.5; in der RAG-Sidecar der Seite verankert). Der Code der Bridge deklariert RFC 7469 §2.1 und §2.6 für die Semantik des mindestens-einen-Backup-Pins und der Schnittmenge des kombinierten Satzes. Pinning ist optional: Sind keine Pins konfiguriert, gilt die standardmäßige Kettenvalidierung, und Pinning wird nicht erzwungen.

Ein nicht parsbarer Pin löst vor jeder Anfrage einen Konfigurationsfehler aus. Ein Live-Zertifikat, dessen SPKI mit keinem konfigurierten Pin übereinstimmt, führt prinzipbedingt dazu, dass der Transport die Anfrage scheitern lässt.

Eine misslungene Rotation sperrt die Bridge vom Dienst aus. Rotieren Sie ohne Ausfall:

  1. Erzeugen Sie vor dem Wechsel des Serverschlüssels den SPKI-Pin für den neuen Schlüssel und fügen Sie ihn der Backup-Pin-Liste hinzu. Stellen Sie diese Konfiguration bereit. Die Bridge akzeptiert nun sowohl den aktuellen als auch den zukünftigen Schlüssel.
  2. Wechseln Sie das Serverzertifikat oder den Schlüssel auf den neuen Schlüssel.
  3. Stellen Sie sicher, dass Konvertierungen weiterhin gelingen (der neue Schlüssel stimmt nun mit dem Backup-Pin überein).
  4. Verschieben Sie den neuen Pin von der Backup-Liste auf die Primärliste und entfernen Sie den Pin des ausgemusterten Schlüssels. Stellen Sie bereit.
  5. Erzeugen Sie den Pin für die nächste Rotation und legen Sie ihn als neuen Backup-Pin bereit, damit der Satz stets einen verwendbaren Ersatz enthält.

Wenn Sie die Backup-Liste von der Primärliste getrennt halten, können Sie den nächsten Pin bereitstellen und validieren, ohne den aktiven anzutasten.

Wenn apiKey nicht leer ist, wird er als Authorization: Bearer-Header mit der Konvertierungsanfrage gesendet. Das Feld ist mit #[\SensitiveParameter] markiert, sodass der Wert aus Stack-Traces entfernt wird. Die Bridge ruft das Geheimnis nicht für Sie ab; stellen Sie es beim Prozessstart aus einem Secret-Manager bereit und committen Sie es niemals. Das Token wird nicht in das Anfrageprotokoll geschrieben — der protokollierte Debug-Eintrag enthält nur die URL, den Dateinamen, das Format und die Inhaltslänge.

Eine Antwort wird nur akzeptiert, wenn der Status 200 ist, der Content-Type application/pdf enthält und der Body mit der %PDF-Signatur beginnt. Die Byte-Signatur-Prüfung existiert, weil ein deklarierter Inhaltstyp allein nicht belegt, welchen Typ die Bytes tatsächlich haben — derselbe Gedanke, den der WHATWG-MIME-Sniffing-Standard in seinem MIME-Typ-Sniffing-Algorithmus formalisiert, der einen berechneten Typ aus dem Abgleich führender Byte-Muster ableitet statt aus dem angegebenen Typ. Die OWASP-Leitlinie zum Datei-Upload formuliert das entsprechende Anwendungsprinzip: Validieren Sie den Dateityp und vertrauen Sie nicht dem deklarierten Content-Type-Header, da er gefälscht werden kann (WHATWG MIME Sniffing §6.2.3; OWASP Cheat Sheet Series, Datei-Upload-Validierung; beide in der RAG-Sidecar der Seite verankert). Die Bridge wendet die entsprechende Prüfung defensiv auf der eingehenden Seite an: Eine Abweichung löst eine typisierte Ausnahme aus, und die Bytes werden niemals als Ergebnis zurückgegeben.

Diese Grenze ist auch der Grund, warum der PSR-18-Vertrag hier von Bedeutung ist. Ein PSR-18-Client wirft nur dann eine Ausnahme, wenn er die Anfrage nicht senden oder die Antwort nicht in ein PSR-7-Objekt parsen kann — er wirft nicht bei einem Fehlerstatuscode. Eine wohlgeformte 4xx/5xx-Antwort wird dem Aufrufer wie üblich zurückgegeben (PSR-18, „Exceptions“; in der RAG-Sidecar der Seite verankert). Die Bridge prüft daher Status, Typ und Signatur selbst, statt anzunehmen, dass eine zurückgegebene Antwort erfolgreich ist. Die HTTP-Semantik für eine Verletzung der Content-Type-Beschränkung — eine Ablehnung mit 415 (Unsupported Media Type), bei der ein Server Inhalte in einem nicht unterstützten Format verweigert — ist das Modell, das die eingehende Prüfung nachbildet (RFC 9110 §15.5.16; in der RAG-Sidecar der Seite verankert).

Die einzige prozessinterne Ressourcengrenze ist maxFileSize (Standard 52.428.800 Bytes = 50 MiB), die vor der Anfrage durchgesetzt wird, sodass eine übergroße Eingabe den Dienst nie erreicht. Es gibt in der Bridge keine eingebaute Nebenläufigkeitsgrenze, kein Ratenlimit und keine Obergrenze für die Ausgabegröße. Das sind Aufgaben der Bereitstellung und des Aufrufers (siehe /integrations/gotenberg/production-usage/). Setzen Sie maxFileSize auf den kleinsten Wert, den Ihre tatsächlichen Dokumente erfordern — eine engere Obergrenze ist eine kostengünstigere Denial-of-Service-Kontrolle.

Bereitstellen und Absichern des Gotenberg-Dienstes

Abschnitt betitelt „Bereitstellen und Absichern des Gotenberg-Dienstes“

Die Bridge ist nur so sicher wie der Dienst, den sie aufruft. Der Dienst liegt in Ihrer Betriebsverantwortung; die folgenden Pflichten vervollständigen die oben beschriebenen Kontrollen.

  • Terminieren Sie TLS vor Gotenberg. Der Container von Gotenberg spricht standardmäßig unverschlüsseltes HTTP. Die Bridge erfordert HTTPS; platzieren Sie Gotenberg daher hinter einem TLS-terminierenden Reverse-Proxy, Ingress oder Service-Mesh und richten Sie die Bridge auf den HTTPS-Endpunkt. Pinnen Sie das SPKI des Proxys, wenn Sie Pinning aktivieren.
  • Stellen Sie Gotenberg nicht öffentlich bereit. Es führt Dokumentkonvertierung mit LibreOffice- und Chromium-artigen Engines durch und ist kein für das Internet exponierter Dienst. Beschränken Sie den eingehenden Verkehr per Netzwerkrichtlinie oder Firewall auf die Anwendungshosts, die es aufrufen.
  • Verlangen Sie Authentifizierung auf dem Pfad. Die Bridge sendet ein Bearer-Token, wenn konfiguriert; erzwingen Sie es (oder gegenseitiges TLS) am Proxy, damit eine nicht authentifizierte Anfrage die Konvertierungs-Engine nicht erreichen kann.
  • Pinnen Sie eine bestimmte Dienstversion. Die Bridge nimmt genau zwei Dienstpfade an — /forms/libreoffice/convert und /health. Pinnen Sie das Gotenberg-Image auf ein bestimmtes Patch-Tag, verifizieren Sie diese beiden Pfade für die von Ihnen bereitgestellte Version und verifizieren Sie sie bei jedem Upgrade erneut.
  • Bemessen Sie die Konvertierungskapazität bewusst. Jede Konvertierung belegt einen Worker für die Dauer der Anfrage. Bemessen Sie die Gotenberg-Bereitstellung für Ihre maximale gleichzeitige Konvertierungsrate und begrenzen Sie die laufenden Konvertierungen auf Aufruferseite entsprechend. Die Kapazität ist eine Eigenschaft Ihrer Bereitstellung, nicht dieses Pakets.
  • Behandeln Sie Konvertierungseingaben als nicht vertrauenswürdig. Dokumente, die zur Konvertierung übergeben werden, werden von komplexen Engines verarbeitet. Begrenzen Sie maxFileSize, isolieren Sie die Gotenberg-Bereitstellung (eigenes Netzwerksegment, minimaler Egress, kein Zugriff auf interne Dienste) und halten Sie die Engine gepatcht.
  • Es ist nicht „standardmäßig sicher“: Die Kontrollen sind real, aber sie hängen von korrekter Bereitstellung und Konfiguration ab.
  • Es macht die Konvertierung nicht „manipulationssicher“ oder die Ausgabe „zertifiziert“. Es validiert den Transport und die Struktur der Antwort; es bezeugt nicht den Dokumentinhalt.
  • Es bietet keine Signierung, kein Zeitstempeln und keine Langzeitvalidierung. Das sind Belange der Nachverarbeitung. Die PAdES-Unterstützung der Pro-Edition ist ausschließlich die Baseline B-B und umfasst nicht B-T, B-LT oder B-LTA; nichts in dieser Bridge impliziert eine Zeitstempel- oder LTV-Fähigkeit.
  • Es unterstützt nicht „alle Office-Dateien“. Es unterstützt die sechs aufgezählten Formate und lehnt alles andere vor jeder Anfrage ab.
  • /integrations/gotenberg/configuration/ — die Regeln zur Transportauswahl und das vollständige Pin-Modell.
  • /integrations/gotenberg/production-usage/ — Wiederholungen, Timeouts, Nebenläufigkeit, Observability.
  • /integrations/gotenberg/troubleshooting/ — jede Sicherheitsausnahme und ihr Auslöser.
  • /integrations/gotenberg/overview/ — der Konvertierungsfluss und das Abhängigkeitsmodell.