NextPDF Laravel パッケージのセキュリティと運用
このパッケージは、固定のレスポンスヘッダーセットを適用し、ダウンロードファイル名をサニタイズし、ワーカー上でキュー出力パスを検証し、タイムスタンプ局への HTTP 通信をリクエスト偽造検知クライアントでラップします。このページでは、脅威モデルと、各コントロールに必要なデプロイ構成について説明します。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-config概念的な全体像
「概念的な全体像」という見出しのセクションこのパッケージは、PDF エンジンを Web フレームワークで扱えるようにします。信頼境界は、HTTP リクエストとキュートランスポートです。以下のコントロールは、レスポンス処理、デシリアライズされたジョブペイロード、タイムスタンプ局への送信 HTTP に対処します。
API サーフェス — 脅威モデル
「API サーフェス — 脅威モデル」という見出しのセクション| 資産 | 脅威 | このパッケージのコントロール | 必要なデプロイ構成 |
|---|---|---|---|
| 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-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 ヘッダーに到達する前にサニタイザーを通過します。サニタイザーはパス区切り文字、制御文字、ヌルバイトを除去し、非 ASCII 名には RFC 5987 の filename*= パラメーターを出力します。空のファイル名は document.pdf になります。
キューペイロードの検証
「キューペイロードの検証」という見出しのセクションGeneratePdfJob は、クロージャをキュートランスポートにシリアライズします。出力パスは、ディスパッチ時ではなく、ワーカー側の handle() 内で検証されます。この検証では、次のものが拒否されます。
- パス内のヌルバイト、
- ストリームラッパーのスキーム(例:
php://)、 ..によるパストラバーサルセグメント、- 末尾が
.pdfではないパス(大文字・小文字を区別しない)。
いずれの拒否でも InvalidArgumentException が発生します。検証は、キューが消費される時点で実行されます。Redis やデータベーストランスポート上のシリアライズ済みペイロードは、ワーカーが読み取る前に改ざんされる可能性があります。出力先は管理されたストレージディレクトリにしてください。検証されていないリクエスト入力から導出しないでください。
タイムスタンプ局への送信 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 形式)を設定します。 - ピン留めした証明書が失効する前に SPKI の変更がログに記録されるよう、
tsa.warn_on_key_rotationをtrueに設定したままにします。 tsa.urlは必ず、信頼できる構成からのみ取得します。運用担当者が管理画面から設定できる場合は、リクエスト偽造のリスクを低減するために、送信側ファイアウォールまたは DNS ポリシーを適用します。
診断には Psr\Log\LoggerInterface を使用します。補間された文字列ではなく、構造化されたコンテキストを渡します。PSR-3 はプレースホルダーのエスケープをロガーの実装に委ね、呼び出し側にコンテキスト値を事前にエスケープしないよう求めています(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 が必要なアプリケーションは、ファクトリがレスポンスを返した後に、そのレスポンスを後処理する必要があります。
- パスの検証はワーカー上で実行されます。不正なパスは
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/ — 長時間稼働するワーカーでのバインディングのライフタイム