コンソールセッション
- セッションはデータベースに保存されます(Spring Session JDBC)。ブラウザが保持するのは
GRANTFORGE_SESSIONCookie のみで、これは HttpOnly、SameSite=Lax であり、HTTPS では Secure が付きます(またはgrantforge.security.cookie-secureで強制できます)。 - ログイン時、二段階認証の完了時、連携ログインの完了時に、セッション ID と CSRF トークンを更新し、セッション固定攻撃を防ぎます。
- 状態を変更するリクエストには必ず
X-XSRF-TOKENヘッダーを付与し、その値はXSRF-TOKENCookie から取得します。 - 管理者はすべてのセッションを一覧表示し、終了させることができます。アカウントの無効化、ロック、パスワードのリセットはそのアカウントのすべてのセッションを直ちに終了させ、パスワードの変更は他の端末のセッションを終了させます。
パスワード
- 新しいパスワードは Argon2id でハッシュします。BCrypt と 1.x からインポートされたハッシュも引き続き検証でき、次回ログイン時に現在のアルゴリズムへアップグレードされます。
- ポリシー: 長さ、文字の種別、履歴、有効期間はすべて設定でき、パスワードにユーザー名を含めることはできません。
- 連続して失敗して設定された回数に達するとアカウントをロックします。存在しないユーザー名に対してもハッシュ比較を一度実行するため、応答時間からどのユーザー名が存在するかは分かりません。無効化されたアカウントと無効化されたテナントは、パスワードが正しいことが確認された後にだけ通知されます。
二段階認証と再認証
- TOTP(RFC 6238、SHA-1、6 桁、30 秒、前後それぞれ 1 時間ステップを許容)を使用し、同じ時間ステップの検証コードは一度しか使用できません。使い捨てのリカバリコード 10 個は SHA-256 で保存します。
- 二段階認証を有効にしたアカウントでは、パスワードが正しいとセッションは 5 分間「未完了」状態となり、第二段階を完了するまではログイン状態にはなりません。
- 重要なインターフェースには
@RequireStepUpを付与します。二段階認証を有効にしたアカウントは、設定可能な時間枠の中で再認証済みである必要があり、そうでない場合はGF-SECURITY-006を返し、コンソールが確認ダイアログを表示した後に再試行します。
暗号化保存
アイデンティティソースのバインドパスワードとクライアントシークレット、認証器のキー、データサービスの重要な設定、認可サーバーの署名用秘密鍵は、いずれも AES-GCM で暗号化してから保存します。キーは grantforge.security.encryption-key から取得し、未設定の場合は自動生成してデータベースに保存します(試用のみを想定)。エージェントトークンと OAuth クライアントシークレットはハッシュのみを保存します。
トークン
- 認可サーバーはトークン本体ではなく、トークンのハッシュを保存します。
- リフレッシュトークンは使用されるたびに置き換えられ、古いトークンがリプレイされた場合はその認可全体を取り消します。
- アカウントの無効化、ロック、パスワード変更の要求、クライアントの無効化、テナントの無効化はいずれもトークンの更新を阻止します。オープン API は呼び出しのたびにトークンが現在も有効であることを確認します。
- ポリシースナップショットは Ed25519 で署名され、エージェントは署名を検証してから使用します。
インターフェース保護
- すべてのインターフェースはアクセス方式を必ず宣言する必要があり、宣言のないインターフェースは起動できません。権限を必要とするインターフェースは、呼び出しのたびに最新のスナップショットで検査されます。
- 拒否された呼び出しは監査に記録されます(リクエストはブロックしません)。
- 外部アイデンティティソースと同名のローカルアカウントは自動的に関連付けられず、アカウントの乗っ取りを防ぎます。
- CSV へエクスポートする際、
=、+、-、@で始まるセルには接頭辞を付与し、数式インジェクションを防ぎます。
監査
すべての管理操作、権限付与の変更、ログインイベント、拒否された呼び出しは監査ログに記録されます。権限に関する変更とそれに対する監査記録は同一トランザクション内でコミットされるため、変更がロールバックされれば監査記録も残りません。
