# [ERC4361] Ethereumアドレスを使用してオフチェーンサービスにログインする仕組みを理解しよう！

> 「Sign-In with Ethereum」とは、Ethereumアカウントを使ってオフチェーンサービス（インターネット上のサービスなど）にログインするための方法です。

- URL: https://cardene.dev/articles/b4d04cc84b4f1f8a3be1
- 公開日: 2024-01-11
- 更新日: 2024-01-11
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、Ethereumアカウントを使用して、オフチェーンサービスにログインする方法を提案している**ERC4361**についてまとめていきます！

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

https://eips.ethereum.org/EIPS/eip-4361

:::message alert
**4361**は現在（2024年1月7日）では「**Review**」段階です。
:::

他にも様々なEIPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

「**Sign-In with Ethereum**」とは、Ethereumアカウントを使ってオフチェーンサービス（インターネット上のサービスなど）にログインするための方法です。
このシステムでは、特定の情報（スコープやセッションの詳細）とセキュリティ要素（例えば、一度だけ使われるランダムな数字であるナンス）を含んだメッセージにユーザーがサインします。
目的は、中央集権的なアイデンティティプロバイダー（例えば、GoogleやFacebookでログインすること）の代わりに、自分自身で管理する方法を提供し、Ethereumを使った認証がさまざまなサービス間でうまく機能するようにすることです。
また、この仕様はウォレットの提供者が一貫した形式でメッセージを読むことを可能にし、これによりユーザーの体験や同意管理が改善されます。

## 動機

通常、オンラインサービスにサインインする時、多くの人はGoogleやFacebookのような大手企業が提供するアイデンティティプロバイダー（**IdP**）を使います。
これらのサービスは便利ですが、ユーザーの個人情報を完全にコントロールしています。
利害関係が一致しないことも多く、プライバシーやセキュリティに懸念があります。

「**Sign-In with Ethereum**」は、こうした問題に対する1つの解決策を提供します。
これは、Ethereumブロックチェーンを利用した新しいサインイン方法で、ユーザーが自分のデジタルアイデンティティを自ら保管し、管理することを可能にします。
つまり、ユーザーは自分自身の識別情報の所有者となり、中央集権的な企業に頼らずともサービスにアクセスできるようになります。

既に多くのサービスで、メッセージを署名することによってEthereumアカウントを認証する方法がサポートされています。
これにより、ユーザーがサービスにログインする時に、安全に自分のアイデンティティを証明できます。
そして、「**Sign-In with Ethereum**」は、このような署名プロセスを標準化し、さまざまなサービス間での連携をスムーズにし、さらにウォレットのベンダーがユーザーのサインインリクエストを簡単に識別できるようにすることで、ユーザーエクスペリエンスを大きく向上させます。

:::message
アイデンティティプロバイダー（**IdP**）は、ユーザーのアイデンティティ情報を管理し、認証サービスを提供するシステムやプラットフォームです。
主な目的は、ユーザーが自身の身元を証明し、様々なオンラインサービスに安全にアクセスできるようにすることです。

**認証**
**IdP**はユーザー名とパスワード、二要素認証、生体認証など、さまざまな方法を使用してユーザーの身元を確認します。
ユーザーが正しい認証情報を提供すると、**IdP**はそのユーザーが誰であるかを確認し、アクセスを許可します。

**シングルサインオン（SSO）**
**IdP**はシングルサインオンをサポートすることが多いです。
これは、ユーザーが一度ログインするだけで、複数の関連するが独立したソフトウェアシステムにアクセスできるようにする機能です。
SSOは、ユーザーの利便性を向上させ、パスワード関連のリスクを減らすのに役立ちます。

**権限付与とアクセス管理**
**IdP**は、ユーザーがアクセスできるリソースや実行できる操作を定義する権限を管理します。
これにより、適切なユーザーのみが機密情報や機能にアクセスできるようになります。

**フェデレーション**
複数の**IdP**が互いに信頼関係を築き、ユーザーが異なるドメイン間でシームレスに移動できるようにすること。
これにより、ユーザーは異なるサービス間で同じ認証情報を再利用できます。

**プライバシーとセキュリティ**
**IdP**はユーザーの個人情報を保護するために、データ暗号化、セキュリティポリシー、監査ログなどのセキュリティ対策を実施します。

代表的な**IdP**には、Googleアカウント、Facebookログイン、Twitter認証などのソーシャルログインサービス、企業や教育機関が利用するMicrosoft Active DirectoryやLDAPなどがあります。
**IdP**は、オンラインのアイデンティティとセキュリティを管理する上で不可欠な役割を果たしています。
:::

## 仕様

### 概要

「**Sign-In with Ethereum**」（**SIWE**）は、ユーザーがEthereumアカウントを使ってサービスにログインするための方法です。
このプロセスは以下のステップで構成されています。

1. **サービス提供者の役割**
    - まず、サービス提供者（依存するパーティー）が特別なメッセージ（**SIWE**メッセージ）を作成します。
    - このメッセージには、**ERC191**というEthereumの標準に従って、以下のような特定のプレフィックスが付けられます。
        - `\x19Ethereum Signed Message:\n<length of message>`
    - これはメッセージが本物であることを示すためのものです。

2. **ユーザーとウォレットの役割**
    - 次に、ユーザーのウォレット（Ethereumを管理するアプリ）が、このメッセージをユーザーに見せ、署名を依頼します。
    - ユーザーはウォレットを使って、このメッセージに対して自分のデジタル署名を行い、**ERC191**形式で署名されたデータを生成します。

3. **署名の確認**
    - ユーザーが署名した後、この署名されたメッセージはサービス提供者に戻されます。
    - サービス提供者は、署名が正しいかどうか、そしてメッセージの内容が適切かどうかを確認します。

4. **追加データの取得**
    - 確認が終わったら、サービス提供者は必要に応じて、ユーザーのEthereumアドレスに関連する追加のデータを取得できます。
    - これには、ブロックチェーン上に公開されている情報（例：ENS名、アカウント残高、**ERC20**、**ERC721**、**ERC1155**トークンの所有情報）や、他のデータソースからの情報が含まれる場合があります。

:::message
**ERC191**については以下の記事を参考にしてください。
:::

[\[ERC191\] 署名済みデータを安全に使用する仕組みを理解しよう！](/articles/ee4edd15ad6fe7f58f7e)

:::message
**ERC20**については以下の記事を参考にしてください。
:::

https://chaldene.net/erc20

:::message
**ERC721**については以下の記事を参考にしてください。
:::

https://chaldene.net/erc721

:::message
**ERC1155**については以下の記事を参考にしてください。
:::

https://chaldene.net/erc1155

この一連のプロセスによって、ユーザーは自分のEthereumアカウントを使って、安全にさまざまなオンラインサービスにログインできるようになります。

### メッセージフォーマット

#### ABNFメッセージフォーマット

「**Sign-In with Ethereum**」（**SIWE**）メッセージは、ユーザーがEthereumアカウントを使用してオンラインサービスにサインインする時に使われる特定の形式のメッセージです。
このメッセージは、安全な認証を保証するために厳格なルールに従って構成されており、それらのルールは拡張バッカス・ナウア形式（**ABNF**）という規格で定義されています。

```
sign-in-with-ethereum =
    [ scheme "://" ] domain %s" wants you to sign in with your Ethereum account:" LF
    address LF
    LF
    [ statement LF ]
    LF
    %s"URI: " uri LF
    %s"Version: " version LF
    %s"Chain ID: " chain-id LF
    %s"Nonce: " nonce LF
    %s"Issued At: " issued-at
    [ LF %s"Expiration Time: " expiration-time ]
    [ LF %s"Not Before: " not-before ]
    [ LF %s"Request ID: " request-id ]
    [ LF %s"Resources:"
    resources ]

scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
    ; See RFC 3986 for the fully contextualized
    ; definition of "scheme".

domain = authority
    ; From RFC 3986:
    ;     authority     = [ userinfo "@" ] host [ ":" port ]
    ; See RFC 3986 for the fully contextualized
    ; definition of "authority".

address = "0x" 40*40HEXDIG
    ; Must also conform to captilization
    ; checksum encoding specified in EIP-55
    ; where applicable (EOAs).

statement = *( reserved / unreserved / " " )
    ; See RFC 3986 for the definition
    ; of "reserved" and "unreserved".
    ; The purpose is to exclude LF (line break).

uri = URI
    ; See RFC 3986 for the definition of "URI".

version = "1"

chain-id = 1*DIGIT
    ; See EIP-155 for valid CHAIN_IDs.

nonce = 8*( ALPHA / DIGIT )
    ; See RFC 5234 for the definition
    ; of "ALPHA" and "DIGIT".

issued-at = date-time
expiration-time = date-time
not-before = date-time
    ; See RFC 3339 (ISO 8601) for the
    ; definition of "date-time".

request-id = *pchar
    ; See RFC 3986 for the definition of "pchar".

resources = *( LF resource )

resource = "- " URI
```

- **`sign-in-with-ethereum`**
    - メッセージの始まりを示し、ユーザーにEthereumアカウントでサインインすることを要求していることを伝えます。
- **`scheme`**
    - ウェブサイトやアプリのプロトコル（httpやhttpsなど）を指します。
- **`domain`**
    - ユーザーがサインインを求められているウェブサイトやサービスのドメイン名です。
- **`address`**
    - ユーザーのEthereumアドレス。特定のフォーマット（**EIP55**）に従っている必要があります。

:::message
**EIP55**については以下の記事を参考にしてください。
:::

[\[EIP55\] Ethereumアドレスのチェックサムの仕組みを理解しよう！](/articles/985f03760df12929b5f9)

- **`statement`**
    - サービス提供者がユーザーに伝えたい任意のメッセージや声明。
- **`uri`**
    - サービスやトランザクションに関連するウェブアドレス。
- **`version`**
    - メッセージフォーマットのバージョン。
- **`chain-id`**
    - トランザクションが行われるEthereumのチェーンID。
- **`nonce`**
    - このメッセージが一意であることを保証するためのランダムな文字列。
- **`issued-at`, `expiration-time`, `not-before`**
    - メッセージが発行された時間、有効期限、及びその効力が始まる時間。
- **`request-id`**
    - トランザクションの一意識別子。
- **`resources`**
    - トランザクションに関連する追加リソースのリスト。

このように、SIWEメッセージはユーザーとサービス提供者の間で安全なコミュニケーションを確保するための多くの要素を含んでいます。
ユーザーはこのメッセージを署名し、サービス提供者に送信することで、自分のEthereumアカウントを使って確実にサインインできるようになります。

#### メッセージフィールド

「**Sign-In with Ethereum**」（**SIWE**）メッセージは、Ethereumアカウントで安全にサービスにログインするために使用される情報の集まりです。
各フィールドは、サインインプロセスの異なる側面を扱い、特定の情報を提供します。
ここでの説明は、これらのフィールドが何を意味するのか、そしてそれらがどのように機能するのかをより理解しやすくするためのものです。

- **scheme (選択可)**
    - これはウェブサイトのプロトコル（httpやhttpsなど）を示します。
    - これにより、リクエストがどのようなタイプの接続を通じて行われたかがわかります。

- **domain (必須)**
    - サインインを要求しているウェブサイトのアドレスです。
    - これにより、ユーザーはどのサイトが認証を求めているのかを知ることができます。

- **address (必須)**
    - ユーザーのEthereumアドレスで、署名の実行者として機能します。
    - これはユーザーのデジタル身分を示すものです。

- **statement (選択可)**
    - ユーザーがサインするメッセージで、何を承認しているのかを明確にします。
    - これは通常、短く、理解しやすい文章です。

- **uri (必須)**
    - このサインインが関連する具体的なウェブページやリソースのアドレスです。
    - サインインが何に関連しているのかを示します。

- **version (必須)**
    - 使用されている**SIWE**メッセージのバージョンで、現在は`1`です。
    - これにより、将来的な更新や変更を管理できます。

- **chain-id (必須)**
    - トランザクションが行われるEthereumのチェーンを示します。
    - 異なるチェーンには異なる特性があります。

- **nonce (必須)**
    - このランダムな文字列は、同じメッセージが再利用されるのを防ぎます。
    - これはセキュリティを強化するために重要です。

- **issued-at (必須)**
    - メッセージが生成された正確な時刻。
    - これにより、メッセージが最新であることが保証されます。

- **expiration-time (選択可)**
    - メッセージの有効期限。
    - これが過ぎると、メッセージは無効になります。

- **not-before (選択可)**
    - メッセージが有効になる時刻。
    - これまでには、メッセージは使用できません。

- **request-id (選択可)**
    - 特定のサインイン要求を識別するためのID。
    - これにより、特定の要求を追跡できます。

- **resources (選択可)**
    - 認証中に参照されるかもしれない追加情報のリスト。
    - これにより、サインインプロセスがよりリッチで情報に富んだものになります。

これらのフィールドは、ユーザーがEthereumアカウントを使用してオンラインサービスにサインインする時に、透明性、セキュリティ、利便性を確保するために設計されています。

#### 非公式メッセージのテンプレート

「**Sign-In with Ethereum**」（**SIWE**）メッセージの非公式テンプレートは、ユーザーがEthereumアカウントでオンラインサービスにログインする時に使用される情報を簡潔に示しています。
このテンプレートは特に、メッセージの構造を直感的に理解するためにデザインされています。
各変数（`${...}`）はメッセージの特定の部分を表しており、その内容や目的を以下になります。

```
${scheme}:// ${domain} wants you to sign in with your Ethereum account:
${address}

${statement}

URI: ${uri}
Version: ${version}
Chain ID: ${chain-id}
Nonce: ${nonce}
Issued At: ${issued-at}
Expiration Time: ${expiration-time}
Not Before: ${not-before}
Request ID: ${request-id}
Resources:
- ${resources[0]}
- ${resources[1]}
...
- ${resources[n]}
```

- **${scheme}:// ${domain}**
    - この部分はサービスのウェブアドレスを示し、どのドメインがEthereumアカウントでのサインインを求めているのかを表します。
    - `scheme`は通信のプロトコル（通常はhttps）、`domain`はそのサービスのドメイン名（例：`example.com`）です。

- **${address}**
    - これはあなたのEthereumアドレスを指し、サインインする時にどのアカウントが使用されるかを示します。

- **${statement}**
    - サービスがあなたに提示するメッセージや声明で、あなたが何に同意しているのかを示します。

- **URI: ${uri}**
    - 署名が関連する具体的なリソースまたはサービスの場所を指すウェブアドレスです。

- **Version: ${version}**
    - **SIWE**メッセージのフォーマットバージョンを示します。

- **Chain ID: ${chain-id}**
    - トランザクションが行われるEthereumのチェーンを識別します。

- **Nonce: ${nonce}**
    - 一意性を保証し、リプレイ攻撃を防ぐためのランダムな文字列です。

- **Issued At: ${issued-at}**
    - メッセージが作成された正確な日時です。

- **Expiration Time: ${expiration-time}**
    - メッセージが無効になる日時です。

- **Not Before: ${not-before}**
    - メッセージが有効になる開始日時です。

- **Request ID: ${request-id}**
    - 特定のサインインリクエストを識別するための一意のIDです。

- **Resources**
    - 認証プロセス中にサービスが確認する追加情報のリストです。
    - 各リソースはURIで示されます。

このテンプレートは、**SIWE**メッセージの基本的な理解を助けるためのものであり、実際にはより複雑な**ABNF**メッセージフォーマットに従って正確に構成される必要があります。
このテンプレートは、どのような情報がメッセージに含まれ、各部分がどのような目的を果たしているのかを簡潔に理解する手助けとなります。

#### 例

各例には、サービスのドメイン、ユーザーのEthereumアドレス、利用規約への同意、リクエストの詳細などが記載されています。

##### 暗黙的スキームの例

```
example.com wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

I accept the ExampleOrg Terms of Service: https://example.com/tos

URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
Resources:
- ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/
- https://example.com/my-web2-claim.json
```

- サービス「`example.com`」があなたのEthereumアドレスを使用してログインすることを求めています。
- あなたはサービスの利用規約に同意し、特定のログインページ（URI）にアクセスします。
- メッセージにはEthereumメインネットへの参照（チェーンID）、ナンス、メッセージの発行時刻などが含まれています。
- 追加リソースとして、IPFSリンクとウェブリンクが提供されています。

##### 暗黙的スキームと明示的ポートの例

```
example.com:3388 wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

I accept the ExampleOrg Terms of Service: https://example.com/tos

URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
Resources:
- ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/
- https://example.com/my-web2-claim.json
```

- これは基本的に最初の例と同じですが、ドメインには特定のポート（`3388`）が含まれています。
- これは、サービスが特定のポートを通じて通信することを示しています。

##### 明示的スキームの例

```
https://example.com wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

I accept the ExampleOrg Terms of Service: https://example.com/tos

URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
Resources:
- ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/
- https://example.com/my-web2-claim.json
```

- ここでは、サービスが明示的に`https`プロトコルを使用することが指定されており、「`https://example.com`」がログインを要求しています。
- 他の詳細は上記の例と同様です。

これらの例は、**SIWE**メッセージがどのように構成されるか、そしてそれがどのような情報を含んでいるかを示しています。
ユーザーが自分のEthereumアカウントを使用してログインする時のプロセスが、これらのメッセージを通じてどのように進行するかを理解するのに役立ちます。

### イーサリアムアカウントによるメッセージの署名と検証

Ethereumアカウントを使ったメッセージの署名とその検証には、アカウントのタイプに応じた特定の方法があります。
これらはセキュリティを確保し、信頼性のあるやりとりを行うために重要です。

#### 外部所有アカウント（EOAs）
これらのアカウントは、個人が直接管理する通常のEthereumアカウントです。
メッセージに署名するときは、「**ERC191**」というルールに従います。
これはメッセージが本物であることを証明するための一般的な方法です。

:::message
**ERC191**については以下の記事を参考にしてください。
:::

[\[ERC191\] 署名済みデータを安全に使用する仕組みを理解しよう！](/articles/ee4edd15ad6fe7f58f7e)

#### コントラクトアカウント
これらはコードによって管理されるアカウントで、より複雑な機能を持っています。
通常、「**ERC1271**」という特別な検証ルールに従ってメッセージが検証されます。
これにより、コントラクトが署名を確認できるようになります。
もし「**ERC1271**」が使われない場合、別の確かな検証方法を明確に定義して使用する必要があります。
このタイプのアカウントでは、ブロックチェーンの状態によって検証結果が変わることがあるため、セキュリティと検証ルールに特に注意を払う必要があります。

:::message
**ERC1271**については以下の記事を参考にしてください。
:::

[\[ERC1271\] コントラクトで署名を検証する仕組みを理解しよう！](/articles/da237b1b8cc185491512)

これらの方法を適切に使用することで、ユーザーはEthereumアカウントを使って安全にサービスにサインインしたり、メッセージを信頼性高く交換したりすることができます。
重要なのは、適切な標準に従い、状況に応じて最も安全な方法を選択することです。

### イーサリアムネームサービス（ENS）データの解決

Ethereum Name Service（ENS）は、Ethereumのアドレスに対してより読みやすい名前や他の情報を関連付けるサービスです。
これにより、ユーザーが長く複雑なアドレスの代わりに簡単な名前を使用してトランザクションを行ったり、アカウントを識別したりすることができます。
具体的な解決可能なENSデータには以下のようなものがあります。

#### プライマリENS名
これは、あなたのEthereumアドレスに関連付けられた主な名前で、通常は「`yourname.eth`」のような形式です。

#### ENSアバター
あなたのアドレスに関連付けられた画像やアイコン。
これにより、視覚的にアカウントを識別できます。

#### その他のリソース
ENSのドキュメントに記載されている他のあらゆる情報。
これには、連絡先情報やソーシャルメディアのプロファイルなどが含まれることがあります。

信頼されるパーティーやウォレットがこれらの情報を解決することで、ユーザー体験を向上させることができますが、プライバシーを守るために注意が必要です。
特に、ENSデータを解決する過程でユーザーのアドレスが第三者に知られる可能性があるため、この情報がどのように使用され、共有されるのかについて明確なガイドラインと同意が必要です。
安全かつ透明な方法でENSの機能を利用することが、ユーザーの信頼とセキュリティを保つ鍵となります。

### ステップ

「**Sign-In with Ethereum**」（**SIWE**）メッセージを取り扱う時の重要な手順を説明します。

1. **リクエスト元の一致**
    - リクエストされたサインインの元となるドメイン（と場合によってはスキーム）は、**SIWE**メッセージに正確に記載されている必要があります。
    - これにより、サインインが要求された正確な場所が確認され、セキュリティが保たれます。

2. **メッセージの検証**
    - **SIWE**メッセージは特定の形式に従っている必要があり、メッセージの有効期限やナンスなどの期待される値に対してチェックされます。
    - さらに、メッセージの署名は適切な方法で確認されなければなりません。

3. **セッションの紐付け**
    - セッションはユーザーのアドレスに基づいて作成されるべきです。
    - 変更可能な情報に基づいてセッションを作成すると、セキュリティ上のリスクが生じる可能性があります。

4. **リソースの取り扱い**
    - メッセージに含まれるリソース（URI）は、ユーザーが理解しやすい形で表現されるべきです。
    - ただし、これらのリソースの具体的な解釈は**SIWE**メッセージの範囲外です。

これらの手順を適切に実装することで、ユーザーがEthereumアカウントを使用してサービスに安全にログインできるようになり、信頼性とセキュリティが確保されます。

### ウォレット導入ステップ

#### メッセージ・フォーマットの検証

ウォレット実装者が行うべき手順について説明します。

1. **メッセージ形式の厳格な検証**
    - 受け取った**SIWE**メッセージが正しい形式かどうかをチェックすることが必須です。
    - これは、メッセージが正確で信頼性のある情報を含んでいることを確実にするためです。
    - 特に、メッセージが正式なルール（**ABNF**フォーマット）に従っているかを検証します。

2. **不審なメッセージに対する警告**
    - ユーザーがサインインを求める特定の文言（例: **"wants you to sign in with your Ethereum account"**）を含むメッセージに対しては特に注意が必要です。
    - もしそのメッセージが正式な形式に完全に準拠していない場合、ユーザーに警告を発するべきです。
    - これにより、ユーザーが誤って不適切なメッセージに署名するリスクを減らすことができます。

これらの手順は、ウォレットがユーザーの安全を守り、信頼性の高い操作を保証するために重要です。
正しい形式のメッセージのみを扱い、疑わしいリクエストに対しては警告を発することで、安全な環境を提供します。

#### リクエスト元の確認

ウォレット実装者が行うリクエスト元の検証手順を説明します。

1. **リクエスト元の一致確認**
    - サインインリクエストが正しいウェブサイト（例：`https://example.com`）から来ているかを確認します。
    - これは、**SIWE**メッセージのドメインとスキーム情報を使って行います。
    - これにより、ユーザーが安全でない偽サイトに誤って情報を提供するリスクを減らします。

2. **信頼される情報源からの確認**
    - リクエストが発信された元の場所は、ブラウザウィンドウやWalletConnectセッションなどの信頼できる情報源から取得されるべきです。
    - これは、リクエストの正当性を確実にするためです。

3. **ローカルホストへの対応**
    - リクエスト元がローカルホスト（開発中のプロジェクトなど）の場合、完全に拒否するのではなく、警告を発することも選択できます。
    - これにより、開発中のプロジェクトでもテストがしやすくなります。

4. **推奨される検証アルゴリズム**
    - 入力変数（**SIWE**メッセージの内容、署名リクエストの元の場所、許可されたスキームなど）に基づいて、リクエスト元が正しいかどうかを確認するためのアルゴリズムを実行します。
    - 特に、元の場所がローカルホストの場合の対応や、スキームが指定されていない場合のデフォルト値の使用に注意します。

これらの手順は、ユーザーが正当なリクエストにのみ応答していることを確実にし、フィッシングなどの不正行為から保護するために重要です。
安全なサービス提供のため、これらの検証手順の正確な実装と適用が推奨されます。

ウォレットがリクエスト元を検証するためのアルゴリズムを説明します。

- **スキーム設定**
    - スキームが未指定の場合、ウォレットはデフォルト（通常は'https'）を使用します。

- **スキームの検証**
    - 許可されたスキームリストにリクエストのスキームがなければ、ウォレットはリクエストを拒否します。
    - 通常、安全性のために'https'のみが許可されます。

- **スキームの一致**
    - リクエストのスキームがウェブサイトのものと異なる場合、ウォレットは通常リクエストを拒否しますが、開発者モードでは警告を出して続行することもあります。

- **ドメインとホストの一致**
    - リクエストのドメインとウェブサイトのホストが異なる場合、ウォレットはリクエストを拒否します。
    - 開発者モードでは警告を出して続行することがあります。

- **サブドメインの一致**
    - ドメインと元の場所のサブドメインが異なる場合、通常はリクエストを拒否しますが、開発者モードでは警告を出して続行することがあります。

- **ポートの一致**
    - ポートが指定されている場合、それがウェブサイトのものと一致するかを確認します。
    - 異なる場合や、ポートが空でウェブサイトに特定のポートがある場合は警告を出すことがあります。

これらのステップにより、ウォレットはリクエストが正当なウェブサイトから来ていることを確認し、ユーザーがフィッシングサイトなどに誤って情報を渡さないように保護します。
開発者モードでは、一部の検証を緩和してテストがしやすくなるように設計されていますが、一般的な使用では厳格な検証が行われます。

#### イーサリアムインターフェイスを使ったサインインの作成

- **メッセージ内容の表示**
    - ウォレットは、ユーザーが署名する前に、スキーム、ドメイン、アドレス、声明、リソースなど、**SIWE**メッセージに含まれる重要な情報をデフォルトで表示する必要があります。
    - 他の存在するフィールドもユーザーに見せるべきです。

- **テキストスクロールの確認**
    - ウォレットは、ユーザーがプレーンテキストのメッセージを最後までスクロールして読んだことを確認するため、スクロールを要求することが推奨されます。

- **カスタムインターフェースの作成**
    - ウォレット実装者はメッセージをデータ要素に解析し、よりユーザーフレンドリーなカスタムインターフェースを作成できますが、重要な情報は依然として表示される必要があります。

これらの手順を通じて、ウォレット実装者はユーザーに明確で信頼性の高い署名プロセスを提供し、同時に多様なニーズに対応するインターフェースを実現できます。

#### 国際化（i18n）のサポート

メッセージが正常に解析された後、ユーザーインターフェースは異なる言語に翻訳されるかもしれません。
これにより、さまざまな言語を話すユーザーに対応できます。

## 補足

### 必要条件

「**Sign-In with Ethereum**」のための仕様作成における要件を説明します。

- **シンプルで実用的な仕様**
    - 仕様は簡潔で、既に広く採用されている方法に基づいているべきです。
    - 余計な機能や、少数プロジェクトの組み込みを避け、分散型でオープンなアプローチを取ります。

- **核心要件**
    - Ethereumアカウントを認証に利用し、ENS名をユーザー名として（逆解決により）、ENS名のテキストレコードから追加のプロファイル情報を取得します。
    - 集中型サーバーに依存することなく、アプリケーションが既に実行しているサーバーのみを使用します。

- **ユーザーインターフェース**
    - ユーザーには、署名する前に理解しやすいインターフェースが提示されるべきです。
    - コンピューター向けの複雑な表現（JSONブロブや16進コードなど）は極力排除します。

- **アプリケーションサーバーのサポート**
    - アプリケーション側はウォレット側の変更を強いることなく、サポートを実装できるべきです。

- **アップグレードパス**
    - 既存のEthereumアカウント署名を使用しているアプリケーションやウォレットには、シンプルで直接的なアップグレードパスが提供されるべきです。

- **セキュリティ対策**
    - 中間者攻撃、リプレイ攻撃、悪意ある署名リクエストなどに対する適切な緩和策とガイドラインが必要です。

これらの要件は、「**Sign-In with Ethereum**」がユーザーにとって安全で使いやすい認証方法であり続けるために重要です。

### 設計目標

「**Sign-In with Ethereum**」の設計目標を以下で説明します。

- **ヒューマンフレンドリー**
    - ユーザーにとって理解しやすく、使いやすいインターフェースを目指します。
    - これには、複雑な技術用語の回避や直感的な操作が含まれます。

- **実装のシンプルさ**
    - 開発者が容易に理解し実装できるよう、シンプルな設計を心がけます。
    - これにより、広範囲のアプリケーションやウォレットでの採用が促進されます。

- **セキュリティ**
    - ユーザーのデータとアイデンティティを保護するため、セキュリティを最優先事項とします。
    - これには、不正アクセスやデータ漏洩を防ぐための堅牢な対策が含まれます。

- **機械可読性**
    - システム間でのデータのやりとりがスムーズに行われるよう、メッセージは機械が解析しやすい形式であることが求められます。
    - これにより、自動化や効率的な処理が可能になります。

- **拡張性**
    - 将来の技術進化や新たな用途に対応できるよう、システムは拡張可能であるべきです。
    - これにより、長期的な持続可能性と柔軟性が保たれます。

これらの設計目標は、「**Sign-In with Ethereum**」が使いやすく、安全で、広く受け入れられるシステムとなるための基盤を提供します。

### 技術的決断

「**Sign-In with Ethereum**」の技術的決定に関する説明を説明します。

- **ERC-191（署名データ標準）をEIP-712より選んだ理由**
    - **ERC191**は多くのウォレットのユーザーインターフェースで広くサポートされている。
    - **ERC191**の実装は署名前にプリセットのプレフィックスを使用するだけでシンプル。
    - **ERC191**はより人間が読めるメッセージを生成するが、**EIP712**は機械処理用の署名出力を作成し、多くのウォレットで人間に優しく表示されない。

:::message
**EIP712**については以下の記事を参考にしてください。
:::

[\[EIP712\] 型付き構造化データのハッシュ化と署名の仕組みを理解しよう！](/articles/f54bc85cb66de5a54257)

- **JWT（JSON Web Token）を使用しない理由**
    - ウォレットはJWTをサポートしておらず、keccakハッシュ関数はJOSEアルゴリズムとしてIANAに割り当てられていない。

- **YAMLまたは例外付きYAMLを使用しない理由**
    - YAMLは**ABNF**に比べて緩く、ABNFは文字セットの制限、必要な順序、厳格な空白などを容易に表現できる。

これらの技術的決定は、「**Sign-In with Ethereum**」がシンプルで、広くサポートされ、ユーザーフレンドリーで、かつセキュアな認証方法を提供するために重要です。

![signing.png](/images/qiita-85d1017d-2118-86cf-81b3-c3fbc3c90e7f.webp)
引用: https://eips.ethereum.org/EIPS/eip-4361

### カバー範囲外

「**Sign-In with Ethereum**」仕様の現バージョンでは、以下のような項目は範囲外とされています。

- **Ethereumアドレス以外の認証方法**
    - この仕様は、Ethereumアドレスに基づく認証方法に焦点を当てており、それ以外の方法は含まれていません。

- **サーバーリソースへのアクセス認可**
    - サーバー側でのリソースアクセスを管理する認可プロセスは、この仕様の範囲外です。

- **リソースフィールドのURIの扱い**
    - リソースフィールド内のURIを、クレームやその他のリソースとしてどう解釈するかについての詳細は、この仕様では定義されていません。

- **ドメインバインディングのメカニズム**
    - ドメインとリクエストを関連付けるための具体的な技術的手法は、この仕様では扱われていません。

- **ナンスの生成と評価**
    - 一度だけ使用される数値（ナンス）をどのように生成し、その適切性をどう評価するかについては、範囲外とされています。

- **TLS非使用時のプロトコル**
    - 暗号化されていない接続（TLS非使用）での使用に関するプロトコルも、この仕様では取り上げられていません。

これらの項目は、現在の仕様では対象外ですが、将来的に追加される可能性があります。
現バージョンの主な目的は、シンプルで効果的なEthereumベースの認証システムを提供することにあります。

### 互換性に関する考察

「**Sign-In with Ethereum**」の将来の互換性に関する検討事項を説明します。

- **分散型識別子と検証可能な証明書**
    - DIDsや検証可能な証明書のような、デジタルアイデンティティに関連する技術を統合する可能性があり、これによりユーザーのアイデンティティ管理がさらに豊かで安全になるかもしれません。

- **クロスチェーンサポート**
    - Ethereum以外のブロックチェーンとの相互運用性を提供することで、さまざまなブロックチェーン技術を使用するユーザーもサポートする可能性があります。

- **SIOPv2サポート**
    - 新しい認証プロトコルや標準への対応を通じて、より幅広いユーザーのニーズに応えるための機能を拡張する可能性があります。

- **EIP-712の将来的なサポート**
    - **EIP712**などの改善提案への対応により、ユーザーがよりわかりやすい署名プロセスを体験できるようになるかもしれません。

- **バージョン解釈ルール**
    - 仕様の将来的な更新に柔軟に対応できるよう、バージョン管理と解釈に関するルールを設定し、安定したアップグレード経路を提供する可能性があります。

これらの検討事項は、システムの将来的な拡張性と柔軟性を確保し、ユーザーにとってより便利で安全な認証体験を実現するためのものです。

## 互換性

「**Sign-In with Ethereum**」の基盤となる**ERC191**は、すでに多くのウォレットにサポートされています。
この既存のサポートを基に、利用規約の受諾、リプレイ攻撃を防ぐナンス、メッセージに含まれるEthereumアドレスなど、追加機能が組み合わされています。
これらの要件は、類似するサインインワークフローが採用している既存の実装から取り入れられています。

このアプローチにより、「**Sign-In with Ethereum**」は広く受け入れられた技術の上に構築されると同時に、よりユーザーフレンドリーでセキュアな認証体験を提供します。
ユーザーは明確な手順に従ってサービスの利用規約に同意し、自分のEthereumアドレスを使用して確実にサインインできます。
また、ナンスを使用することで、セキュリティも強化されています。

## 実装

参考実装は以下になります。

https://eips.ethereum.org/assets/eip-4361/example.js

## セキュリティ

### 識別子の再利用

「**Sign-In with Ethereum**」での識別子再利用に関する考慮事項は、ユーザーのプライバシー保護に重点を置いています。

- **プライバシーの最大化**
    - ユーザーが各インタラクションで新しい、関連性のないEthereumアドレスを使用することで、より完全なプライバシーが実現されます。
    - これにより、必要最小限の情報のみが開示され、余計な情報漏洩が防げます。

- **初期採用者への影響**
    - 現在のところ、自身と関連付けたEthereumアドレスを持つユーザーなど、初期採用者にはこのプライバシーへの配慮がそれほど重要ではないかもしれません。
    - 彼らはサービス間で同一のアイデンティティを維持するため、識別子の再利用を好むことが多いです。

- **主流への採用とプライバシー保護の向上**
    - 主流への採用が進むにつれ、プライバシーへの配慮がより重要になります。
    - HDウォレットやゼロ知識証明などの高度な技術を利用することで、ユーザーのプライバシーをさらに保護できる可能性がありますが、これらは現在の仕様では対象外です。

:::message
この仕様はユーザーのプライバシーを重視しつつ、現時点では特にプライバシーに敏感でない初期採用者のニーズにも応えるよう設計されています。
将来的には、より高度なプライバシー保護技術が組み込まれる可能性があります。
:::

### キーマネージメント

「**Sign-In with Ethereum**」におけるキーマネジメントは、ユーザーが自身のキーを通じてコントロールを持つことを意味しますが、これは同時に彼らにとって新しい責任も伴います。
特に、中央集権型のアイデンティティプロバイダーに慣れている主流のユーザーにとっては、キーマネジメントは未知の領域であり、パスワードを忘れた時に簡単に回復できる手段がないという点で難易度が高い問題です。

初期採用者はすでにキーマネジメントに精通している可能性が高いですが、主流への採用が進むにつれて、より多くの一般ユーザーがこれに直面するため、この問題はより重要になります。
解決策として、スマートコントラクトやマルチシグを使用するウォレットがあり、これらは**ERC1271**署名を通じてキーの使用と回復を簡素化し、ユーザーエクスペリエンスを向上させます。

:::message
キーマネジメントは「**Sign-In with Ethereum**」を使用する上での重要な側面であり、初期採用者から一般ユーザーに至るまで、より安全で簡単な方法を提供することが今後の課題です。
:::

### ウォレットとユーザーを組み合わせたセキュリティ

「**Sign-In with Ethereum**」におけるウォレットと依存するパーティーのセキュリティ対策について説明します。

- **両者の連携によるセキュリティ強化**
    - エンドユーザーに提供されるセキュリティを向上させるためには、ウォレットと依存するパーティー双方がこの仕様を適切に実装し協力する必要があります。

- **リクエスト元の確認の重要性**
    - ウォレットは、**SIWE**メッセージが正しいリクエスト元（例えば、正しいウェブサイト）から来ていることを確認する責任を持ちます。
    - これは、ユーザーがフィッシングサイトなどの悪意あるリクエストに騙されないようにするためです。
    - ウォレットは、ユーザーが自分でこの確認を行えるような手段（視覚的確認など）も提供することが求められます。

- **フィッシング攻撃への対応**
    - このリクエスト元の確認が適切に行われなければ、ユーザーはフィッシング攻撃などのリスクにさらされます。
    - そのため、ウォレットはリクエストの正当性を確認するための厳格なプロセスを持つことが非常に重要です。

:::message
ウォレットと依存するパーティーが協力し、リクエスト元を確認することによって、ユーザーのセキュリティを強化し、フィッシングなどのリスクから守るための対策が講じられています。
:::

### ウォレットとサーバーの相互作用の最小化

「**Sign-In with Ethereum**」においてウォレットとサーバーの相互作用を最小限に抑えることは、ユーザーのプライバシーを保護する上で重要な側面です。

- **サインインワークフローの選択**
    - サーバーからウォレットへのパラメータ送信とクライアント側での完全な**SIWE**メッセージ生成という、二つの異なる実装アプローチがあります。
    - プライバシー保護の観点から、サーバーとの相互作用を最小限に抑える後者のアプローチが推奨されます。

- **リプレイ攻撃防止**
    - バックエンドサーバーがナンスを生成してリプレイ攻撃を防ぐ一方で、プライバシーを保護する代替手段も考慮されています。

- **ウォレットとサーバーのコミュニケーション**
    - ウォレットはサーバーに相談して、適切なナンスやリソースセットなどの署名されるメッセージの内容を確認する場合があります。
    - この際、ユーザー情報の漏洩を防ぐための措置を講じることが重要です。

- **ユーザーの好みへの対応**
    - ウォレットは署名前にユーザーの好みを確認することがあります。
    - これには、多くのアドレスの中から一つを選ぶ、または複数のENS名の中から好みのものを選ぶといった選択が含まれる場合があります。

このように、ウォレットとサーバーの相互作用を慎重に扱い、ユーザーの好みやプライバシーに配慮することで、安全で信頼性の高いサインイン体験を提供することが目指されています。

### リプレイ攻撃の防止

「**Sign-In with Ethereum**」におけるリプレイ攻撃の防止に関する説明は、セッション開始時に適切なナンスを選択することの重要性に焦点を当てています。
リプレイ攻撃は、攻撃者がユーザーの署名を盗み、新しいセッションを不正に確立する中間者攻撃です。
これを防ぐためには、各セッション開始時に十分なエントロピー（予測不可能性）を持つ一度限りの数値（ナンス）を使用することが重要です。
さらに、プライバシーを尊重しつつ広く利用可能な値、例えば最近のEthereumブロックハッシュやUnixタイムスタンプをナンスとして利用することも検討されています。
これにより、ユーザーがリプレイ攻撃のリスクから守られると同時に、プライバシーも保護されます。

### フィッシング攻撃の防止

フィッシング攻撃を防ぐための対策として、ウォレットはリクエストが正当な場所から送信されたものであるかを検証するプロセスを実装する必要があります。
このプロセスは「**リクエスト元の検証**」と呼ばれ、ウォレットが**SIWE**メッセージが本当に正しい元、つまりユーザーが意図したとおりのサービスから来ているかを確認することを意味します。
この検証を行うことで、ウォレットは攻撃者が偽のリクエストを送信し、ユーザーを騙して誤った行動を取らせることを防ぐことができます。
このように、リクエスト元の正確な確認はユーザーを保護し、安全なサインイン体験を提供するために不可欠です。

### チャネル・セキュリティ

ウェブベースのアプリケーションにおけるチャネルセキュリティに関する対策は、ユーザーの通信を保護し、安全な「**Sign-In with Ethereum**」体験を提供するために重要です。
具体的には、次のような対策が推奨されています。

#### HTTPSの使用
メッセージ署名のプロセスにおいて中間者攻撃を防ぐため、全ての通信にはHTTPSを使用することが推奨されます。
HTTPSは通信を暗号化し、データの機密性、完整性、そして送信者と受信者の真正性を保証します。

#### HTTPS以外のプロトコルの使用時の保護対策
もしHTTPS以外のプロトコルを使用する場合でも、通信の機密性、データの完整性、送信者と受信者の真正性を維持するための適切な保護技術を使用することが推奨されます。
これには、強固な暗号化技術やセキュリティプロトコルの適用が含まれます。

これらの対策によって、ユーザーの通信は保護され、安全な環境での認証プロセスが実現されます。
安全なチャネルを確保することは、フィッシング攻撃やデータ漏洩などのセキュリティリスクを軽減し、ユーザー信頼とサービスの信頼性を高めるために不可欠です。

### セッション無効化

「**Sign-In with Ethereum**」におけるセッション無効化のプロセスは、セッションの安全性を保つために特定の状態変更を確認することに関連しています。
特に、**ERC1271**実装やそれに依存するデータが変更された場合、これが署名計算に影響を及ぼす可能性があるため、サーバーはセッションを適切に無効化する必要があります。
また、`resources`フィールドで指定されたリソースが変更された場合も同様に、サーバーはセッションを無効化すべきです。
ただし、リソースの具体的な解釈はこの仕様の範囲外です。
これらの対策は、ユーザーのセッションが最新で安全であることを保証し、不正アクセスやデータの不正利用を防ぐために重要です。

:::message
**ERC1271**については以下の記事を参考にしてください。
:::

[\[ERC1271\] コントラクトで署名を検証する仕組みを理解しよう！](/articles/da237b1b8cc185491512)

### ABNF用語の最大長

この仕様ではABNF用語の具体的な最大文字列長に関する規範的な要件は設定されていませんが、実装者はサービス拒否攻撃の防止、様々な使用事例への対応、およびユーザーの可読性の3つの側面のバランスを考慮して適切な最大長を選択することが推奨されています。
長すぎる文字列はシステムに過大な負荷をかけたり、使用が不便になる可能性があるため、適切な長さの設定はセキュリティとユーザビリティを確保するために重要です。
このように、実装者はシステムの安全性とユーザー体験の質を保つために、各用語の最大長を慎重に選ぶべきです。

## 引用

Wayne Chang (@wyc), Gregory Rocco (@obstropolos), Brantly Millegan (@brantlymillegan), Nick Johnson (@Arachnid), Oliver Terbu (@awoie), "ERC-4361: Sign-In with Ethereum [DRAFT]," Ethereum Improvement Proposals, no. 4361, October 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4361.

## 最後に

今回は「Ethereumアカウントを使用して、オフチェーンサービスにログインする方法を提案している**ERC4361**」についてまとめてきました！
いかがだったでしょうか？

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

[Twitter @cardene777](https://twitter.com/cardene777)

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
