セキュリティ
もてなすように、守る。
IDプロバイダーの価値は、テナント間の壁の確かさと、シークレットの扱いの丁寧さで決まります。ここでは、Usher Identityがどのように作られているかをご紹介します。説明するのはソフトウェアの動作であり、いかなる認定の取得も主張するものではありません。
アーキテクチャ
別々のドメイン、別々のネットワーク。
Usher Identity自身のページと各顧客の発行者は、それぞれ異なる登録可能ドメインに置かれています。データベースはインターネットに到達できないネットワーク上にあり、外に出る唯一の道は、行き先を確認するプロキシです。
- CaddyがすべてのホストのTLSを終端し、Usher Identity自身のサービスだけが設定できるヘッダーを取り除きます。
- 認証層はホストで区別しながら、すべての環境に応答します。あるホスト向けにキャッシュしたものを、別のホストに返すことはありません。
- 各サービスは専用のユーザーとしてValkeyに接続し、自分のキーにしかアクセスできません。デフォルトユーザーはありません。
- トークンやコードを含むSQL文が、その値ごとデータベースのログに書き込まれることはありません。
インターネット
ユーザー、あなたのアプリ、あなたのサーバー
エッジ
Caddy:TLS、HSTS、内部ヘッダーの除去
usheridentity.com
サイトとConsole
usheridentity.com, console.usheridentity.com
API
api.usheridentity.com
*.usherid.com
認証層
すべての環境の発行者とLobby
データネットワーク · 外部への経路なし
Postgres
環境ごとに1つのスキーマ
Valkey
各サービスは自分のキーだけにアクセス
唯一の出口
エグレスプロキシ
顧客が指定したすべてのURLに
ディスカバリ、JWKS、ログアウト
公開アドレスのみ
分離
重要なものは、何も共有しない。
プロジェクトの各環境には、専用のPostgresスキーマ、専用の署名鍵、そして専用のデータキーで封印された専用のシークレットがあります。発行者はテナントドメイン上のホストで、Cookieはホスト限定のため、ブラウザーがある環境のCookieを別の環境に送ることはありません。
usheridentity.com
サイト、Usher Identity Console、Usher Identityアカウント
*.usherid.com
環境ごとに1つの発行者を、別のドメインに
ユーザー、セッション、トークンは、この環境のために作られたスキーマに保存されます。クエリはそのスキーマに対して実行され、テナント列を持つ共有テーブルが使われることはありません。
Acmeの本番環境にある封印済みのGoogleクライアントシークレットを、Northwindの本番環境にコピーする。
保存時の暗号化
あるべき場所に結び付いた、エンベロープ暗号化。
Usher Identityに預けたシークレットは、ひとつの環境に属するデータキーを使ってAES-256-GCMで封印されます。データキー自体も、データベースの外に保管された、バージョン管理されたマスターキーでラップされます。
- 環境ごとのデータキー
- ある環境のデータキーが漏えいしても、別の環境のデータキーについては何もわかりません。
- AADによる結び付け
- すべての暗号文に環境と用途が結び付けられているため、値を別の行や別のテナントに移すことはできません。
- バージョン管理された鍵
- 封印された値には、それぞれ作成時の鍵のバージョンが記録されるため、鍵をローテーションし、古い値をラップし直せます。
- 認証付き暗号
- GCMのタグにより、改ざんされた値は別の内容に復号されるのではなく、開くことに失敗します。
マスターキー
データベースの外に保管、バージョン管理
データキー(環境ごとに1つ)
マスターキーでラップ
シークレット
データキーを使いAES-256-GCMで封印
u1.<key version>.<iv>.<ciphertext + tag>
aad = u1 | version | environment | purpose
取り組み
細部まで、丁寧に。
パスワード(使う場合)
OWASPが推奨するコスト(19 MiB、2パス)でArgon2idを使ってハッシュ化し、同時に実行する数に上限を設けているため、大量のサインインでサービスが停止することはありません。新しいパスワードは、Have I Been PwnedのRange APIで既知の漏えいと照合されます。このAPIが受け取るのは、パスワードのハッシュの短い先頭部分だけです。最小文字数はデフォルトで12文字です。
再利用されうるものは保存しない
クライアントシークレット、トークン、マジックリンクのトークン、メールで届くコードは、ハッシュ化して保存されます。バックアップコードは暗号化されます。認可コードの有効期間は5分で、メールで届くコードは3回まで試せます。
すべての扉にレート制限
サインイン、新規登録、メールで届くコード、マジックリンク、パスワードのリセット、2段階認証の確認には、それぞれ個別の制限があります。たとえば、パスワードでのサインインは1分間に10回、メールで届くコードは10分間に5回までです。
厳格なContent-Security-Policy
Lobbyのページには毎回新しいnonceと、それを軸にしたポリシーが付与されます。実行されるのはnonceを持つこのオリジンのスクリプトだけで、フォームの送信先は同一オリジンに限られ、ほかのサイトがページをフレームに埋め込むことはできません。
信頼できる監査ログ
ワークスペース、プロジェクト、環境への変更は追記専用のログに書き込まれ、各エントリーは直前のエントリーとハッシュチェーンでつながっています。そのため、編集されたエントリーや欠けたエントリーがあれば、すぐにわかります。
顧客のURLのためのエグレスプロキシ
顧客から指定されたアドレスへのUsher Identityのリクエスト(OIDCディスカバリ、JWKS、バックチャネルログアウト)は、すべてひとつのプロキシを経由して外に出ます。プロキシは名前解決を一度だけ行い、プライベート、ループバック、リンクローカル、クラウドメタデータのアドレスを拒否したうえで、確認したアドレスに接続します。そのため、DNSリバインディングによって顧客のURLを内部のURLに変えることはできません。
二度と割り当てられないハンドル
本番環境のハンドルは、その発行者のホスト名の最初のラベルです。Consoleは招待制で、フィッシングとして報告されたLobbyは停止されます。また、一度使われたハンドルが再び割り当てられることはありません。古いアプリが、まだそのトークンを信頼しているかもしれないからです。
終わらせたいときに終わるセッション
Usher Identityはキャッシュされたコピーを信頼せず、リクエストのたびに自身のセッションを確認します。そのため、終了したセッションはすぐに無効になります。アクセストークンの有効期間は短く(デフォルトで10分)、APIからイントロスペクションできます。
責任ある開示
何か見つけましたか?まずはお知らせください。
Usher Identityにセキュリティ上の問題を見つけたと思ったら、ぜひお知らせください。修正に向けて、一緒に取り組みます。
- 見つけた内容、場所、再現手順。
- あなたの理解の範囲で、その問題を使って何ができるか。
- 連絡先と、謝辞にお名前を掲載してよいかどうか。
テストはご自身が所有する環境だけで行い、他人のデータにはアクセスしないでください。また、問題を公表する前に、修正のための妥当な猶予をいただけますようお願いします。Usher Identityのサインインになりすましたページを報告するには、不正利用の報告をご覧ください。