ApiCatcher リアルタイム同期の使い方

スマートフォンでキャプチャした HTTP/HTTPS 通信を、パソコンやほかのシステムへリアルタイムに送信します。

プロトコル仕様:Real-time Sync Protocol


1. できること

ApiCatcher は、iOS/Android 上で VPN 機能を使ってキャプチャした通信を、WebSocket で同一 LAN 内のレシーバーへリアルタイムにストリーミングします。キャプチャの開始と同時に送信されるため、セッションの終了を待ってファイルをエクスポートする必要はありません。

レシーバー用途接続方法
ApiCatcher Desktopパソコン上で通信を確認、分析、リプレイDesktop の QR コードをスキャン
Burp Suite 拡張Burp でセキュリティテスト拡張画面の QR コードをスキャン
カスタムレシーバー独自サービスや社内システムと連携ws:// の URL を入力して接続テスト

同時に有効にできるレシーバーは 1 種類だけです。いずれかを有効にすると、ほかの 2 種類は無効になります。


2. 使いどころ

パソコンで通信を確認する。 大きな JSON、長いヘッダー、バイナリ形式のボディは、スマートフォンでは確認しにくいことがあります。Desktop に接続すれば、パソコン上で解析、比較、リプレイができます。

Burp Suite に送信する。 ApiCatcher for Burp Suite Extension をインストールすると、スマートフォンでキャプチャしたリクエストが Site map または Proxy History に追加され、Repeater や Intruder に送信できるようになります。スマートフォン側の VPN 機能でキャプチャするため、パソコンでシステムプロキシを設定する必要はありません。

API セキュリティ検査や DLP に連携する。 アプリのテスト時にキャプチャとリアルタイム同期を有効にすると、通信を独自の検査基盤へ送信できます。身分証明書番号、電話番号、トークン、秘密鍵などの機微情報を検出し、情報漏えいにつながる可能性のある API を開発担当者やテスト担当者に報告できます。

実際の通信から API ドキュメントを更新する。 レシーバーで過去のフィールドと比較し、リクエストやレスポンスに追加された可能性のあるフィールドを検出します。必要に応じて大規模言語モデル(LLM)で用途や説明文の下書きを生成し、ドキュメント担当者にメールで通知できます。

自動化やモックに利用する。 リクエスト全体をテスト用フィクスチャとして保存したり、モックの生成に利用したりできます。


3. 始める前に

  1. HTTPS 通信を復号する場合は、ApiCatcher のルート証明書をインストールし、完全に信頼するよう設定してください。
  2. スマートフォンとレシーバーを同じ Wi-Fi に接続してください。データを安全に取り扱うため、現在は LAN 内の ws:// 接続にのみ対応しています。wss:// には対応しておらず、通信が LAN の外へ送信されることもありません。
  3. パソコンまたはサーバーのファイアウォールで、レシーバーの待受ポート(例:8080)を許可してください。
  4. レシーバーを起動してから、アプリで接続テストを実行してください。

4. リアルタイム同期を開く

  1. ApiCatcher を開き、キャプチャのホーム画面へ移動します。
  2. 右上の「+」をタップします。
  3. 「Real-time Sync」を選択します。
  4. 画面上部には Desktop、Burp Suite、Custom Receiver の 3 つのタブがあります。

有効にすると、ホーム画面に「Real-time Sync Active」と、レシーバーの状態を示す「Online」または「Offline」が表示されます。この表示をタップすると、設定画面に戻れます。


5. ApiCatcher Desktop につなぐ

  1. apicatcher.net から ApiCatcher Desktop をダウンロードし、起動します。
  2. Desktop でリアルタイム同期レシーバーを起動すると、QR コードが表示されます。
  3. スマートフォンで「Real-time Sync → Desktop」を開きます。
  4. 「Scan QR Code」をタップし、Desktop に表示された QR コードをスキャンします。
  5. スキャンに成功すると、レシーバーのアドレスと「Online」または「Offline」が表示されます。
  6. 「Enable」をオンにします。
  7. ホーム画面に戻り、VPN キャプチャを開始して対象アプリを操作します。Desktop にリクエストが順次表示されます。

「Offline」と表示される場合は、Desktop が起動していることと、スマートフォンとパソコンが同じサブネットに接続されていることを確認してから、「Rescan」で QR コードを再度スキャンしてください。

ApiCatcher Desktop リアルタイム同期受信


6. Burp Suite につなぐ

拡張の説明:ApiCatcher for Burp Suite Extension

  1. 拡張機能の .jar をダウンロード(または自身でビルド)し、Burp の Extensions → Installed → Add から Java 拡張として読み込みます。
  2. 画面上部の ApiCatcher タブを開き、WebSocket サーバーが起動していることを確認します。停止している場合は Start Server をクリックします。
  3. スマートフォンで「Real-time Sync → Burp Suite」を開き、拡張画面の QR コードをスキャンします。
  4. 「Enable」をオンにしてから、キャプチャを開始します。
  5. デフォルトの同期先は Target → Site map です。リクエストとレスポンスの全体を確認する場合は、同期先を Proxy → HTTP history に変更してください。HTTP history に追加されたリクエストには X-ApiCatcher-RequestId が付与されます。
  6. 追加されたリクエストは Repeater や Intruder に送信できます。

同期に問題がある場合は、Extensions → Installed でこの拡張機能を選択し、画面下部の Output/Errors を確認してください。

ApiCatcher for Burp Suite 拡張の設定


7. カスタムレシーバーに接続する

  1. パソコンまたは社内ネットワークで、あらかじめレシーバーを起動します(第 8 節を参照)。アドレスは ws://192.168.1.75:8080 のような形式です。
  2. スマートフォンで「Real-time Sync → Custom Receiver」を開きます。
  3. 「Remote URL」に ws://IP:ポート を入力します。右側の「Documentation」からプロトコル仕様を確認できます。
  4. 「Test Connection」をタップします。接続に成功すると、アドレスが保存されます。
  5. 「Enable Real-time Streaming」をオンにします。アドレスが空の場合や接続テストに失敗した場合は、スイッチをオンにできません。
  6. アドレスを変更すると、スイッチはオフになります。もう一度「Test Connection」を実行してからオンにしてください。
  7. キャプチャを開始すると、レシーバーに JSON フレームが届き始めます。

http:// または wss:// は指定しないでください。127.0.0.1 はスマートフォン自身を指すため、レシーバーのアドレスとして使用できません。


8. カスタムレシーバーでプロトコルを実装する

仕様:README.md
リポジトリ:apicatcher-realtime-sync-protocol
Java SDK:apicatcher-sync-sdk-java

8.1 接続

役割対象
WebSocket ClientApiCatcher アプリ
WebSocket Server実装するカスタムレシーバー
  • LAN 内の ws:// を使用します(データを安全に取り扱うため wss:// には対応しておらず、通信は LAN 内に留まります)
  • 接続が切れると、アプリが自動的に再接続します
  • 切断中にキャプチャしたデータと送信途中のチャンクは破棄され、再送されません
  • 1 本の接続では複数のリクエストが混在するため、必ず requestId ごとに分けて処理します

8.2 メッセージ形式

各メッセージは、JSON テキストを格納した WebSocket テキストフレームとして送信されます。

{
  "type": "http",
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "event": "req_start",
  "timestamp": 1711268370123,
  "payload": {}
}
フィールド意味
type現在は http
requestId1 件のリクエストを識別する UUID。チャンクはこの値でまとめる
event後述のイベントを参照
timestampミリ秒単位のタイムスタンプ
payloadイベントに対応するデータ

8.3 イベント

典型的な流れは次のとおりです。

req_start → req_body* → res_start → res_body* → req_end

req_bodyres_body は送信されない場合もあれば、複数のチャンクに分かれて送信される場合もあります。ボディがない場合、対応するイベントは送信されません。

req_start — リクエストの送信開始:

{
  "type": "http",
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "event": "req_start",
  "timestamp": 1711268370123,
  "payload": {
    "url": "https://api.example.com/data",
    "method": "POST",
    "httpVersion": "HTTP/1.1",
    "headers": [{"name": "User-Agent", "value": "ApiCatcher/1.0"}]
  }
}

受信したら requestId ごとにキャッシュを作成し、URL、メソッド、リクエストヘッダーを保存します。

req_bodyres_body — ボディのチャンク:

{
  "type": "http",
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "event": "res_body",
  "timestamp": 1711268370123,
  "payload": {
    "data": "eyBzdWNjZXNz..."
  }
}

payload.data には、バイナリデータを Base64 エンコードした文字列が入ります。送信順序は維持されます。WebSocket は TCP 上で動作するため、受信順序は送信順序と同じです。受信した順にデコードして連結してください。大きなボディは約 16~32 KB 単位の複数チャンクに分割されるため、ボディ全体の受信完了を待たずに処理してください。

res_start — レスポンスヘッダーの受信:

{
  "type": "http",
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "event": "res_start",
  "timestamp": 1711268370123,
  "payload": {
    "status": 200,
    "httpVersion": "HTTP/1.1",
    "headers": [{"name": "Content-Type", "value": "application/json"}]
  }
}

req_end — リクエストの終了:

{
  "type": "http",
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "event": "req_end",
  "timestamp": 1711268370123,
  "payload": {
    "error": null,
    "timings": {
      "send": 0,
      "wait": 150,
      "receive": 5
    }
  }
}
  • errornull の場合は正常終了です。それ以外の場合は、"Timeout""Connection Aborted" などのエラー内容が入ります
  • timings の単位はミリ秒で、送信、応答待ち、受信にかかった時間を表します
  • req_end を受信したら完全な 1 件のリクエストに組み立て、該当するキャッシュを削除します
  • WebSocket 接続が切れた場合、まだ req_end を受信していない記録はすべて破棄します

8.4 組み立て

接続確立
  └─ map: requestId → 組み立て中のリクエスト

JSON フレーム受信
  ├─ req_start  → 新規作成し、url / method / headers を保存
  ├─ req_body   → Base64 デコードしてリクエストボディに追加
  ├─ res_start  → status / レスポンスヘッダーを保存
  ├─ res_body   → Base64 デコードしてレスポンスボディに追加
  └─ req_end    → error / timings を保存し、後続処理へ渡して map から削除

切断
  └─ map を空にし、未完成のデータを完全なリクエストとして扱わない

検査、保存、ドキュメントの更新は、req_end を受信してから実行してください。チャンクの受信途中では、ボディ全体が揃っていません。

8.5 Java SDK を使う

apicatcher-sync-sdk-java は、WebSocket サーバーとチャンクの組み立てを処理します。1 件のリクエストが完成すると、1 件分の HAR 1.2 エントリーを JSON 文字列としてコールバックに渡します(HAR ファイル全体ではありません)。

環境:JDK 11 以上、Maven 3.x 以上。

リスナーを実装します。

import com.apicatcher.sync.TrafficListener;

public class StandardConsoleListener implements TrafficListener {
    @Override
    public void onTrafficReceived(String harJson) {
        System.out.println("Received a complete request:");
        System.out.println(harJson);
    }
}

レシーバーを起動します。

import com.apicatcher.sync.ApiCatcherReceiver;

public class App {
    public static void main(String[] args) {
        int port = 8080;
        ApiCatcherReceiver receiver =
            new ApiCatcherReceiver(port, new StandardConsoleListener());
        receiver.start();
        System.out.println("Listening on port " + port);
    }
}

スマートフォン側の接続先には ws://<このパソコンの LAN IP>:8080 を指定します。ファイアウォールでこのポートへの接続を許可してください。

onTrafficReceived では、機微情報の検査、ドキュメントとの差分確認、分析サービスへの転送、メッセージキューへの書き込みなどを実行できます。

8.6 独自に解析する場合

  • テキストフレームだけを処理し、requestId ごとにまとめます
  • ボディは受信順に連結し、timestamp では並べ替えないでください
  • 並行する複数のリクエストは混在して届くため、requestId ごとに分けてください
  • 接続が切れたら未完了の記録を破棄してください。このプロトコルでは再送されません
  • 現在の仕様は 1.0.0-Draft です。未知の event は、受信処理を終了せずにそのイベントだけを無視してください

9. 主なユースケース

キャプチャした通信をセキュリティ検査に利用する

  1. 社内ネットワークのレシーバーを先に起動します
  2. スマートフォンで QR コードをスキャンするか ws:// の URL を入力し、接続テスト後に有効にします
  3. キャプチャを開始し、テストケースに沿ってアプリを操作します
  4. 検査基盤で、組み立て済みのリクエストから機微情報を検出します
  5. URL、フィールド名、リクエストヘッダー/Query/ボディのどこで検出されたかを明記し、メールや IM で報告します

通信を基に API ドキュメントを更新する

  1. レシーバーで、API ごとの直近数回分のリクエストとレスポンスを保存します
  2. パスとメソッドの組み合わせごとにフィールドを比較します
  3. 追加されたフィールドや型が変更されたフィールドについて、大規模言語モデル(LLM)で説明文を生成します
  4. 更新内容の一覧を作成し、API の担当者にメールで送信します

Burp Suite でセキュリティテストを行う

  1. 拡張機能をインストールし、Start Server をクリックします
  2. アプリで QR コードをスキャンし、Burp Suite との同期を有効にします
  3. キャプチャ後、Site map で API を確認し、HTTP history からリクエストを選んでさらにテストします

10. よくある質問

接続テストが失敗する
レシーバーが起動していること、IP がパソコンの LAN アドレスであること、ファイアウォールでポートが許可されていること、スマートフォンとレシーバーが同じサブネットに接続されていることを確認してください。127.0.0.1http:// は使用できません。

スイッチが入らない
「Remote URL」を入力してください。Custom Receiver を使用する場合は、先に「Test Connection」を実行して接続に成功する必要があります。

ホームはオフラインなのに、受信側は動いている
パソコンのスリープ、Wi-Fi の切り替え、レシーバープロセスの終了などにより、「Offline」と表示されることがあります。設定画面で状態を確認してください。Desktop または Burp Suite を使用している場合は、「Rescan」で QR コードを再度スキャンできます。

一部のリクエストがパソコンに出ない
切断中にキャプチャした通信は再送されません。同期が有効になっていることを確認してからキャプチャを開始してください。フィルタリングルールやドメインのブラックリストにより、一部の通信が MITM 処理の対象外になっている可能性もあります。

3 種類のレシーバーを同時に使えますか
いいえ。優先順位は Desktop → Burp Suite → Custom Receiver で、同時に接続できるレシーバーは 1 種類だけです。

なぜ HAR を 1 ファイルで送らないのですか
大きなボディを VPN プロセス内で 1 つの JSON にまとめると、メモリ不足になる可能性があります。そのため、このプロトコルではデータをチャンクに分けて送信します。Java SDK は、レシーバー側でチャンクを HAR エントリーに組み立てます。

ホームの状態が回り続ける
WebSocket の接続状態を確認しています。表示が変わらない場合は、ネットワークとレシーバープロセスを確認してください。


11. 関連リンク