認証なしの認可:パスワード不要の設計

認証と認可は別の問題を解く

ほとんどのアプリはゲートから始まります。ユーザーは何かをする前に、身元を確立しなければなりません。メールを入力し、確認コードを受け取り、パスワードを決め、あるいはマジックリンクをたどる。この段階が認証であり、中央の権威が保持する記録に対して、その人が誰かを確認する手続きです。

認可は別の問いに答えます。この人は何を許可されているのか。多くのチームは両者を一つの「ログイン」フローにまとめますが、これらは別個の処理です。分けて考えると有益な洞察が見えてきます。

サーバーは、ユーザーが何を許可されているかを実施するために、その人が誰かを知る必要はありません。

JustCall はこの分離の上に作られています。サインアップも、アカウントのテーブルも、パスワードも、サーバー上の個人データもありません。認可がシステム全体を支え、従来の意味での認証は存在しません。これを可能にするのは3つの構成要素です。秘密鍵、公開鍵、そしてマスター鍵と呼ぶ委任された役割です。

公開鍵ベースの身元がアカウントを置き換える仕組み

JustCall を初めて開くと、ブラウザはローカルで秘密を生成し、決して送信しません。その秘密から鍵ペアを導出し、公開側があなたのユーザーIDになります。

// The private key is generated on your device. The server never sees it.
privateKey = crypto.randomUUID();

// The PUBLIC half, encoded as text, becomes your user ID.
userId = await derivePublicUserId(privateKey);

識別子は公開鍵そのものであり、それを指すデータベースの行ではありません。このひとつの決定が、従来のアカウントシステムが抱える複数の負債を取り除きます。

  • 登録の段階がない。サーバーはIDで署名された要求を、初めて見た瞬間から受け入れます。
  • メールも電話番号もない。IDは個人情報ではなく、あなたの端末上のランダムな秘密から導かれます。
  • パスワードがない。保存・ハッシュ化・漏洩しうる共有秘密はなく、サーバーは公開鍵しか保持しません。
  • パスワードリセットの流れもクレデンシャルスタッフィングもない。攻撃できる再利用可能な資格情報が存在しないからです。

あなたはサーバーに身元を明かしません。特定の公開鍵の背後にある秘密鍵を持っていることを暗号学的に証明し、その証明が認可として十分です。

サーバーが要求を認可する方法

セッションもログイントークンもないため、各要求は自らの証明を携えます。クライアントはペイロードを構築し、秘密鍵で署名し、両方を送ります。サーバー側では、認可はただ一度の署名検証に帰着し、セッション参照も資格情報ストアへの問い合わせもありません。

const isValid = await verifyPayload(
  request.userId,   // the public key = the claimed identity
  request.payload,  // exactly what was signed
  request.signature,
);

if (!isValid) {
  return jsonResponse({ message: "invalid signature" }, 401);
}

有効な署名は、要求を一度の操作で本物かつ認可済みにします。攻撃者は、秘密鍵を持たないIDの要求を偽造できません。一致する署名を生成できないからです。秘密鍵の所持が権限です。

マスター鍵:秘密を共有せずに端末を連携する

1台の端末だけが唯一の鍵を持つモデルは、2台目を追加した途端に破綻します。電話があなたの身元への唯一の鍵を持つなら、ノートPCはシステムにとって他人です。

マスター鍵がこれを解決します。最初の端末がマスターとなり、あなたのIDが導かれる元の秘密を保持します。追加の端末はそれぞれ自分専用の別の鍵ペアを生成します。新しい端末はあなたに代わって署名できず、マスター鍵が端末間でコピーされることはありません。連携は委任で機能します。マスターは、新しい端末の公開鍵をあなたのIDに結びつける短い証明書に署名します。

// Only the master can authorize a new device.
const authorization = {
  action: "device-authorization",
  userId: identity.userId,
  devicePublicKey: newDevice.devicePublicKey, // the new device's PUBLIC key
  role: newDevice.role,
  createdAt: Date.now(),
};
const signature = await signPayload(identity.privateKey, authorization);

以後、新しい端末は自分の鍵で自分の要求に署名し、サーバーはマスターが保証した鍵に対して検証します。マスターは秘密を一度も明かさずに資格を発行します。これは、自分が秘密鍵を持たないウェブサイトを認証局が保証するのと同じです。

こうして、本番運用の権限システムが備える語彙のすべて、すなわちロール、委任、失効、最小権限が、署名だけで表現されます。マスターは連携した端末の名前変更や失効ができ、失効した端末は次の署名検証に失敗し、その有効な接続が閉じられます。

アカウントのないサーバーが保存するもの

データベースの実際の中身を見てください。各アカウントが保持するのは、ユーザーが選んだ表示名、任意のアバター、そして公開端末鍵のリストです。それ以外はありません。メールも、電話番号も、パスワードハッシュも、秘密の質問もなく、秘密鍵もありません。秘密鍵はユーザーの端末を決して離れません。

データベース全体が漏れる、という典型的な侵害シナリオを考えてください。攻撃者が得るのは、設計上公開であり対応する秘密鍵なしでは無価値な公開鍵の集合と、ユーザーが選んだいくつかの表示名です。誰にもなりすませません。なりすましにはサーバーが一度も保存しなかった秘密鍵が要るからです。パスワードダンプと突き合わせもできません。パスワードが存在しないからです。「あなたのメール」でフィッシングもできません。一度も収集されていないからです。

システムは、決して保持しないデータを漏らせません。個人情報を守る最も確実な方法は、それを収集しないことであり、IDが公開鍵であるという身元モデルは、それを文字どおり実現します。

なぜパスワード不要の認可が侵害リスクを下げるのか

攻撃面を直接比べてみましょう。従来のメールとパスワードのアプリは、資格情報データベース、パスワードリセットの流れ、メールとSMSのコード配信、セッショントークン、そして今や責任を負う規制対象の個人データ群を守らねばなりません。いずれもアカウント乗っ取りと情報漏洩の常習的な原因です。

公開鍵モデルが守るのはひとつ、ユーザーが鍵を保持し続けることです。これは本物のトレードオフです。失った鍵をリセットできる中央の権威がないからです。その代わり、前のリストの各項目は消えます。サーバー侵害の影響は、攻撃者が公開鍵と表示名を読める範囲まで狭まります。もともと機微でなかった情報です。

公開鍵認可を自分のアプリに適用する

このパターンは通話アプリの枠をはるかに超えて一般化できます。

  • 身元を鍵ペアにし、ユーザーIDを公開鍵にする。クライアントで生成し、秘密側は決して送らず、サーバーが有効な署名を見た瞬間にアカウントが生まれるようにします。
  • セッション確認ではなく署名検証で認可する。各操作はペイロードと署名を携えます。正規化されたバイト列に署名し、何に署名したかでクライアントとサーバーが一致するようにします。
  • マスター鍵は共有ではなく委任に使う。主体が信頼を2台目の端末、チームメイト、APIクライアントへ広げる必要があるとき、ルート鍵に新しい鍵向けの範囲限定で失効可能な証明書を署名させます。ルートの秘密は決して動きません。
  • 公開素材だけを保存する。そうすれば「漏洩したらどうなるか」への答えは平凡なままです。

出荷前に注意すべき制約がいくつかあります。鍵の保管が中心的な問題になるため、本番システムはソーシャルリカバリ、任意の暗号化バックアップ、ハードウェアキーなどの復旧手段を加えます。署名済みの要求はリプレイを防ぐためにタイムスタンプかnonceを必要とします。身元がないため、スパム対策はメール確認ではなくレート制限や招待制に移ります。いずれもモデルを損ないません。どれも、真ん中にパスワードデータベースを置かないだけで、あらゆるシステムが抱える通常の課題です。

よくある質問

アプリはどうやって認証なしでユーザーを認可できるのですか。秘密鍵の所持を権限として扱います。公開鍵がユーザーIDとなり、各操作は対応する秘密鍵で署名され、サーバーはその署名を公開鍵に対して検証します。ユーザーは、中央のアカウントシステムに身元を証明せずに、行動が許可されていることを証明します。

アカウントのないモデルはメールとパスワードより安全性が低いのですか。ほとんどの面でより安全です。漏らすべきパスワードデータベースも、悪用されるリセットの流れも、失う個人データもありません。トレードオフは鍵の保管です。バックアップなしで鍵を失うと、アカウントを復旧できる中央の権威はありません。

認証と認可の違いは何ですか。認証はあなたが誰かを確立します。認可はあなたが何を許可されるかを確立します。多くのシステムは両者を組み合わせますが、鍵ペアは前者なしで後者を可能にします。

JustCall のサーバーが侵害されたらどうなりますか。攻撃者が見つけるのは公開鍵と表示名です。公開鍵は公開されるべきもので、端末を決して離れない秘密鍵なしでは無価値です。盗めるパスワードもメールも電話番号もありません。

アカウントなしで複数の端末を使えますか。はい。最初の端末がマスターとして働き、各新端末の公開鍵をあなたのIDに結びつける証明書に署名します。マスターの秘密は決してコピーされず、マスターはいつでもどの端末でも失効できます。

関連記事