NextPDF Laravel 套件的安全性與維運
本套件會套用固定的回應標頭集、清理下載檔名、在 worker 端驗證佇列輸出路徑,並透過具備請求偽造防護的用戶端,包裝連往時間戳記憑證機構的 HTTP 連線。本頁說明威脅模型,以及各項控制措施所需的部署設定。
composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-config概念總覽
標題為「概念總覽」的區段本套件會將 PDF 引擎接入 Web Framework(框架)。信任邊界是 HTTP 請求與佇列傳輸。以下控制措施涵蓋回應處理、反序列化後的 job 負載,以及對外連往時間戳記憑證機構的 HTTP 連線。
API 介面 — 威脅模型
標題為「API 介面 — 威脅模型」的區段| 資產 | 威脅 | 本套件中的控制措施 | 所需的部署設定 |
|---|---|---|---|
| PDF HTTP 回應 | 內容類型嗅探、點擊劫持、被搜尋引擎建立 Index(索引) | 每個 PdfResponse 工廠都會設定固定的標頭集 | 無;標頭不可設定 |
| 下載檔名 | 標頭注入、Content-Disposition 中的路徑遍歷 | 檔名清理器會移除分隔字元、控制字元與 null 位元組 | 無;清理器一律會執行 |
| 佇列 job 輸出路徑 | 透過竄改後的序列化負載寫入任意檔案 | 在 worker 上的 handle() 中驗證路徑 | 把輸出導向受控制的儲存路徑 |
| 對外的 TSA HTTP 連線 | 伺服器端請求偽造、明文竄改 | 具備請求偽造防護的 HTTP 用戶端;除非明確放寬,否則強制使用 HTTPS | 保持 tsa.allow_insecure_http = false;釘選 SPKI |
| 共用的 worker 狀態 | 長存 worker 中的跨請求狀態外洩 | 鎖定的字型登錄;有界限的影像快取;綁定至工廠的 document | 設定 preload_fonts;在容器層設定記憶體上限 |
回應強化
標題為「回應強化」的區段每個 PdfResponse 工廠都會設定一組固定的標頭集:
Cache-Control: private, max-age=0, must-revalidatePragma: publicX-Content-Type-Options: nosniffX-Frame-Options: DENYContent-Security-Policy: default-src 'none'X-Robots-Tag: noindex, nofollowReferrer-Policy: no-referrer
這些值是 PdfResponse 中的常數,且不可設定。本套件的測試套件會針對每個工廠方法斷言所有標頭,包含串流變體。
下載檔名寫入 Content-Disposition 標頭前,會先經過清理器。清理器會移除路徑分隔字元、控制字元與 null 位元組,並針對非 ASCII 名稱輸出一個 RFC 5987 filename*= 參數。空白檔名會變成 document.pdf。
佇列負載驗證
標題為「佇列負載驗證」的區段GeneratePdfJob 會把一個閉包序列化到佇列傳輸上。輸出路徑是在 worker 端的 handle() 內驗證,而非在派送時。驗證會拒絕:
- 路徑中的 null 位元組、
- stream-wrapper 結構描述(例如
php://)、 ..路徑遍歷片段、- 任何未以
.pdf結尾的路徑(不分大小寫)。
每一次拒絕都會引發 InvalidArgumentException。驗證會在實際使用該值時執行。Redis 或資料庫傳輸中的序列化負載,可能在 worker 讀取前被竄改。請把輸出路徑導向受控制的儲存目錄;不要從未經驗證的請求輸入推導出該路徑。
對外連到時間戳記憑證機構的 HTTP 連線
標題為「對外連到時間戳記憑證機構的 HTTP 連線」的區段設定時間戳記憑證機構時,本套件會綁定一個 PSR-18 Psr\Http\Client\ClientInterface。PSR-18 用戶端會送出 PSR-7 請求並回傳 PSR-7 回應(PSR-18 §2)。綁定的用戶端會以具備請求偽造防護的層,包裝以 curl 為基礎的用戶端;除非 tsa.allow_insecure_http 明確為 true,否則強制使用 HTTPS。
時間戳記憑證機構屬於 Premium 等級能力。本頁所記載的 Core 套件負責綁定 HTTP 用戶端與時間戳記用戶端的接線;簽章本身需要 nextpdf/premium。本頁不記載 PAdES 在 B-B 以外的基準行為;更高的基準不在範圍內。
時間戳記憑證機構的維運指引:
- 在正式環境中,讓
tsa.allow_insecure_http維持為false。 - 把
tsa.pinned_public_keys設為時間戳記憑證機構憑證的 base64 SHA-256 SPKI 雜湊值(RFC 7469 形式)。 - 讓
tsa.warn_on_key_rotation維持為true,如此一來,在釘選憑證過期前,變更後的 SPKI 就會被記錄下來。 - 請僅從受信任的設定取得
tsa.url。若操作人員可以從管理介面設定它,請套用對外流量防火牆或 DNS 政策,以降低請求偽造的暴露面。
使用 Psr\Log\LoggerInterface 進行診斷。請傳入結構化的內容,而非經插值的字串。PSR-3 將 placeholder(佔位符)的逸出交由記錄器實作處理,並指示呼叫端不要預先逸出內容值(PSR-3 §1.2)。請記錄例外類別,而非訊息或追蹤,以減少記錄中暴露的內部細節。
程式碼範例 — 正式環境
標題為「程式碼範例 — 正式環境」的區段<?php
declare(strict_types=1);
// .env — production timestamp-authority hardening// NEXTPDF_TSA_URL=https://tsa.example.test// NEXTPDF_TSA_ALLOW_INSECURE_HTTP=false// NEXTPDF_TSA_WARN_ROTATION=true
return [ 'tsa' => [ 'url' => env('NEXTPDF_TSA_URL'), 'allow_insecure_http' => env('NEXTPDF_TSA_ALLOW_INSECURE_HTTP', false), 'warn_on_key_rotation' => env('NEXTPDF_TSA_WARN_ROTATION', true), 'pinned_public_keys' => [ // base64 SHA-256 SPKI hashes of the TSA certificate ], ],];邊界情況與陷阱
標題為「邊界情況與陷阱」的區段- 回應標頭集是固定的。需要不同 CSP 的應用程式,必須在工廠回傳回應後再進行後處理。
- 路徑驗證會在 worker 端執行。有問題的路徑會通過
dispatch(),只有在 job 執行時才會失敗。 tsa.allow_insecure_http = true會移除 HTTPS 強制要求,並削弱時間戳記的可信度。請把它限制在本機開發環境。- 字型登錄在暖機後會被鎖定;在長存 worker 中於執行期嘗試註冊字型的行為,依設計會被拒絕。
這些安全控制是常數時間的字串與陣列運算,不會增加可量測的單次請求成本。主要的維運成本來自首次使用時的字型剖析;請在 worker 啟動時預載字型,以避免首次請求延遲。
安全性備註
標題為「安全性備註」的區段本頁是本套件的威脅模型參考文件。此處所述的控制措施都在原始碼中強制執行,並由測試套件加以斷言。操作人員必須提供的部署設定,已在威脅模型表格與時間戳記憑證機構的步驟中明確指出。
符合性
標題為「符合性」的區段| 主張 | 來源 | 條款 | 參考 ID |
|---|---|---|---|
| PSR-18 用戶端送出 PSR-7 請求,回傳 PSR-7 回應 | PSR-18 HTTP 用戶端 | §2 | |
| 呼叫端傳入未逸出的結構化記錄內容 | PSR-3 記錄器 | §1.2 |
RFC 7469 SPKI 釘選是 tsa.pinned_public_keys 設定鍵所使用的形式;本套件會取用操作人員提供的釘選值,但本身並不實作該 RFC。
商業情境
標題為「商業情境」的區段PAdES B-B 簽章與時間戳記憑證機構整合需要 nextpdf/premium。這是一項選用的 Enterprise 能力;採用它時,本頁所記載的 Core 套件不需要任何程式碼變更。請參見 https://nextpdf.dev/get-license/?intent=laravel-signing。
另請參閱
標題為「另請參閱」的區段- /integrations/laravel/configuration/ — 每個 TSA、簽章與佇列設定鍵
- /integrations/laravel/production-usage/ — DI 與錯誤處理模式
- /integrations/laravel/troubleshooting/ — 為何路徑檢查會拒絕輸入
- /integrations/laravel/boot-and-discovery/ — 長存 worker 中的綁定生命週期