技術シリーズ#8: Vite Connectの概要
背景
ViteXに統合されるサードパーティ製のゲートウェイが増えるにつれ、サードパーティ製のサービスが増えるため、セキュリティリスクが高まります。ニーモニックシード(または秘密鍵)をブラウザに保存するのは十分なセキュリティではありません。ウェブクライアントからニーモニック/秘密鍵を分離するためのリモート署名ソリューションを見つけることが急務となっています。ハードウェアウォレットの代替として、Vite モバイルアプリに保存された秘密鍵を使用して、Vite ウェブウォレットから送信されたトランザクションに署名する必要があります。最終的なソリューションは、安全で便利で実装が簡単なものでなければなりません。
まず、既存の2つのソリューションを見てみましょう。
2つのソリューションの主な違いは、ピア間の接続タイプです。 以下では、説明のために https://developer.mozilla.org のWebRTCアーキテクチャからいくつかの用語と図を引用します。
MEWconnect
- MEWconnect は、STUN (Session Traversal Utilities for NAT) サーバを実装しています。サーバは2つのピアのNATタイプを検出し、お互いのパブリックネットワークアドレスを両当事者に公開します(注意:これは一部のNATタイプでは実現できません)。
- お互いのパブリックネットワークアドレスを知った後、2つのピアは直接通信します。
MEWconnectには中継サーバがありません。通信データにアクセスできるのは2つのピア以外にはありません。しかしながら、ほとんどの3 / 4GネットワークはP2P通信を実現できない対称NATの下にあるため、MEWconnectは私たちの要件を満たしていません。
WalletConnect
WalletConnectは、TURN(Traversal Using Relays around NAT)のような中継サーバを実装しています。一度登録してしまえば、中継サーバを介してお互いのピアを探し出して通信することができるので、3/4Gネットワークでも通常の通信が可能になります。これが最終的にViteConnectで採用した設計です。
ここでは、Webクライアントとモバイルアプリのハンドシェイクのプロセス、つまりViteConnectの典型的な利用シーンを深く見てみましょう。
WalletConnectでのハンドシェイクプロセス
- ウェブクライアントはキーとハンドシェイクトピックを生成し、サーバーのインターネットアドレスを含むQRコードの形式で表示します。
- ウェブクライアントは、サーバー上のハンドシェイクトピックにセッション要求を送信し、ウェブクライアントトピックを送信してから、受信メッセージのためにウェブクライアントトピックをサブスクライブします。
- モバイルアプリはQRコードをスキャンしてサーバーに接続し、ハンドシェイクトピックからセッション要求を取得します。 キーでメッセージを復号化した後、モバイルアプリはウェブクライアントトピックを取得できます。以降のウェブクライアントへのメッセージは、このトピックを介して公開されます。このとき、モバイルアプリは approveSession メッセージを送信し、モバイルクライアントトピックを伝えます。
- Web クライアントは approveSession メッセージを受信し、モバイルクライアントトピックを取得します。それ以降のモバイルアプリへのメッセージは、このトピックを通して公開されます。
特徴
- すべてのメッセージは暗号化されています。暗号化キーは二者間でしか知られておらず、サーバーには透過的です。
- セッション確立時には、プライベートトピック(ウェブクライアントトピック、モバイルクライアントトピック)がセキュアに交換され、公開されることはありません。
- セッションリクエストの送信と利用は一度きりなので、QRコードのハンドシェイクトピックと暗号化キーの内容が漏洩した場合でも、攻撃者は二者のプライベートトピックにアクセスできません。
WalletConnectの既知の問題点
- 暗号化キーはハンドシェイク中に更新されません。 QRコードと暗号化されたメッセージが公開されると、第三者がメッセージを読み取ることができます。
- プライベートトピックは一度だけ生成され、デバイス内のローカルにキャッシュされます。一度漏洩すると、暗号化されたメッセージは第三者に傍受される可能性があります。
- ピアはお互いを見ることができず、さらにサーバーはトピック間の対応する関係を知りません。 ピアとサーバー間のデカップリングは、セキュリティ上の理由から考えられます。 ただし、これは再接続の実装にも困難をもたらします。
- サーバとクライアントの両方が socket.readyState===1 でメッセージの送信準備ができたかどうかを判断しています。しかし、我々のテストでは、接続が切断された後も5~7秒程度 socket.readyState が有効になります。この間のメッセージは失われる可能性があります。
全体として、ハンドシェイクプロセスは巧妙に設計されています。 ただし、再接続のメカニズムや、サーバー側のメッセージストレージ、およびトピックのリサイクルには、まだ改善の余地があります。
我々の仕事
- ViteXのユーザーは世界中にいるため、1台のサーバーでは一部のユーザーに大きな遅延が発生し、安定性が低下するため、複数の分散サーバーをセットアップする必要があります。
- 2 つのピア間の状態不可知性の問題を解決するために、ViteConnect ではハートビートメカニズムが導入されています。一方の当事者のハートビートが10秒以内に検出されなかった場合、もう一方の当事者は切断メッセージを送信して接続を終了します。
- 未使用のトピックをリサイクルするために、ViteConnectは各セッションに1つのトピックのみが存在することを保証します。 長時間(1時間)未使用のトピックはリサイクルされます。
- ベーシックなモニターが採用されています。
ViteConnectの最初のバージョンがリリースされた後、初日のトピック数のピークは3700前後で、同時に1200人以上のユーザーにサービスを提供しました。
V2での最適化
フィードバックによると、最初のバージョンではメッセージが消えたり、画面ロック時に接続が切れたりすることがありました。
これは安定性とリアルタイム性のトレードオフです。低速なネットワーク環境では、メッセージの到着を待つか、すぐに接続を切断するかの判断は必ずしも容易ではありません。 モバイルアプリでの接続維持の難しさとネットワーク遅延の影響の測定を考慮して、ViteConnectに再接続メカニズムを実装することにしました。
- 各メッセージに一意のシーケンス番号を追加して、ピアが再接続後に最後のインデックスから再サブスクライブできるようにします。
- 新しいメッセージタイプの導入:
- a. セッション関連のメッセージ。セキュリティ上の理由から、メッセージは使い捨てであるべきです。
- b. 接続の最適化の目的では、ピアとサーバ間のメッセージは暗号化されていてはなりません。
- c. 再接続後にトピックの再サブスクリプションが発生した場合に備えて、プライベートメッセージは一定期間サーバー上に保存しておく必要があります。
- d. 一定時間アイドリングするとトピックがリサイクルされます。
3. バージョン管理をサポートします。 メッセージ/ピアのバージョンはサーバーによって検出される必要があります。 異なるバージョンのピアやメッセージを処理する場合、サーバーは異なる処理方法を選択する必要があります。
参考情報:
https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Protocols
https://github.com/MyEtherWallet/MEWconnect
https://github.com/WalletConnect/walletconnect-monorepo
https://github.com/WalletConnect/node-walletconnect-bridge