ボディ書き換え
Chuteは正規表現またはJSONPath式を使用して、HTTPリクエストおよびレスポンスボディのコンテンツを検索・置換できます。HTTPSトラフィックにはMitM復号が必要です。
注意: 平文HTTPのリクエストが処理されるのは、ChuteのHTTPプロキシを経由して届いた場合だけです。TUNインターフェースから届いた平文HTTPは手を加えずに転送されます。Chute Androidは、設定でシステムHTTPプロキシをオンにしない限り、すべてのトラフィックをTUNに通します。このオプションはChuteのHTTPプロキシをアプリに渡すものです(Android 10以降。デフォルトはオフ)。
Surgeのhttp-request-jqとhttp-response-jqのjqプログラムにも対応しています。Surge構文を参照してください。
ボディ書き換えルールは[Body Rewrite]セクションで定義されます。各方向(リクエスト / レスポンス)について、1つのメッセージには最初にマッチしたルールのみが適用されます。同じメッセージにボディを受け取るhttp-requestまたはhttp-responseスクリプトもマッチした場合は、ルールが先に適用され、スクリプトは書き換え後のボディを受け取ります。http-request-before-sendスクリプトはその両方の後に実行されます。
[Body Rewrite]
^https://api\.example\.com/response.* response regex "old-text" "new-text"
^https://api\.example\.com/request.* request regex "sensitive" "[redacted]"
^https://api\.example\.com/data.* jsonpath-response jsonpath $.ads null
ルール形式
各ルールは次の一般的な形式に従います:
<URL regex> [direction] <mode> <pattern> <replacement>
注意: URL正規表現は、URL書き換えと同じく、リクエストの完全なURLのどの位置でもマッチし、パスだけに対してもマッチします。
^https://example\.comだけでそのホストのすべてのパスとクエリ文字列が対象になるため、末尾に.*を付ける必要はありません。また、^/apiはパスが/apiで始まるすべてのリクエストにマッチします。復号されたリクエストの完全なURLはhttps://で始まるため、^http://のパターンがそれにマッチすることはありません。パターンの大文字・小文字は保持されるので、\S、\D、\W、\Bは書いたとおりの意味になります。マッチング自体は大文字・小文字を区別しません。
行頭またはスペースの直後に置かれた#や//は、ダブルクォートの中でない限り、行末まで続くコメントを開始します。;はコメントになりません。コメントを参照してください。
Surge構文
Surge独自の行形式も受け付けられます。方向を先頭に書き、regexキーワードは省略します。
[Body Rewrite]
http-response ^https://api\.example\.com/feed "\"ads\":\s*\[.*?\]" "\"ads\":[]"
http-request ^https://api\.example\.com/submit "sensitive" "[redacted]"
Surge形式の行には複数のパターン/置換の組を書けます。左から右へ順に、前の組の結果に対して適用されます。http-request-jqとhttp-response-jqは、パターンと置換の代わりにjqプログラムを取ります: <種別> <URL パターン> <jq プログラム>。プログラムには空白が含まれるため、通常は引用符で囲みます。引用符の外では、空白に続く//または#がコメントを開始し、プログラムはそこで終わります。引用符の中では//はjqの代替演算子なので、これを使うプログラムは引用符で囲んでください。ボディはJSONとして処理されます。ボディがJSONでない場合、プログラムがエラーを投げた場合、出力が何もない場合は、いずれもボディをそのまま残します。プログラム自体が不正な場合は報告され、その1行だけがスキップされます(設定全体は失敗しません)。プログラムはファイルも環境も読めません: importとincludeは何も解決せず、$ENVとenvは空です。
注意: Chute Androidはjqプログラムをjackson-jqで実行します。出力は4096個の結果または4 MBまでに制限され、それより多くを出力するプログラムはボディをそのまま残します。また、jq 1.7の組み込み関数の一部がありません。欠けているものには、
now、todateiso8601、fromdateiso8601以外の日付関数(strftime、strptime、mktime、gmtime、todateなど)、@base32と@base32d、abs、toarray、trim・ltrim・rtrim、IN・INDEX・JOIN、tostreamとfromstreamがあります。これらを呼び出すプログラムは実行時にエラーを投げるため、ボディはそのまま残ります。
方向
| キーワード | 説明 |
|---|---|
response |
レスポンスボディに適用(省略時のデフォルト) |
request |
リクエストボディに適用 |
モード
| モード | 説明 |
|---|---|
regex |
正規表現による検索と置換 |
jsonpath-response / jsonpath-request / body-jsonpath-response / body-jsonpath-request |
JSONPathベースの変更 |
正規表現モード
デコードされたボディテキストに対して標準的な正規表現の検索と置換を実行します。NSRegularExpression(ICU)を使用し、大文字小文字を区別しないマッチングを行います。置換はキャプチャグループ参照($1、$2など)をサポートします。
<URL regex> [response|request] regex <pattern> <replacement>
例 — JSONレスポンスから広告を削除:
[Body Rewrite]
^https://api\.example\.com/feed.* response regex "\"ads\":\s*\[.*?\]" "\"ads\":[]"
例 — リクエストボディをサニタイズ:
[Body Rewrite]
^https://api\.example\.com/submit.* request regex "\"password\":\s*\".*?\"" "\"password\":\"[FILTERED]\""
例 — キャプチャグループを使用してデータを再フォーマット:
[Body Rewrite]
// "last, first" を "first last" に入れ替え
^https://api\.example\.com/users.* response regex "\"name\":\s*\"(\w+),\s*(\w+)\"" "\"name\":\"$2 $1\""
例 — レスポンスボディ内の埋め込みURLを書き換え:
[Body Rewrite]
^https://api\.example\.com.* response regex "https://old-cdn\.example\.com" "https://new-cdn.example.com"
スペースを含むトークンはダブルクォートで囲む必要があります:
[Body Rewrite]
^https://example\.com.* response regex "old value with spaces" "new value"
トークン内にリテラルのダブルクォートを含めるには、バックスラッシュでエスケープします: \"。
JSONPathモード
JSONPath式を使用してJSONボディを変更します。特定のパスでの値の読み取り、設定、削除をサポートします。
<URL regex> jsonpath-response|jsonpath-request jsonpath <jsonpath-expression> [value]
サポートされるJSONPath構文
| 式 | 説明 |
|---|---|
$.key |
オブジェクトプロパティにアクセス |
$.key.subkey |
ネストされたプロパティにアクセス |
$[0] |
インデックスで配列要素にアクセス |
$.key[0].subkey |
オブジェクトと配列の混合アクセス |
$.items[*].name |
ワイルドカード: 配列内の全アイテム |
$.*.value |
ワイルドカード: 全プロパティ |
.*はオブジェクトのすべてのメンバーと配列のすべての要素を取り出すため、$.items.*.nameは各アイテムの名前を指します。配列に対する最後のステップとして使うと何も変わりません。要素そのものを置き換えるには[*]を使ってください。
値の型
| 値 | 結果 |
|---|---|
string |
文字列値に設定 — 以下のどの形式にも当たらない値はすべて文字列なので、example.com、1.0.0-beta、12abcは文字列のまま残ります |
42 |
整数に設定 — トークン全体がJSONの数値で、小数部も指数もないもの |
3.14 |
浮動小数点数に設定 — 小数部か指数を持つJSONの数値(1e3など)と、64ビットに収まらない整数 |
true |
ブール値trueに設定 |
false |
ブール値falseに設定 |
[…] または {…} |
クォートしなければJSONとして解析され、その配列やオブジェクトとして設定されます。最後のフィールドなので、行の残りは書かれたまま読み取られ、空白を含んでいても構いません。クォートした場合や、正しいJSONでない場合は文字列のままです。 |
null、nil または省略 |
パスを削除 |
注意: 値をクォートしても文字列型にはなりません — クォートはトークン化の際に取り除かれ、型は残った内容から推論されます。そのため
"42"は数値の42に、"true"はブール値のtrueになり、"null"はパスを削除します。クォートが意味を持つのは[…]と{…}だけで、クォートするとこれらは文字列のままです。キーワードは大文字・小文字も含めて完全に一致する必要があるので、TrueやNULLは文字列です。数値として扱われるのは、トークン全体がJSONの書き方どおりの数値である場合だけです:+1、.5、1.、007は文字列のまま残り、浮動小数点数でも表せないほど大きな数(1e400など)も同様です。"42"や"true"のような文字列を設定する書き方はありません — 代わりにregexルールを使ってください。
例 — JSONフィールドを設定:
[Body Rewrite]
^https://api\.example\.com/profile.* jsonpath-response jsonpath $.user.name "Anonymous"
例 — JSONフィールドを削除:
[Body Rewrite]
^https://api\.example\.com/data.* jsonpath-response jsonpath $.tracking null
例 — ワイルドカード変更:
[Body Rewrite]
^https://api\.example\.com/list.* jsonpath-response jsonpath $.items[*].hidden true
実践例
JSONレスポンスからトラッキングパラメータを除去
全てのAPIレスポンスからtrackingIdフィールドを削除します。方向ごとに最初にマッチしたルールのみが適用されるため、URLパターンごとに1つのルールを使用してください:
[Body Rewrite]
^https://api\.example\.com/.* jsonpath-response jsonpath $.trackingId null
HTMLレスポンスにスクリプトタグを注入
全てのHTMLページの</body>の前にカスタム<script>タグを追加:
[Body Rewrite]
^https://www\.example\.com/.* response regex "</body>" "<script>console.log('injected')</script></body>"
リクエストログの機密フィールドを墨消し
サーバーに到達する前に、送信リクエストボディ内のAPIキーとトークンを置換します。方向ごとに最初にマッチしたルールのみが適用されるため、両方のフィールドを1つのルールにまとめてください:
[Body Rewrite]
^https://api\.example\.com/.* request regex "\"(apiKey|token)\":\s*\"[^\"]+\"" "\"$1\":\"[REDACTED]\""
レスポンスの日付形式を正規化
ISO日付を短い形式に置換:
[Body Rewrite]
^https://api\.example\.com/.* response regex "(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z" "$1/$2/$3 $4:$5"
アプリ設定の機能フラグを無効化
設定エンドポイントの全ての機能フラグをfalseに強制:
[Body Rewrite]
^https://api\.example\.com/config.* jsonpath-response jsonpath $.features[*].enabled false
キャッシュされたレスポンスのCDN URLを書き換え
古いCDNへの全ての参照を新しいものに置換:
[Body Rewrite]
^https://www\.example\.com/.* response regex "https://old-cdn\.example\.com" "https://new-cdn.example.com"
処理パイプライン
ボディ書き換えは以下を自動的に処理します:
- Content-Encoding:
gzipとdeflateをサポート。サポートされていないエンコーディングはスキップされます。 - Transfer-Encoding: 処理前にチャンク転送エンコーディングをデチャンクします。
- デコード: 書き換えルールを適用する前にボディを展開します。
- 再エンコード: ボディを再圧縮し、
Content-Lengthを更新します。Transfer-Encodingヘッダーを削除します。 - Accept-Encoding: レスポンスルールがリクエストのURLにマッチした場合、レスポンスがデコード可能なエンコーディングに保たれるよう、リクエストの
Accept-Encodingヘッダーはgzip, deflate, identityに書き換えられます。
書き換え処理の最大ボディサイズは、HTTP/1.x(平文HTTPと復号されたHTTP/1.1)では128KBです。これより大きいボディは変更されずに通過します。復号されたHTTP/2のメッセージは全体がバッファされ、サイズにかかわらず書き換えられます。
HTTP/1.xでは、レスポンスボディは全体が届いてから書き換えられます。その前にサーバーが接続を閉じた場合、
Content-Lengthもチャンク転送エンコーディングも持たないボディは接続の終わりがボディの終わりなので完全であり、通常どおり書き換えられます。Content-Lengthまたはチャンク転送エンコーディングで区切られていて、切断によって途中で切れたボディは、受け取ったとおりのままクライアントへ送られ、書き換えられずContent-Lengthもそのままです。その後接続が閉じられるので、クライアントはレスポンスが不完全だとわかります。
注意事項
- HTTPSトラフィックの場合、マッチするホスト名に対してMitM復号が有効になっている必要があります。
- 正規表現マッチングは大文字小文字を区別しません。置換テンプレートはICUキャプチャグループ参照をサポートします:
$0(完全一致)、$1(最初のグループ)、$2(2番目のグループ)など。 - URLパターンやボディのパターンが有効な正規表現でない場合、regexやJSONPathの行は設定エラーになり、そのルールは読み込まれません。jqの行は代わりに警告を出してスキップされます。2番目以降のパターン/置換の組では、無効なパターンはその組だけを取り除き、ログに警告が出ます。
- JSONPathモードはボディが有効なJSONである場合にのみ適用されます。
- ボディ書き換えルールはデコードされた(UTF-8)ボディテキストに適用されます。
- 1つのメッセージには、方向(リクエスト / レスポンス)ごとに最初にマッチしたルールのみが適用されます。複数の編集が必要な場合は、1つにまとめたルールを定義してください。
- 存在しないJSONPathを削除してもボディは変更されません。値の設定は、親オブジェクトが存在する場合にキーを作成します。中間パスが欠けている場合は何も起こりません。
本ページは英語版からの翻訳です。内容に相違がある場合は、英語版が優先されます。