
OpenClaw を初めてセットアップしたとき、ちょっとした違和感を覚えました。通常のWebサービスなら当たり前にある「パスワード登録」や「アカウント作成」がないんです。
「認証どうなってるんだ?」と気になってドキュメントを読み始めたら、Dashboard UIとGatewayのペアリング機構が思いのほか面白い設計になっていました。Challenge-Response認証、デバイストークンのローテーション、5分間のタイムアウトなど、細かい設計判断が積み重なっていて、「ローカル優先だけどセキュアに」という思想が一貫しています。
本記事では、OpenClawのGateway Protocolを読み解きながら、これらの設計がどう組み合わさって「信頼」を構築しているかを解説します。
OpenClawのアーキテクチャ: Gatewayとは
まず前提として、OpenClawのアーキテクチャを簡単に整理します。
OpenClaw は、WhatsApp、Telegram、Slack、Discord、WebChatなど複数のメッセージングプラットフォームと接続できるAIアシスタントです。その中心にあるのがGatewayです。
Gatewayの役割
- 単一のコントロールプレーン: すべてのクライアント(CLI、WebUI、macOSアプリ、iOS/Androidノード)が接続する中央サーバー
- メッセージングプラットフォームの管理: WhatsApp(Baileys経由)、Telegram(grammY経由)などのセッションを保持
- デバイス認証の管理: どのデバイスが接続を許可されるかを決定
デフォルトでは 127.0.0.1:18789 でサーバーが起動します。
Gateway Protocol
OpenClawのGateway Protocolは、JSON-RPCライクな通信を行います。すべての接続は、最初に connect リクエストを送る必要があります。これがハンドシェイク(認証フロー)の起点です。
ペアリングフローの全体像
OpenClawのペアリングは「Gateway-Owned Pairing」と呼ばれる方式で、Gatewayが信頼の源です。
基本フロー
sequenceDiagram
participant Client as クライアント
participant Gateway as Gateway
Gateway->>Client: connect.challenge (nonce)
Client->>Gateway: connect (署名付き)
Gateway->>Gateway: 署名検証
alt 新規デバイス
Gateway->>Gateway: ペアリングリクエスト保存
Gateway->>Client: hello-ok (トークンなし)
Note over Gateway: 承認待ち(5分間有効)
Gateway->>Client: node.pair.requested イベント
Note over Gateway: ユーザーが承認
Gateway->>Client: デバイストークン発行
else 既知デバイス
Gateway->>Client: hello-ok (デバイストークン)
end
3つの重要な要素
- Challenge-Response認証: nonceを使った署名検証
- デバイストークン: 承認後に発行される認証トークン
- 5分タイムアウト: 未承認リクエストの自動失効
それぞれの設計意図を掘り下げます。
Challenge-Response: なぜnonceが必要か
リプレイ攻撃の防止
接続確立時の connect リクエストが盗聴・再利用されるリスクがあります。Challenge-Response認証は、このリプレイ攻撃を防ぐための仕組みです。
フロー詳細
1. Gatewayがnonceを発行
クライアントが接続を開始すると、Gatewayは最初に connect.challenge イベントを送信します。
| |
2. クライアントがnonceに署名
クライアントは、自分の秘密鍵でnonceに署名し、connect リクエストに含めます。
| |
3. Gatewayが署名を検証
Gatewayは、クライアントの公開鍵を使って署名を検証します。これにより、以下を確認できます。
- クライアントが秘密鍵を保持している(なりすましではない)
- nonceが改ざんされていない
- リクエストが最新のもの(古いnonceの再利用ではない)
設計意図
- リプレイ攻撃の防止: 過去の
connectリクエストを再利用できない - なりすまし防止: 秘密鍵を持たないクライアントは署名を作成できない
- タイムスタンプ検証:
signedAtとtsの差分で、古すぎるリクエストを拒否できる
この仕組みは、SSH公開鍵認証と同じ原理です。
デバイストークン: ローテーションの設計
トークンのライフサイクル
OpenClawのデバイストークンは、以下のライフサイクルを持ちます。
stateDiagram-v2
[*] --> PendingRequest: connect (新規デバイス)
PendingRequest --> Approved: 承認
PendingRequest --> Rejected: 拒否
PendingRequest --> Expired: 5分経過
Approved --> TokenIssued: デバイストークン発行
TokenIssued --> Reconnect: 次回接続
Reconnect --> TokenRotated: 再ペアリング時
Rejected --> [*]
Expired --> [*]
トークンローテーションの仕組み
初回承認時:
| |
再ペアリング時:
- 既存のトークンは無効化される
- 新しいトークンが発行される
設計意図
なぜトークンをローテーションするのか?
- 漏洩時の影響を限定: トークンが漏洩しても、再ペアリングで無効化できる
- 権限の再確認: 再ペアリング時に、ユーザーが明示的に承認する
- 長期トークンのリスク回避: 永続的なトークンは避け、定期的な更新を促す
この設計は、OAuth 2.0のRefresh Tokenローテーションと似た考え方です。
トークンの保存場所
トークンは、Gatewayのステートディレクトリに保存されます。
~/.openclaw/
├── nodes/
│ ├── paired.json # 承認済みデバイスとトークン
│ └── pending.json # 承認待ちリクエスト
セキュリティ上の注意:
paired.jsonは秘密情報として扱う- ファイルパーミッションを適切に設定する(
chmod 600) - Gitリポジトリには含めない
5分タイムアウト: なぜこの値か
ペアリングリクエストの有効期限
OpenClawでは、未承認のペアリングリクエストは5分後に自動的に失効します。
| |
設計意図
なぜ5分なのか?
- DoS攻撃の防止: 大量のペアリングリクエストでメモリを消費させる攻撃を防ぐ
- ユーザー体験: 5分あれば、ユーザーがCLIやUIで承認操作を完了できる
- セキュリティ: 長すぎる有効期限は、攻撃者に時間的猶予を与える
他のシステムとの比較:
| システム | タイムアウト | 用途 |
|---|---|---|
| OpenClaw | 5分 | デバイスペアリング |
| Bluetooth | 2分 | デバイスペアリング |
| OAuth 2.0 | 10分 | 認可コード |
| SSH | なし | 公開鍵登録(手動) |
5分という値は、Bluetoothのペアリングタイムアウト(約2分)よりは長く、OAuth 2.0の認可コード(10分)よりは短い、バランスの取れた設定です。
CLIでの承認フロー
ペアリングリクエストは、CLIで確認・承認できます。
| |
ヘッドレスサーバーでも、SSH経由でこのコマンドを実行すれば承認できます。
ローカル自動承認: UXとセキュリティのトレードオフ
ローカル接続の特別扱い
OpenClawには、ローカル接続の自動承認という機能があります。
ローカル接続の定義:
- ループバック接続(
127.0.0.1) - Gatewayホストの自身のTailnetアドレス
これらの接続は、ペアリング承認をスキップして自動的に許可されます。
設計意図
なぜローカルだけ自動承認するのか?
- UXの改善: 同一ホストのCLI/UIは、毎回承認を求めると煩雑
- セキュリティの妥当性: ローカルホストにアクセスできる時点で、すでに信頼されている
- Tailnetの信頼: Tailscaleのネットワーク内は、すでに認証済み
トレードオフ:
- ✅ 利便性: 開発時の体験が向上
- ❌ リスク: ローカルホストが侵害された場合、自動承認される
macOSアプリのサイレント承認
macOSアプリには、さらに高度な自動承認機能があります。
条件:
- ペアリングリクエストが
silent: trueフラグを持つ - アプリがSSH接続でGatewayホストを検証できる
この場合、ユーザーに確認なしで承認されます。失敗した場合は、通常の「承認/拒否」プロンプトにフォールバックします。
リモートアクセス時の考慮事項
SSH/Tailscaleの推奨
OpenClawは、リモートアクセス時に以下を推奨しています。
推奨方法:
- Tailscale: VPN不要で、Tailnetアドレスで接続
- SSH Tunnel: ローカルポートフォワーディング
| |
非推奨:
- 公開インターネットへの直接露出
- 認証なしのHTTP接続
TLS + ピンニング
リモートアクセス時は、TLS + 証明書ピンニングを有効にできます。
| |
クライアント側で証明書のフィンガープリントを検証:
| |
これにより、中間者攻撃(MITM)を防げます。
トラブルシューティング: よくあるエラー
“pairing required (1008)” エラー
原因:
- デバイスIDが未承認
- トークンが無効化された
- HTTPSなしでリモート接続している
対処法:
| |
Docker環境での接続エラー
Docker内でGatewayを実行している場合、ホストからの接続が「リモート」と判定されることがあります。
対処法:
| |
クライアント側でトークンを設定:
| |
まとめ: 設計から学べること
OpenClawのペアリングプロトコルは、以下の設計判断が組み合わさっています。
| 要素 | 設計意図 | トレードオフ |
|---|---|---|
| Challenge-Response | リプレイ攻撃防止 | 実装の複雑さ |
| トークンローテーション | 漏洩時の影響を限定 | 再ペアリングの手間 |
| 5分タイムアウト | DoS攻撃防止 | ユーザー体験 |
| ローカル自動承認 | UXの改善 | ローカル侵害時のリスク |
これらは、「ローカル優先だけどセキュアに」という一貫した思想を反映しています。
個人的には、この設計が面白いのは、完璧なセキュリティを目指していない点だと思います。ローカル自動承認のように、「実用上の妥当性」を優先している箇所があります。
OpenClawは「パーソナルアシスタント」という前提で設計されているため、エンタープライズ向けのZero Trust原則とは異なる判断をしています。この「用途に応じた設計」が、実際に使いやすいツールを生む鍵なのかもしれません。
興味のある方は、公式ドキュメント でプロトコル仕様を確認してみてください。