セッションとセキュリティ

ドキュメントセッションとアクセス制御

Doconut トークンは強力です。これを提示した者は、オープンセッションにバインドされていなければドキュメントのすべてのページを要求できてしまいます。このページでは、セッションが保持するもの、存続期間、そして UseDoconut() がデフォルトで有効にするチェックについて説明します。

ドキュメントセッションが保持するもの

  • ロードされたフォーマットビューア(解析されたドキュメントを保持するドキュメントエンジンのインスタンス),
  • ページ単位の状態 — 回転、フリップ、ウィジェットでユーザーが適用する注釈データ,
  • オプションの 検索インデックス、最初の検索時に遅延構築され(またはページが共有ストレージから提供される場合は事前構築された .srh ファイルからロードされ),
  • DocOptions.Watermark からのセッション ウォーターマーク.

有効期間

セッションは スライディングウィンドウ で期限切れになります:DocOptions.TimeOut 分(デフォルト 60)で、トークンを提示するすべてのリクエストによりリセットされます。セッションが期限切れまたは CloseDocument(token) によって削除されると、削除コールバックがドキュメントエンジンを破棄し、関連メモリを即座に解放します。

csharp
// 一回限りのプレビュー用の短命セッション
var token = await viewer.OpenDocumentAsync(path, new DocOptions { TimeOut = 10 });

期限切れトークンでのリクエストは、Document session not found. Please re-open document. というエラー画像が返されます — クライアントは新しいトークンを取得するためにドキュメントを再度開く必要があります。

組み込みトークンバインディング

UnsafeMode = false(デフォルト) の場合、OpenDocumentAsync は新しいトークンをそれを開いた HTTP リクエストの ASP.NET セッション にバインドし、secure-{token} マーカーをそのセッションに書き込みます。Doconut ミドルウェアはそれ以外のブラウザセッションへのページ提供を拒否します。

  • 盗まれたトークンを提示した別のブラウザ/セッション → エラー画像 You Are Not Authorized To View This Page.
  • セッションミドルウェアが登録されていない → HTTP 500 Session middleware not configured. Call UseSession() before UseDoconut().

このため、クイックスタートでは Doconut ブランチの前に AddSession() と app.UseSession() を必ず行うことが推奨されています。実務上の影響は二つあります:

  • クライアントはページリクエストに ASP.NET セッションクッキー を送信しなければなりません。クッキーを除去するクロスオリジン設定やクッキー保存がない API クライアントではチェックが失敗します — これはバグではなく機能が働いているということです。
  • options.UnsafeMode = true はバインディングを完全に無効にします。制御されたシナリオ向けに存在するので、単一ノードの本番環境では false のままにしてください。

綴りに注意してください。以前の .NET Standard ライブラリではこのプロパティは UnSafeMode と呼ばれ、ミドルウェアに渡されていましたが、ここでは UnsafeMode と呼び、AddDoconut() 内で一度だけ設定されます。

トークンバインディングはこのグローバルな UnsafeMode スイッチだけで制御されます — デフォルトで有効(UnsafeMode = false)で、すべてのセッションに適用されます。ドキュメント単位でのオプトアウトはなく、UnsafeMode = true に設定するとバインディングが全体で無効になります。

アクセス権限と認証ユーザー

UnsafeMode が false の場合、UseDoconut() はページミドルウェアの前にドキュメントアクセスミドルウェアを自動的に挿入します。二度登録しないでください。リクエストがトークンを持つと、ドキュメントが開かれた際に記録された アクセス権限 を検索し、以下すべてが成立する場合にのみ認可します:

  1. トークンに対する権限が存在すること
  2. 期限切れでないこと(権限の有効期間はドキュメントの TimeOut と同じ)
  3. 要求側の ASP.NET セッション ID がドキュメントを開いたときのものと一致すること
  4. 開いた側が認証済みの場合、要求側ユーザーの NameIdentifier クレームも一致すること

失敗した場合は 403 を返します — ページやサムネイルのリクエストでは PNG エラー画像として、その他の場合はプレーンテキストとして返されます。メッセージとトークンクエリキーは DocumentSecurityOptions から取得されます(TokenQueryKey はデフォルト "token"、UnauthorizedMessage はデフォルト "You Are Not Authorized To View This Page.")。アプリ構築前に ASP.NET Core の DI を通じてこれらのオプションを設定してください。セッション状態が利用できない場合、ミドルウェアは HTTP 500 で閉鎖的に失敗します:ASP.NET Session is required for Doconut document security.

csharp
builder.Services.Configure<Doconut.Security.DocumentSecurityOptions>(options =>
{
    options.TokenQueryKey = "token";
    options.UnauthorizedMessage = "You Are Not Authorized To View This Page.";
});

コアのページミドルウェアはドキュメントを提供する前に secure-{token} セッションマーカーを検証します。UnsafeMode = true の場合、UseDoconut() はアクセスミドルウェアをスキップし、コアのマーカーチェックも無効化されます。

複数ノード間のセキュリティ

セッションバインドされたトークンは、ページを提供するノードがドキュメントを開いたリクエストも受け取っていることを前提としています。この前提は、複数のノードが共有ストレージから同じドキュメントを提供する場合には成り立ちません。ページリクエストが開いたことのないノードに届くと、セッション単位のチェックで拒否されます。

解決策はドキュメントを保護しないままにしないことです。AddDoconutDistributedDocumentSecurity(...) を使用して署名付きアクセスチケットを利用すれば、セッションチェックを各ノードが独立して検証できる認証情報に置き換えられます。全体の構成は 分散デプロイメント に記載されています。

取り消し

CloseDocument(token) はメモリを解放するだけでなく、secure-{token} マーカーを削除し、アクセス権限を取り消すため、閉じられたトークンは両方のセキュリティ層で即座に無効になります。

本番環境向けチェックリスト

  • UnsafeMode = false(デフォルト) を単一ノードで維持してください — このグローバルスイッチがトークンをセッションにバインドします。
  • AddDistributedMemoryCache()(MVC と Razor Pages アプリは既に持っています)と AddSession() を登録し、Doconut ミドルウェアブランチの前に app.UseSession() を呼び出してください。
  • セッションクッキーのポリシーがウィジェットのリクエストでクッキーを送信できるように設定してください(SameSite、HTTPS)。
  • ユーザーがドキュメントを離れたときは CloseDocument を使用してください — メモリとセキュリティの両方に効果があります。
  • トークンをログに記録したり共有したりしないでください。短命な認証情報として扱ってください。
  • 共有ストレージから提供していますか? 保護されていないドキュメントを受け入れるのではなく、署名付きアクセスチケットに移行してください。

このページは役に立ちましたか?