본문 재작성
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 프로그램도 지원됩니다 — Surge 구문을 참고하세요.
본문 재작성 규칙은 [Body Rewrite] 섹션에 정의됩니다. 각 방향(요청/응답)별로 하나의 메시지에는 첫 번째로 일치하는 규칙만 적용됩니다. 같은 메시지에 본문을 받는 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 프로그램을 받습니다: <type> <URL pattern> <jq program>. 프로그램에는 공백이 들어가므로 보통 따옴표로 감쌉니다. 따옴표 밖에서는 공백 뒤에 오는 //나 #가 주석을 시작하며, 프로그램은 거기서 끝납니다. 따옴표 안에서 //는 jq의 대안 연산자이므로, 이를 쓰는 프로그램은 따옴표로 감싸세요. 본문은 JSON으로 처리됩니다. 본문이 JSON이 아니거나, 프로그램이 오류를 내거나, 출력이 없으면 모두 본문을 그대로 둡니다. 프로그램 자체가 잘못된 경우에는 보고되고 그 규칙 하나만 건너뜁니다(프로필 전체가 실패하지는 않습니다). 프로그램은 파일도 환경도 읽을 수 없습니다: 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 패턴당 하나의 규칙을 사용하세요:
[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 키와 토큰을 교체합니다. 각 방향별로 첫 번째로 일치하는 규칙만 적용되므로, 두 필드를 하나의 규칙으로 결합하세요:
[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에 대한 모든 참조를 새 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(두 번째 그룹) 등. - URL 패턴이나 본문 패턴이 유효한 정규식이 아니면 regex 줄이나 JSONPath 줄은 구성 오류가 되어 규칙이 로드되지 않습니다. jq 줄은 대신 경고와 함께 건너뜁니다. 첫 번째 쌍 뒤의 쌍에서는 유효하지 않은 패턴이 그 쌍만 버리며, 로그에 경고가 남습니다.
- JSONPath 모드는 본문이 유효한 JSON인 경우에만 적용됩니다.
- 본문 재작성 규칙은 디코딩된(UTF-8) 본문 텍스트에 적용됩니다.
- 각 방향(요청/응답)별로 하나의 메시지에는 첫 번째로 일치하는 규칙만 적용됩니다. 여러 수정이 필요하면 하나의 통합 규칙으로 정의하세요.
- 존재하지 않는 JSONPath를 삭제하면 본문은 변경되지 않습니다. 값을 설정할 때 부모 객체가 존재하면 키가 생성되며, 중간 경로가 없으면 아무 일도 일어나지 않습니다.
이 페이지는 영어판의 번역본입니다. 내용이 다를 경우 영어판이 우선합니다.