跳转到内容

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。 它会用 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/ —— 转换流程与依赖模型。