跳到內容

NextPDF Gotenberg 的安全性與維運

此橋接器會透過網路,將你的應用程式持有的文件傳送到外部服務。因此,它同時形成伺服器端請求面與傳輸安全面。此套件在這兩個面向都實作了具體且可驗證的控制,但光靠套件本身並不會讓系統變得安全。這些控制必須搭配你部署與維運 Gotenberg 服務的方式,才能發揮效果。本頁說明已實作的控制,以及用來補足這些控制的維運職責。

此處沒有任何控制被描述為保證。每一項都是界限明確、並由測試涵蓋的既定行為。

此橋接器具備兩個不同的安全政策,且分別運作於不同層級:

  • 傳輸政策GotenbergSecurityPolicy)—— URL scheme 強制、伺服器端請求偽造(SSRF)篩查、DNS 重新繫結防禦、輸入大小限制,以及檔名篩查。下文深入說明的是這一層。
  • HTML 解析政策 —— 解析層級的內容政策,預設採用 NextPDF 核心的預設政策,會在內容抵達轉譯器之前先行套用。它與傳輸政策互補,且彼此獨立。本頁討論的是傳輸政策。

在任何位元組離開行程前,已設定的 API URL 都會先經過篩查。此控制分為三個部分。

Scheme 強制。 只接受 https(不分大小寫)。純 http:// URL 會被拒絕。因此,每次轉換與健康探測都必須使用 Transport Layer Security。

位址篩查。 若主機是 IP 字面值,只要它落在私有或保留範圍內,就會被拒絕。若主機是名稱,則會解析出它所有的 A 與 AAAA 記錄;只要任何一個解析出的位址屬於私有或保留位址,請求就會被拒絕。解析完整的記錄集合(而不是單一位址),正是用來擊敗攻擊者的控制:攻擊者會把私有位址藏在一個也會回傳公開位址的名稱背後。這正是 OWASP SSRF 防護指引所描述的作法:取得網域名稱背後的每一個 IP 位址(A 與 AAAA 記錄,涵蓋 IPv4 與 IPv6),並逐一比對允許清單(OWASP Cheat Sheet Series,SSRF prevention,應用層防禦;釘選於本頁的 RAG sidecar)。

檢查時點/使用時點(TOCTOU)重新檢查。 在驗證期間擷取的位址集合,會在請求發出前的瞬間重新解析並再次比對。若出現新的位址,請求會以 DNS 重新繫結錯誤中止。這道控制關閉了驗證檢查與連線之間的時間窗;否則重新繫結攻擊正是利用這個時間窗。

當橋接器使用本身的 cURL 釘選傳輸時,會以 CURLOPT_RESOLVE 把已驗證的位址集合繫結到連線上,讓底層連線連往經過審核的位址,而不是連線當下重新進行 DNS 查詢可能回傳的任何位址。該傳輸已停用重新導向追蹤(CURLOPT_FOLLOWLOCATION 關閉、CURLOPT_MAXREDIRS 為零),因此 3xx 無法悄悄把請求送往未經審核的主機。回應會改為浮現至政策層。

維運上的後果。 SSRF 防護依設計會拒絕私有與保留位址。若你的 Gotenberg 執行於私有網路上,你便無法把橋接器指向它的私有位址。請改透過防護機制可接受的位址公開它,並以網路分段與身分驗證保護該路徑;做法詳見下方的部署說明。

在 cURL 釘選傳輸中,TLS 對端與主機驗證一律開啟(CURLOPT_SSL_VERIFYPEER 為 true、CURLOPT_SSL_VERIFYHOST 為 2)。在標準憑證鏈驗證之上,橋接器支援 SubjectPublicKeyInfo(SPKI)釘選。

每個釘選都是伺服器 SubjectPublicKeyInfo 的 SHA-256 雜湊,以 sha256/<base64> 表示。只要憑證的 SPKI 雜湊比對到主要釘選與備援釘選合併集合中的任一釘選,橋接器就會接受該憑證。此備援釘選模型遵循 RFC 7469 §4.3,該節將備援釘選 —— 一組尚未部署的次要金鑰對指紋 —— 認定為從非預期釘選驗證失敗中復原的主要方式;並遵循 §2.5,該節要求釘選集合至少包含一個不存在於目前憑證鏈中的釘選(RFC 7469 §4.3 與 §2.5;釘選於本頁的 RAG sidecar)。橋接器的程式碼針對「至少一個備援釘選」與「合併集合交集」語意,宣告了 RFC 7469 §2.1 與 §2.6。釘選採選擇性啟用:在未設定任何釘選時,套用標準憑證鏈驗證,且不強制執行釘選。

無法解析的釘選會在任何請求之前引發設定錯誤。若實際憑證的 SPKI 未比對到任何已設定的釘選,傳輸會讓該請求失敗;這是刻意設計的行為。

一次失敗的輪替會使橋接器被擋在服務之外。若要不中斷地進行輪替:

  1. 在更換伺服器金鑰之前,先為金鑰產生 SPKI 釘選,並將其加入備援釘選清單。部署該設定。橋接器此時會同時接受目前金鑰與未來金鑰。
  2. 將伺服器憑證或金鑰輪替到新金鑰。
  3. 確認轉換仍然成功(新金鑰此時會比對到備援釘選)。
  4. 將新釘選從備援清單移到主要清單,並移除已退役金鑰的釘選。部署。
  5. 下一次輪替產生並備妥釘選作為新的備援,讓該集合始終保有一個可用的備援釘選。

將備援清單與主要清單分開,能讓你在不動到使用中釘選的情況下,備妥並驗證下一個釘選。

apiKey 非空時,橋接器會在轉換請求中以 Authorization: Bearer 標頭送出此值。此欄位標記為 #[\SensitiveParameter],因此其值會在堆疊追蹤中被遮蔽。橋接器不會替你取得此密鑰;請在行程啟動時從密鑰管理器提供它,且絕不要將它提交到版控。此權杖不會寫入請求日誌;記錄的除錯項目僅包含 URL、檔名、格式與內容長度。

唯有狀態為 200Content-Type 含有 application/pdf、且主體以 %PDF 簽名開頭時,回應才會被接受。這道位元組簽名檢查之所以存在,是因為僅憑宣告的內容類型,無法確立這些位元組究竟是什麼。這與 WHATWG MIME Sniffing 標準在 MIME 類型嗅探演算法中形式化的推理相同:該演算法會依據開頭位元組樣式的比對,推導出運算得出的類型,而不是依據所提供的類型。OWASP 檔案上傳指引陳述了對應的應用層原則:驗證檔案類型,且不要信任所宣告的 Content-Type 標頭,因為它可被偽造(WHATWG MIME Sniffing §6.2.3;OWASP Cheat Sheet Series,檔案上傳驗證;兩者皆釘選於本頁的 RAG sidecar)。橋接器在入站側以防禦性方式套用等效檢查:不相符時會引發具型別的例外,且那些位元組永遠不會被當作結果回傳。

這道邊界也說明了 PSR-18 契約為何在此處重要。PSR-18 用戶端只有在無法送出請求,或無法將回應解析成 PSR-7 物件時才會擲出例外;它不會因為錯誤狀態碼而擲出例外。格式正確的 4xx/5xx 回應會照常回傳給呼叫端(PSR-18,「Exceptions」;釘選於本頁的 RAG sidecar)。因此,橋接器會自行檢視狀態、類型與簽名,而不是把被回傳的回應假定為成功回應。content-type 約束違反對應的 HTTP 語意,正是入站檢查所採用的模型:415(Unsupported Media Type)拒絕,其中伺服器會拒絕不受支援格式的內容(RFC 9110 §15.5.16;釘選於本頁的 RAG sidecar)。

行程內唯一的資源限制是 maxFileSize(預設 52,428,800 位元組 = 50 MiB),會在請求之前強制執行,因此過大的輸入永遠不會抵達服務。橋接器內並沒有內建的並行數限制、速率限制或輸出大小上限。這些屬於部署與呼叫端的職責(請見 /integrations/gotenberg/production-usage/)。請將 maxFileSize 設為你的實際文件所需的最小值;越緊的上限,就是越低成本的阻斷服務控制。

橋接器的安全程度,只能延伸到它所呼叫的那個服務。該服務由你維運;下列職責用來補足上述控制。

  • 在 Gotenberg 前方終結 TLS。 Gotenberg 的容器預設使用純 HTTP 通訊。橋接器要求 HTTPS,因此請把 Gotenberg 置於終結 TLS 的反向代理、ingress 或服務網格之後,並把橋接器指向該 HTTPS 端點。若你啟用釘選,請釘選該代理的 SPKI。
  • 不要公開暴露 Gotenberg。 Gotenberg 以 LibreOffice 與 Chromium 這類引擎執行文件轉換,並非面向網際網路的服務。請使用網路政策或防火牆,將入站流量限制為會呼叫它的應用程式主機。
  • 在該路徑上要求身分驗證。 橋接器在設定後會送出 bearer 權杖;請在代理上強制驗證它(或採用雙向 TLS),使未經驗證的請求無法觸及轉換引擎。
  • 釘選特定的服務版本。 橋接器假設恰好有兩條服務路徑 —— /forms/libreoffice/convert/health。請將 Gotenberg 映像釘選到特定的修補標籤,對照你部署的版本驗證這兩條路徑,並在每次升級時重新驗證。
  • 刻意規劃轉換容量。 每一次轉換都會在請求期間占用一個工作者。請依你的尖峰並行轉換速率來規劃 Gotenberg 部署的規模,並在呼叫端相應地約束進行中的轉換數量。容量是你部署的屬性,而非此套件的屬性。
  • 將轉換輸入視為不受信任。 送進轉換流程的文件會由複雜的引擎處理。請約束 maxFileSize、隔離 Gotenberg 部署(讓它有自己的網路分段、最小化出向流量、無法存取內部服務),並讓引擎持續套用修補更新。
  • 它並非「預設安全」:這些控制確實存在,但它們取決於正確的部署與設定。
  • 它不會讓轉換變得「防竄改」或讓輸出變得「經認證」。它驗證的是傳輸與回應的形態;它並不對文件內容進行證明。
  • 它不提供簽署、時間戳記或長期驗證。那些屬於後處理層面的事項。Pro 版的 PAdES 支援僅為 B-B 基準,並不包含 B-T、B-LT 或 B-LTA;此橋接器中沒有任何內容暗示具備時間戳記或 LTV 能力。
  • 它並不支援「所有 Office 檔案」。它支援所列舉的六種格式,並在任何請求之前拒絕其餘一切。
  • /integrations/gotenberg/configuration/ —— 傳輸選擇規則與完整的釘選模型。
  • /integrations/gotenberg/production-usage/ —— 重試、逾時、並行、可觀測性。
  • /integrations/gotenberg/troubleshooting/ —— 每一個安全例外及其觸發條件。
  • /integrations/gotenberg/overview/ —— 轉換流程與相依模型。