コンテンツにスキップ

NextPDF Laravel パッケージのセキュリティと運用

このパッケージは、固定のレスポンスヘッダーセットを適用し、ダウンロードファイル名をサニタイズし、ワーカー上でキュー出力パスを検証し、タイムスタンプ局への HTTP 通信をリクエスト偽造検知クライアントでラップします。このページでは、脅威モデルと、各コントロールに必要なデプロイ構成について説明します。

Terminal window
composer require nextpdf/laravel
php artisan vendor:publish --tag=nextpdf-config

このパッケージは、PDF エンジンを Web フレームワークで扱えるようにします。信頼境界は、HTTP リクエストとキュートランスポートです。以下のコントロールは、レスポンス処理、デシリアライズされたジョブペイロード、タイムスタンプ局への送信 HTTP に対処します。

資産脅威このパッケージのコントロール必要なデプロイ構成
PDF の HTTP レスポンスコンテンツタイプのスニッフィング、クリックジャッキング、インデックス登録すべての PdfResponse ファクトリに設定される固定ヘッダーセットなし。ヘッダーは構成できません
ダウンロードファイル名ヘッダーインジェクション、Content-Disposition を対象としたパストラバーサルファイル名サニタイザーが区切り文字、制御文字、ヌルバイトを除去しますなし。サニタイザーは常に実行されます
キュージョブの出力パス改ざんされたシリアライズ済みペイロードによる任意のファイル書き込みワーカー上の handle() でパスを検証出力を管理されたストレージパスに振り向ける
送信側の TSA HTTPサーバーサイドリクエストフォージェリ、平文の改ざんリクエスト偽造を検知する HTTP クライアント。明示的に緩和しない限り、HTTPS を強制します必ず tsa.allow_insecure_http = false を維持し、SPKI をピン留めする
共有ワーカーの状態長時間稼働するワーカーでのリクエスト間の状態漏えいロックされたフォントレジストリ。上限付きの画像キャッシュ。ファクトリにバインドされたドキュメント必ず preload_fonts を設定し、コンテナ側でメモリに上限を設ける

すべての PdfResponse ファクトリは、固定のヘッダーセットを設定します。

  • Cache-Control: private, max-age=0, must-revalidate
  • Pragma: public
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • Content-Security-Policy: default-src 'none'
  • X-Robots-Tag: noindex, nofollow
  • Referrer-Policy: no-referrer

これらの値は PdfResponse の定数です。構成では変更できません。パッケージのテストスイートは、ストリーミング版を含むすべてのファクトリメソッドについて、各ヘッダーをアサートします。

ダウンロードファイル名は、Content-Disposition ヘッダーに到達する前にサニタイザーを通過します。サニタイザーはパス区切り文字、制御文字、ヌルバイトを除去し、非 ASCII 名には RFC 5987 の filename*= パラメーターを出力します。空のファイル名は document.pdf になります。

GeneratePdfJob は、クロージャをキュートランスポートにシリアライズします。出力パスは、ディスパッチ時ではなく、ワーカー側の handle() 内で検証されます。この検証では、次のものが拒否されます。

  • パス内のヌルバイト、
  • ストリームラッパーのスキーム(例: php://)、
  • .. によるパストラバーサルセグメント、
  • 末尾が .pdf ではないパス(大文字・小文字を区別しない)。

いずれの拒否でも InvalidArgumentException が発生します。検証は、キューが消費される時点で実行されます。Redis やデータベーストランスポート上のシリアライズ済みペイロードは、ワーカーが読み取る前に改ざんされる可能性があります。出力先は管理されたストレージディレクトリにしてください。検証されていないリクエスト入力から導出しないでください。

タイムスタンプ局が構成されている場合、このパッケージは 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 を超えるものについては説明しません。上位のベースラインは対象外です。

タイムスタンプ局に関する運用ガイダンスは次のとおりです。

  1. 本番環境では、tsa.allow_insecure_httpfalse に設定したままにします。
  2. 必ず tsa.pinned_public_keys に、タイムスタンプ局証明書の base64 SHA-256 SPKI ハッシュ(RFC 7469 形式)を設定します。
  3. ピン留めした証明書が失効する前に SPKI の変更がログに記録されるよう、tsa.warn_on_key_rotationtrue に設定したままにします。
  4. tsa.url は必ず、信頼できる構成からのみ取得します。運用担当者が管理画面から設定できる場合は、リクエスト偽造のリスクを低減するために、送信側ファイアウォールまたは DNS ポリシーを適用します。

診断には Psr\Log\LoggerInterface を使用します。補間された文字列ではなく、構造化されたコンテキストを渡します。PSR-3 はプレースホルダーのエスケープをロガーの実装に委ね、呼び出し側にコンテキスト値を事前にエスケープしないよう求めています(PSR-3 §1.2)。ログ内の内部情報を減らすため、メッセージやトレースではなく、例外クラスをログに記録します。

resource: config/nextpdf.php (tsa hardening) + src/Laravel/NextPdfServiceProvider.php
<?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 が必要なアプリケーションは、ファクトリがレスポンスを返した後に、そのレスポンスを後処理する必要があります。
  • パスの検証はワーカー上で実行されます。不正なパスは dispatch() を通過し、ジョブが実行されたときにのみ失敗します。
  • tsa.allow_insecure_http = true は HTTPS の強制を解除し、タイムスタンプの信頼性を弱めます。これはローカル開発に限定してください。
  • フォントレジストリはウォームアップ後にロックされます。長時間稼働するワーカーで実行時にフォントを登録しようとすると、仕様により拒否されます。

これらのセキュリティコントロールは定数時間の文字列操作および配列操作であり、リクエストごとに測定可能なコストを追加しません。主な運用上のコストは初回使用時のフォント解析です。最初のリクエストの遅延を回避するため、ワーカー起動時にフォントをプリロードしてください。

このページは、パッケージの脅威モデルのリファレンスです。ここで説明するコントロールは、ソースコード上で強制され、テストスイートによってアサートされます。運用担当者が用意する必要があるデプロイ構成は、脅威モデルの表とタイムスタンプ局の手順で明示しています。

主張出典条項リファレンス 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/ — 長時間稼働するワーカーでのバインディングのライフタイム