最近、Web3 の出現とウォレットの使用の拡大により、ユーザーが従来の電子メール/パスワード ベースのアカウント システムを捨て、代わりにウォレットを使用してログインするようになることを示唆する記事をかなり見てきました。
正直なところ、いくつかの dApps を使用した後、ポップアップするウォレットを 1 回または 2 回クリックするという非常にシンプルなワークフローは、確かに優れたエクスペリエンスです。
これらの記事の多くは、「もう JWT は必要ありません!」と言っています。
これは私が同意しないところです。
JWT は、最初は少し混乱しますが、バックエンド エンジニア、特にマイクロサービス システムのエンジニアにとって非常に便利です。特に、これらのシステム (多数のシステム) がすでに存在し、JWT と統合されていることを考えると!イーサリアムは素晴らしいですが、一からやり直す必要はありません。必要なときに使い慣れたバックエンド ツールを引き続き使用できるのは良いことです。
MetaMask でログインすると、それがあなたであることを証明できますが、将来の API 呼び出しに対してどのようにしてそれがあなたであることを証明できますか?
「スクリュー JWT」の連中は単純なセッション ID の使用を提案していますが、これは 2000 年代初頭にさかのぼります。単純なレイヤード アーキテクチャが標準であり、今日のバックエンド システムのような複雑さはありませんでした。
残念ながら、付与されたセッション ID が有効なセッションに属しているかどうかを判断するために、データベースへのラウンド トリップを追加しない限り、セッション ID を検証することはできません。これは、バックエンド サービスがセッション ID を含むリクエストを受信すると、それ自体が認証サーバーに「これはアクティブか」と尋ねるリクエストを作成し、マイクロサービス システム内の他のすべてのサービスが同じことを尋ねることを意味します。
関連するサービスが複数ある場合は、認証サービスへの追加のラウンドトリップが数回発生する可能性があります。
この状況を改善するために、暗号の専門家は考えました。
彼らが思いついたのは JWT でした。現在は OpenID 標準の一部であり、Keycloak、Auth0 などが実装を支援します。
解決策は、一連のトークン (正確には JSON Web トークン) を付与することでした。このセットは、 AccessToken
、 RefreshToken
、およびIdToken
で構成されます。これらのトークンは、通常ClientSecret
と呼ばれるシークレットによって「署名」されました。同じページにいるように、署名は、JWT の場合、暗号化ハッシュ アルゴリズムです。通常はHS256
(Auth0 のデフォルト) です。 HS256
の場合、 ClientSecret
が入力として使用されるため、そのハッシュを正常に解読、つまり「検証」するために必要なキーになります。 RS256
およびES256
、公開鍵と秘密鍵のペアが使用されます。つまり、秘密鍵で署名され、クライアントで公開鍵で検証されます。
これは、バックエンド サービスがこれらのトークンの 1 つを受け取り、 ClientSecret
を知っている場合、そのトークンに署名した認証サービスによってトークンが実際に発行されたことを確認できることを意味します。バックエンド サービスへのアクセスを試行するときに使用されるトークンはAccessToken
です。これらのトークンには、具体的には、ユーザーが誰であるか、およびその「主張」に関する情報、つまり、それを気にするシステム用にフォーマットされた、ユーザーが何をすることが許可されているかに関する情報が含まれています。
マイクロサービス システムの場合、ID の検証に関心のある各サービスは、データベースへのラウンドトリップではなく、ClientSecret を使用して JWT が本物であることを検証できるため、 ClientSecret
について知る必要があることを意味します。多くのマイクロサービスを備えたシステムでは、これにより、データベースへの追加のラウンドトリップが大幅に削減され、システム全体のスケーラビリティが向上します。
アクセス トークンが盗まれると、悪意を持って使用される可能性があります。そのため、アクセス トークンを使用するシステムを設計する際には、適切な予防措置を講じることが重要です。
トークンの署名と検証に加えて、最低限の予防策は次のとおりです。
Access Token JWT の有効期限を 5 ~ 15 分に設定し、トークンを受け取ったときに期限切れにならないようにする
アクセストークンをメモリ以外に保存しない
保存して検証のためにサーバーに送信できる更新トークンを発行し、それを発行したClientSecret
とClientId
を使用して更新します。
TLS 接続 (HTTPS) を介して送信される場合にのみ使用します
HTTP のみの Cookie を使用して、ブラウザ側で変更できないようにする
CORS 設定
このアルゴリズムでは、ハッシュ出力と同じサイズ (たとえば、「HS256」の場合は 256 ビット) またはそれ以上のキーを使用する必要があります。 - RFC7518 、注意: Auth0 は HS256 に 512ビットを使用します。
機密性の高いクライアントには、Node.js などの中間サーバーが必要です。このサーバーは認証サービスへのプロキシであるため、クライアントはクライアント シークレットについて知る必要はありません。パブリック クライアントはクライアント シークレットを公開し、ブラウザーと認証サービスの間にプロキシ サーバーはありません。これは CORS 設定でさらに制限できるため、特定のドメインからのリクエストのみが許可されます。
追加の予防措置には次のものがあります。
さらに、たとえば、取り消された更新トークンを使用しようとしている人を検出した場合、そのユーザーのアクティブな更新トークンをすべて取り消すことができます。
確かに、これらの予防策はすべて、正しく行うのを少し難しくする可能性があります.理解すべきことがたくさんあります。使い勝手の問題もあります。 5 分ごとにサイトからログアウトされるユーザーは、非常に煩わしく感じます。これを回避するには、消費側アプリケーションにサイレント リフレッシュ ループを実装して、トークン セットを継続的にリフレッシュする必要があります。
とはいえ、それを正しく行うことの反対側では、スケーラブルな方法ですべてのバックエンド システムと安全に統合できること、およびHasuraなどの多くの既存のツールをベースにすべての API を自動生成できることです。接続された Postgres の DB スキーマ。したがって、既存のツールと簡単に統合できると、開発時間を大幅に節約できます。
すでに OpenId を使用している場合は、これらの機能がすでに整っている可能性があります。結局のところ、これは認証標準です。
では、Web3 で JWT を使用し、MetaMask の世界でログインするという利便性を維持するにはどうすればよいでしょうか?
SSO に使用される OpenId 認証フローを理解することから始めましょう。
web3auth の世界では、ステップ 2 を、ウォレットの秘密鍵と公開鍵のペアを使用してチャレンジに署名することに置き換えています。リダイレクトは不要であり、望ましくありません。
ウェブサイトにアクセスし、自分のアカウントでログインしたい - ログインボタンをクリックする
認証サーバーからチャレンジを受け取り、ウォレットを開いてチャレンジに「署名」するように求めます。記号を押します。
認証サーバーは署名を検証し、適切に保存され、サイレント リフレッシュ バックグラウンド フローで使用される一連の JWT を発行します。
SSO スタイルのリダイレクト フローを、ウォレットによって署名されたチャレンジに置き換えるだけです。トークンを受け取った後のフローは、OpenID と同じです。つまり、たとえば、JWT 発行サーバーで OpenID の使用から web3auth の使用に切り替えることができ、トークンが付与された後のこれらのトークンの使用について変更する必要はありません。 Hasura などのツールとの既存のバックエンド統合はすべて、まったく同じままです。
これこそが、私が Full Cycle 開発者として望んでいることです。車輪の再発明はしたくありません。 OpenID を web3auth に置き換えて、使い慣れた強力なツールをすべて使用できるようにしたいと考えています。
残念ながら、セキュリティ上の予防策と同様にこれを行う web3auth サーバーを見つけることができませんでした。プロセスのテクニックを示すいくつかのプロジェクトを見つけましたが、フロー全体ではありませんでした。
だから私は建物にたどり着きました…
ここに認証サーバーを構築しました: https://github.com/CloudNativeEntrepreneur/web3auth-service
そして、これと一緒にSvelteKitを統合すると、サイレント リフレッシュ、ヤダ ヤダなどのすべてが実装されます。
もちろん、GraphQL クライアントとサンプルがある場合は、GraphQL サーバーとデータベースも必要だったので、そのサンプルも提供しました: https://github.com/CloudNativeEntrepreneur/example-hasura + https: //github.com/CloudNativeEntrepreneur/example-readmodel
この例では、 Zalando Postgres オペレーターとSchemaHeroを使用しているため、DB を宣言し、スキーマを YAML で記述するだけで、Hasura が必要なすべての GraphQL API を自動生成します。そして、Hasura を念頭に置いて認証サーバーを作成したので、Hasura の RBAC とパーミッションを統合するための適切な主張があり、非常に堅牢です。
そしてもちろん、これらすべてを実行する場所が必要です。したがって、istio、オペレーター、SchemaHero などのすべてのツールをセットアップするローカル開発クラスターが必要です! https://github.com/CloudNativeEntrepreneur/local-dev-cluster
しかし、それをすべて使用する方法さえ誰が知っていますか?
だから私はこのメタリポジトリを作成しました: https://github.com/CloudNativeEntrepreneur/web3auth-meta
そのメタ リポジトリを使用すると、必要なすべてのプロジェクトが適切な場所にクローンされ、すべて一緒に実行されます。
最後に、すべてのプロジェクトを一緒に実行するには、ツールをインストールする必要があり、ツールをインストールするのは面倒です。 https://github.com/CloudNativeEntrepreneur/onboard
また、npm でsveltekit-web3auth
を公開し、それを使用する SvelteKit プロジェクトからテンプレートを作成し、GraphQL をセットアップして Hasura インスタンスへの認証と統合したので、独自のプロジェクトを作成する準備ができたら、それを使用できます。テンプレとして! https://github.com/CloudNativeEntrepreneur/sveltekit-web3auth-template
まだ web3 認証の世界の準備ができていない場合は、ローカル開発クラスターに接続するように事前構成されたhttps://github.com/CloudNativeEntrepreneur/sveltekit-oidcと、その中にセットアップされた Keycloak インスタンスを使用することもできます。それ。両方のプロジェクトがどのように JWT を発行するかを見て、目標は認証システムを交換可能にすることです - web3auth または従来の OIDC を使用します - トークンの上流での使用法は同じです。
自動生成された GraphQL API、堅牢な RBAC、アクセス許可とサブスクリプション、認証済み SSR ページ、サイレント リフレッシュ ループ、ローテーション リフレッシュ トークンなどを備えたハイブリッド dApp を作成してみましょう。
結論として、いいえ、JWT と Ethereum/metamask を使用したログインは相互に排他的ではありません。実際、開発者の生産性と既存のツールとの統合が好きなら、JWT と web3auth を使用するとうまくいくと思います。
乾杯!
相談に応じます!あなたが取り組んでいるプロジェクトに関する私の支援に興味がある場合は、Twitter でメッセージを送ってください。