はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、ウォレット側で管理する許可リストを使用して、信頼済みアプリへのSIWE(Sign-In with Ethereum)メッセージを自動署名できるようにする仕組みを提案しているERC8019についてまとめていきます!

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

概要

ERC8019とは、ウォレット内で管理される許可リスト(allowlist)を定義し、シンプルで決定論的なマッチルールが成功した時にERC4361(SIWE)メッセージを自動署名できるようにする規格のことです。

ERC4361については以下の記事を参考にしてください。

ポリシーはウォレットとユーザーのみによって作成・管理されます。

主要な特徴

特徴 説明
ウォレット管理型 ポリシーはウォレットUI内でのみ作成・管理される
自動署名 信頼済みアプリへのログイン時にプロンプトなしで署名
ドメインベースマッチング ドメインとURIプレフィックスによる厳密なマッチング
チェーンID制限 許可されたチェーンでのみ自動ログインが有効
有効期限設定 ポリシーに有効期限を設定可能
ハードウェアウォレット対応 ERC6492とセッションキーによる互換性サポート

SIWE(Sign-In with Ethereum) とは、ERC4361で定義されたEthereumアカウントを使用してWebアプリケーションにログインするための標準です。 ユーザーはウォレットでメッセージに署名することで、オフチェーンでの認証を行います。

動機

ユーザーは信頼済みアプリに対して同じSIWEメッセージに繰り返し署名しています。 毎回ウォレットでの署名確認プロンプトが表示されるため、ユーザー体験が損なわれています。

小規模で明示的なマッチポリシーを使用することで、アプリ側の変更なしにプロンプト不要のログインを実現できます。 ユーザーは最初にアプリに接続する時にウォレットからアプリを信頼するかどうかを尋ねられますが、このフローで該当する場合は自動ログインの許可も行うことができます。

現状の課題

課題 説明
繰り返しの署名操作 同じアプリへのログインで毎回署名が必要
ユーザー体験の低下 頻繁なプロンプト表示によるストレス
無駄な操作 信頼済みアプリへの不要な確認作業

ERC8019による解決

ERC8019では、ウォレット側でポリシーを管理することで、セキュリティを維持しながらユーザー体験を向上させます。 アプリ側からの影響を受けないため、悪意あるアプリがポリシーを操作することはできません。

仕様

ポリシー構造

各許可ポリシー(allow-policy)は以下の形式で定義されます。

javascript
{
  "domain": "example.com",                  // SIWEドメインとの完全一致
  "uriPrefix": "https://example.com/",      // SIWE URIがこれで始まる必要あり
  "allowedChains": [1],                     // 許可されたchainIdのリスト
  "allowedResources": ["https://example.com/login"], // 完全一致するリソースセット
  "supportsEIP6492": true,                  // ハードウェアウォレット使用時の円滑なUXに必要
  "expiresAt": 1700000000000                // ポリシーの有効期限(UNIXタイムスタンプ)、0は無期限
}

このポリシーオブジェクトは、どのSIWEメッセージを自動署名するかを決定するためのルールを定義しています。 domainはアプリのドメインと完全一致する必要があり、uriPrefixはSIWEメッセージのURIがこのプレフィックスで始まることを要求します。

フィールド 型 説明
domain string SIWEドメインとの完全一致が必要
uriPrefix string SIWE URIがこのプレフィックスで始まる必要あり
allowedChains number[] 許可されたchainIdの配列
allowedResources string[] 許可されたリソースURIの配列(順序不問)
supportsEIP6492 boolean ERC6492署名検証のサポート有無
expiresAt number ポリシーの有効期限(UNIXタイムスタンプ)、0は無期限

自動署名ルール

パースされたERC4361メッセージ M が与えられた時、ウォレットは以下の条件がすべて満たされた場合に自動署名できます。

条件 説明
M.domain == policy.domain ドメインが完全一致する
M.uriがpolicy.uriPrefixで始まる URIプレフィックスのマッチング
M.chainIdが存在する場合、policy.allowedChainsに含まれる チェーンIDの確認
policy.allowedResourcesが空でない場合、M.resourcesがそのサブセットである(順序不問)。空の場合はリソースを一切許可しない リソースの確認
policy.expiresAtが0でない場合、現在時刻がそれより前である 有効期限の確認

その他すべてのSIWE検証(ノンスの一意性、時間の有効性、署名ドメインバインディング)はERC4361の規定通りに適用され、ウォレットによって強制される必要があります。

以下のフロー図は、自動署名の判定プロセスを示しています。

flowchart TD
    A[SIWEメッセージ受信] --> B{ドメイン一致?}
    B -->|No| Z[手動署名に移行]
    B -->|Yes| C{URIプレフィックス一致?}
    C -->|No| Z
    C -->|Yes| D{chainId許可?}
    D -->|No| Z
    D -->|Yes| E{リソース許可?}
    E -->|No| Z
    E -->|Yes| F{有効期限内?}
    F -->|No| Z
    F -->|Yes| G[自動署名実行]

このフローでは、すべての条件を順番にチェックし、一つでも失敗すると通常の手動署名フローに移行します。 すべての条件を満たした場合のみ、ユーザーへのプロンプトなしに自動署名が実行されます。

ポリシー管理

ポリシーはウォレットUI内でのみ作成、一覧表示、更新、削除されます。 ウォレットがユーザーにどの程度の制御を与えるかはウォレットの実装次第です。

各ウォレットには以下が推奨されます。

推奨事項 説明
デフォルトポリシーリスト 人気アプリ向けのデフォルトポリシーを含める
自動ポリシー作成 安全と判断したアプリに対し、最初のSIWE署名後にユーザーの同意を得て自動作成
専用の同意フロー 「アプリXがあなたのアカウントでログインしようとしています」というプロンプトを表示し、「今後<アプリホスト名>に自動的にサインインする」チェックボックスを提供

アプリが提供するヒントやヘッダーがポリシー作成に影響を与えることはありません。 これにより、悪意あるアプリがポリシーを操作することを防ぎます。

ハードウェアウォレット互換性とERC6492

ERC6492については以下の記事を参考にしてください。

ハードウェアウォレットアカウントでは自動署名は実行可能ではありません。 ユーザーはコンテキストや予期なしにログインメッセージに署名するようプロンプトが表示されてしまうためです。

このため、supportsEIP6492プロパティが含まれています。 このプロパティがfalseに設定されている場合、アカウントの主要な署名者がハードウェアウォレットである時、ウォレットは自動ログインしてはなりません。 これは、アプリがスマートコントラクト署名を検証する方法がないためです。

ただし、trueに設定されている場合、以下の条件が満たされていればウォレットは自動ログインを実行できます。

条件 説明
EIP7702の有効化 アカウントでEIP7702を有効化できる、またはアカウントがスマートアカウントである
セッションキー/委任 自動ログイン専用の限定スコープセッションキーまたは委任を承認できる

EIP7702については以下の記事を参考にしてください。

これらの条件が満たされている場合、ウォレットはハードウェアデバイスでユーザーにプロンプトを表示せずにログイン署名を生成できます。 ただし、EIP7702の有効化とセッションキー/委任にはユーザーへのプロンプトが必要なため、ウォレットがユーザーをそのプロセスに案内するかどうかはウォレット次第です。

ウォレットがセッションキー/委任をどのように管理すべきかの正確なメカニズムはこの提案の範囲外ですが、ERC7710が使用される可能性があります。

RPCメソッド

ウォレットはRPCメソッド wallet_getCurrentAutoLoginPolicy を実装できます。 このメソッドはパラメータを持たず、呼び出し元アプリの現在のポリシーを記述するオブジェクトを返します。

javascript
{
  // アクティブなポリシーを記述するオブジェクト、またはnull
  "activePolicy": {
    "domain": "example.com",
    "uriPrefix": "https://example.com/",
    "allowedChains": [1],
    "allowedResources": ["https://example.com/login"],
    "supportsEIP6492": true,
    "expiresAt": 1700000000000
  }
}

このメソッドのレスポンスにより、アプリはユーザーの操作なしにログインリクエストを自己開始できるかどうかを判断できます。

以下の条件では、ウォレットは activePolicy に対して null を返す必要があります。

条件 説明
ERCが無効 ウォレットでこの提案が無効化されている
ポリシーなし 呼び出し元アプリに対するアクティブなポリシーが存在しない
ポリシー期限切れ ポリシーの有効期限が切れている(推奨)
許可されていないチェーン アプリが許可されていないチェーンで接続されている(推奨)

補足

設計の根拠

ERC8019は既存アプリへの最小限の変更を念頭に設計されています。 セキュリティの観点から、どのアプリにこのポリシーを有効にするかを決定する作業をウォレットに「アウトソース」する方がはるかに簡単です。 ほとんどのウォレットはすでに「信頼済み」アプリのリストを管理しています。

設計決定 根拠
ウォレット管理型ポリシー アプリからの操作を防ぎ、セキュリティを確保
ERC4361ベース 既存のSIWE標準との互換性維持
EIP712対象外 SIWEがプレーンテキストを基盤としているため

EIP712との関係

EIP712(型付きデータ)はこの規格の対象外です。 これはSIWEがプレーンテキストを基盤として構築されているためです。 将来的にEIP712ベースの自動署名が必要な場合は、別の提案で対応される可能性があります。

後方互換性

後方互換性はこの提案の主要な目標の一つです。 既存のアプリへの変更は不要で、ERC4361をそのまま基盤として構築されています。

この提案を完全に活用するためには、アプリはユーザーがログインボタンを押すことを期待するのではなく、ログインリクエストを自己開始する必要があります。 これはwallet_getCurrentAutoLoginPolicyメソッドを使用して実現できます。

互換性レベル 説明
完全互換 既存のSIWE実装はそのまま動作
機能強化 wallet_getCurrentAutoLoginPolicyを使用することで自動ログインのフル活用が可能

セキュリティ

ポリシー管理はこの提案の範囲外です。 ほとんどのウォレットはすでに信頼済みアプリリストを管理しているためです。 ただし、以下がベストプラクティスとして推奨されます。

考慮事項 推奨対策
デフォルトポリシー 人気アプリ向けのデフォルトポリシーリストを含める
ユーザー同意 ユーザーが同意した場合にのみ他のアプリのポリシーを自動作成
標準SIWE検証 新鮮なノンス、正しいドメインバインディング、時間の有効性を引き続き強制
uriPrefixの限定 過度に広いマッチを避けるため、具体的なパス(例: /login)を指定
無効化オプション 各ウォレットにこの提案を無効化できるトップレベル設定を含める
iframeセキュリティ 悪意あるトップレベルオリジンに含まれるiframeでの自動ログインを防ぐため、M.domainを各アプリのトップレベルオリジンに対してマッチングする

脅威モデル

脅威 対策
悪意あるアプリによるポリシー操作 アプリからのヒントやヘッダーはポリシー作成に影響しない
リプレイ攻撃 標準SIWEのノンス一意性検証を維持
期限切れポリシーの悪用 expiresAtによる有効期限管理
過度に広いマッチング uriPrefixを具体的に設定することで防止

参考実装

以下は、SIWEメッセージを自動署名すべきかどうかを判定する参照実装です。

javascript
function shouldAutoSign(M, P) {
  // ドメインの完全一致を確認
  if (M.domain !== P.domain) return false;

  // URIがプレフィックスで始まることを確認
  if (!M.uri.startsWith(P.uriPrefix)) return false;

  // chainIdが許可リストに含まれることを確認
  if (!P.allowedChains.includes(M.chainId)) return false;

  // リソースが許可リストのサブセットであることを確認
  if (M.resources) {
    const allowList = P.allowedResources || []
    if (!M.resources.every(resource => allowList.includes(resource))) return false;
  }

  // 有効期限を確認
  if (P.expiresAt !== 0 && Date.now() >= P.expiresAt) return false;

  // 標準SIWEの検証もここで実行する
  return true;
}

この関数は、メッセージ M とポリシー P を受け取り、自動署名を実行すべきかどうかをブール値で返します。 各条件を順番にチェックし、一つでも失敗すると false を返して通常の署名フローに移行します。

引用

最後に

今回は「ERC8019によるSIWE自動ログインのウォレット管理」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!