Przejdź do głównej zawartości

NextPDF Gotenberg — bezpieczeństwo i eksploatacja

Ten most przesyła dokumenty z aplikacji do usługi zewnętrznej przez sieć. Dlatego jest jednocześnie powierzchnią żądań po stronie serwera i powierzchnią bezpieczeństwa transportu. Pakiet implementuje dla obu tych obszarów konkretne, weryfikowalne mechanizmy kontroli. Sam w sobie nie zabezpiecza całego systemu. Mechanizmy te działają tylko wtedy, gdy Gotenberg zostanie wdrożony i będzie eksploatowany z odpowiadającymi im zabezpieczeniami. Ta strona wyjaśnia mechanizmy kontroli implementowane przez pakiet oraz obowiązki operacyjne, które je uzupełniają.

Żaden z tych mechanizmów nie stanowi gwarancji. Każdy mechanizm kontroli to zdefiniowane, objęte testami zachowanie o określonych ograniczeniach.

Most stosuje dwie odrębne polityki bezpieczeństwa na różnych warstwach:

  • Polityka transportu (GotenbergSecurityPolicy) — wymusza schemat adresu URL, kontroluje ryzyko fałszowania żądań po stronie serwera (SSRF), chroni przed atakiem DNS rebinding (Domain Name System), ogranicza rozmiar danych wejściowych oraz kontroluje nazwy plików. To właśnie ta warstwa została szczegółowo opisana poniżej.
  • Polityka analizy HTML — polityka treści na warstwie analizy składniowej, domyślnie ustawiona na domyślną politykę rdzenia NextPDF, która działa, zanim treść dotrze do mechanizmu renderowania. Uzupełnia ona politykę transportu, ale pozostaje od niej niezależna. Ta strona dotyczy polityki transportu.

Kontrola pod kątem fałszowania żądań po stronie serwera (SSRF)

Dział zatytułowany „Kontrola pod kątem fałszowania żądań po stronie serwera (SSRF)”

Most sprawdza skonfigurowany adres URL interfejsu API, zanim jakikolwiek bajt opuści proces. Mechanizm kontroli składa się z trzech elementów.

Wymuszanie schematu. Akceptowany jest wyłącznie https (bez rozróżniania wielkości liter). Zwykły adres URL http:// jest odrzucany. Protokół Transport Layer Security (TLS) jest zatem obowiązkowy dla każdej konwersji oraz dla sondy kondycji.

Kontrola adresów. Jeśli host jest literałem IP, most odrzuca go, gdy należy do zakresu prywatnego lub zarezerwowanego. Jeśli host jest nazwą, most rozwiązuje ją na wszystkie jej rekordy A i AAAA oraz odrzuca żądanie, jeśli którykolwiek rozwiązany adres jest prywatny lub zarezerwowany. Rozwiązywanie pełnego zestawu rekordów zamiast pojedynczego adresu udaremnia działanie atakującego, który ukrywa adres prywatny za nazwą zwracającą również adres publiczny. Jest to zgodne z podejściem zalecanym w wytycznych OWASP dotyczących zapobiegania SSRF: pobierz każdy adres IP kryjący się za nazwą domeny (rekordy A i AAAA, dla IPv4 i IPv6) i zweryfikuj każdy z nich względem listy dozwolonych (OWASP Cheat Sheet Series, zapobieganie SSRF, obrona w warstwie aplikacji; przypięte w przylegającym do strony zasobie generowania wspomaganego wyszukiwaniem (RAG)).

Ponowna kontrola czasu sprawdzenia względem czasu użycia (TOCTOU). Bezpośrednio przed żądaniem most ponownie rozwiązuje nazwę i porównuje wynik z zestawem adresów zarejestrowanym podczas walidacji. Jeśli pojawi się nowy adres, żądanie jest przerywane z błędem DNS rebinding. Zamyka to okno między walidacją a połączeniem, które w przeciwnym razie mógłby wykorzystać atak typu rebinding.

Gdy most korzysta z własnego transportu z przypiętym cURL, zweryfikowany zestaw adresów jest wiązany z połączeniem za pomocą CURLOPT_RESOLVE, dzięki czemu jądro łączy się ze sprawdzonym adresem, a nie z tym, co mogłoby zwrócić nowe zapytanie DNS wykonane w chwili nawiązywania połączenia. Podążanie za przekierowaniami jest w tym transporcie wyłączone (CURLOPT_FOLLOWLOCATION wyłączone, CURLOPT_MAXREDIRS równe zero), więc odpowiedź 3xx nie może po cichu skierować żądania do niesprawdzonego hosta. Zamiast tego odpowiedź trafia do warstwy polityki.

Konsekwencja operacyjna. Zabezpieczenie SSRF z założenia odrzuca adresy prywatne i zarezerwowane. Jeśli Gotenberg działa w sieci prywatnej, nie można skierować mostu na jego adres prywatny. Udostępnij go przez adres akceptowany przez zabezpieczenie i chroń tę ścieżkę za pomocą segmentacji sieci oraz uwierzytelniania, zgodnie z opisem w sekcji o wdrażaniu poniżej.

Bezpieczeństwo transportu i przypinanie klucza publicznego

Dział zatytułowany „Bezpieczeństwo transportu i przypinanie klucza publicznego”

Weryfikacja peera i hosta TLS jest w transporcie z przypiętym cURL zawsze włączona (CURLOPT_SSL_VERIFYPEER true, CURLOPT_SSL_VERIFYHOST 2). Oprócz standardowej walidacji łańcucha most obsługuje przypinanie SubjectPublicKeyInfo (SPKI).

Każdy pin to skrót SHA-256 pola SubjectPublicKeyInfo serwera, zapisany jako sha256/<base64>. Most akceptuje certyfikat, gdy jego skrót SPKI pasuje do dowolnego pinu w połączonym zestawie podstawowym i zapasowym. Ten model pinu zapasowego jest zgodny z RFC 7469 §4.3, który wskazuje pin zapasowy — odcisk pomocniczej, jeszcze niewdrożonej pary kluczy — jako podstawową ścieżkę odtworzenia po przypadkowym niepowodzeniu walidacji pinu, oraz z §2.5, który wymaga, aby przypięty zestaw zawierał co najmniej jeden pin nieobecny w bieżącym łańcuchu certyfikatów (RFC 7469 §4.3 i §2.5; przypięte w przylegającym do strony zasobie RAG). Kod mostu odwołuje się do RFC 7469 §2.1 i §2.6 w kontekście semantyki co najmniej jednego pinu zapasowego oraz przecięcia połączonego zestawu. Przypinanie jest opcjonalne: gdy nie skonfigurowano żadnych pinów, obowiązuje standardowa walidacja łańcucha, a przypinanie nie jest wymuszane.

Pin, którego nie można sparsować, wywołuje błąd konfiguracji przed jakimkolwiek żądaniem. Jeśli SPKI aktywnego certyfikatu nie pasuje do żadnego skonfigurowanego pinu, transport odrzuca żądanie — zgodnie z założeniem.

Nieprawidłowa rotacja blokuje mostowi dostęp do usługi. Przeprowadź rotację bez przestoju:

  1. Przed zmianą klucza serwera wygeneruj pin SPKI dla nowego klucza i dodaj go do listy pinów zapasowych. Wdróż tę konfigurację. Most akceptuje teraz zarówno bieżący, jak i przyszły klucz.
  2. Zmień certyfikat lub klucz serwera tak, aby używał nowego klucza.
  3. Potwierdź, że konwersje nadal kończą się powodzeniem (nowy klucz pasuje teraz do pinu zapasowego).
  4. Przenieś nowy pin z listy zapasowej na listę podstawową i usuń pin wycofanego klucza. Wdróż.
  5. Wygeneruj i przygotuj pin dla następnej rotacji jako nowy pin zapasowy, aby zestaw zawsze zawierał użyteczną rezerwę.

Utrzymywanie listy zapasowej oddzielnie od listy podstawowej pozwala przygotować i zweryfikować następny pin bez zakłócania aktywnego.

Gdy apiKey nie jest pusty, most wysyła go jako nagłówek Authorization: Bearer w żądaniu konwersji. Pole jest oznaczone jako #[\SensitiveParameter], dzięki czemu jego wartość jest ukrywana w śladach stosu. Most nie wczytuje sekretu za Ciebie; dostarcz go z menedżera sekretów podczas uruchamiania procesu i nigdy nie umieszczaj go w repozytorium. Token nie jest zapisywany w dzienniku żądań — zapisany wpis debugowania zawiera wyłącznie adres URL, nazwę pliku, format oraz długość treści.

Odpowiedź jest akceptowana wyłącznie wtedy, gdy status wynosi 200, nagłówek Content-Type zawiera application/pdf, a treść zaczyna się sygnaturą %PDF. Kontrola sygnatury bajtowej ma znaczenie, ponieważ sam zadeklarowany typ treści nie dowodzi, czym faktycznie są bajty. Standard WHATWG MIME Sniffing formalizuje to samo rozumowanie w algorytmie wykrywania typu MIME, który wyprowadza obliczony typ z dopasowania początkowych wzorców bajtów, a nie z dostarczonego typu. Wytyczne OWASP dotyczące przesyłania plików formułują odpowiadającą temu zasadę aplikacyjną: zweryfikuj typ pliku i nie ufaj zadeklarowanemu nagłówkowi Content-Type, ponieważ można go sfałszować (WHATWG MIME Sniffing §6.2.3; OWASP Cheat Sheet Series, walidacja przesyłania plików; oba przypięte w przylegającym do strony zasobie RAG). Most stosuje równoważną kontrolę defensywną po stronie przychodzącej: niezgodność wywołuje typowany wyjątek, a bajty nigdy nie są zwracane jako wynik.

Ta granica jest również powodem, dla którego kontrakt PSR-18 ma tu znaczenie. Klient PSR-18 zgłasza wyjątek wyłącznie wtedy, gdy nie może wysłać żądania lub nie może sparsować odpowiedzi do obiektu PSR-7 — nie zgłasza wyjątku dla kodu statusu błędu. Poprawnie sformułowana odpowiedź 4xx/5xx jest zwracana wywołującemu w normalny sposób (PSR-18, „Exceptions”; przypięte w przylegającym do strony zasobie RAG). Dlatego most sam sprawdza status, typ i sygnaturę, zamiast zakładać, że zwrócona odpowiedź oznacza powodzenie. Semantyka HTTP dla naruszenia ograniczenia content-type — odrzucenie 415 (Unsupported Media Type), gdy serwer odmawia przyjęcia treści w nieobsługiwanym formacie — jest modelem odwzorowywanym przez kontrolę przychodzącą (RFC 9110 §15.5.16; przypięte w przylegającym do strony zasobie RAG).

Most ma jedno ograniczenie zasobów w obrębie procesu: maxFileSize (domyślnie 52 428 800 bajtów = 50 MiB). Jest ono wymuszane przed żądaniem, więc nadmiernie duże dane wejściowe nigdy nie docierają do usługi. Most nie ma wbudowanego limitu współbieżności, limitu przepustowości ani górnego pułapu rozmiaru danych wyjściowych. Są to obowiązki wdrożenia i wywołującego (zobacz /integrations/gotenberg/production-usage/). Ustaw maxFileSize na najmniejszą wartość, jakiej wymagają rzeczywiste dokumenty — ściślejszy limit to tańszy mechanizm kontroli przed atakami typu odmowa usługi.

Most jest tylko tak bezpieczny, jak usługa, którą wywołuje. To Ty eksploatujesz tę usługę; obowiązki wymienione poniżej uzupełniają mechanizmy kontroli opisane wyżej.

  • Zakończ połączenie TLS przed Gotenberg. Kontener Gotenberg domyślnie komunikuje się przez zwykły HTTP. Most wymaga HTTPS, dlatego umieść Gotenberg za odwrotnym serwerem proxy kończącym TLS, kontrolerem ingress lub siatką usług i skieruj most na punkt końcowy HTTPS. Jeśli włączysz przypinanie, przypnij SPKI serwera proxy.
  • Nie udostępniaj Gotenberg publicznie. Wykonuje konwersję dokumentów za pomocą mechanizmów klasy LibreOffice i Chromium i nie jest usługą przeznaczoną do wystawienia do internetu. Ogranicz ruch przychodzący do hostów aplikacji, które ją wywołują, korzystając z polityki sieciowej lub reguł zapory.
  • Wymagaj uwierzytelniania na tej ścieżce. Most wysyła token bearer, gdy jest skonfigurowany; wymuś go (lub wzajemne TLS) na serwerze proxy, aby nieuwierzytelnione żądanie nie mogło dotrzeć do mechanizmu konwersji.
  • Przypnij konkretną wersję usługi. Most zakłada dokładnie dwie ścieżki usługi — /forms/libreoffice/convert oraz /health. Przypnij obraz Gotenberg do konkretnego znacznika poprawki, zweryfikuj te dwie ścieżki względem wdrażanej wersji i weryfikuj je ponownie przy każdej aktualizacji.
  • Świadomie wymiaruj przepustowość konwersji. Każda konwersja zajmuje proces roboczy na czas trwania żądania. Wymiaruj wdrożenie Gotenberg pod kątem szczytowej liczby równoczesnych konwersji i odpowiednio ogranicz liczbę trwających konwersji po stronie wywołującego. Przepustowość jest właściwością Twojego wdrożenia, a nie tego pakietu.
  • Traktuj dane wejściowe konwersji jako niezaufane. Dokumenty przepuszczane przez konwersję są przetwarzane przez rozbudowane mechanizmy. Ogranicz maxFileSize, odizoluj wdrożenie Gotenberg (własny segment sieci, minimalny ruch wychodzący, brak dostępu do usług wewnętrznych) i na bieżąco instaluj poprawki mechanizmu.
  • Nie jest „bezpieczny domyślnie”: mechanizmy kontroli są rzeczywiste, lecz zależą od poprawnego wdrożenia i konfiguracji.
  • Nie czyni konwersji „odporną na manipulacje” ani danych wyjściowych „certyfikowanymi”. Waliduje transport i kształt odpowiedzi; nie poświadcza treści dokumentu.
  • Nie zapewnia podpisywania, znakowania czasem ani walidacji długoterminowej. To zagadnienia związane z przetwarzaniem końcowym. Obsługa PAdES w edycji Pro obejmuje wyłącznie poziom bazowy B-B i nie obejmuje B-T, B-LT ani B-LTA; nic w tym moście nie sugeruje funkcji znacznika czasu ani LTV.
  • Nie obsługuje „wszystkich plików Office”. Obsługuje sześć wymienionych formatów i odrzuca wszystko pozostałe przed jakimkolwiek żądaniem.
  • /integrations/gotenberg/configuration/ — reguły wyboru transportu i pełny model pinów.
  • /integrations/gotenberg/production-usage/ — ponawianie prób, limity czasu, współbieżność i obserwowalność.
  • /integrations/gotenberg/troubleshooting/ — każdy wyjątek bezpieczeństwa i jego przyczyna.
  • /integrations/gotenberg/overview/ — przepływ konwersji i model zależności.