Body Rewrite
Chute สามารถค้นหาและแทนที่ข้อความในบอดีของคำขอและการตอบกลับ HTTP โดยใช้นิพจน์ปกติหรือ JSONPath expressions สิ่งนี้ต้องการการถอดรหัส MitM สำหรับทราฟฟิก HTTPS
หมายเหตุ: คำขอ HTTP ธรรมดาจะถูกประมวลผลก็ต่อเมื่อเข้ามาถึง Chute ผ่านพร็อกซี HTTP ของ Chute เท่านั้น ส่วน HTTP ธรรมดาที่เข้ามาทางอินเทอร์เฟซ TUN จะถูกส่งต่อไปโดยไม่มีการแก้ไขใด ๆ Chute Android ส่งทราฟฟิกทั้งหมดผ่าน TUN เว้นแต่จะเปิด พร็อกซี HTTP ของระบบ ในการตั้งค่า ซึ่งจะมอบพร็อกซี HTTP ของ Chute ให้แอปต่าง ๆ ใช้ (Android 10 ขึ้นไป และปิดอยู่โดยค่าเริ่มต้น)
โปรแกรม jq ของ Surge คือ http-request-jq และ http-response-jq ก็รองรับเช่นกัน — ดูไวยากรณ์ของ Surge
กฎ Body Rewrite ถูกกำหนดในส่วน [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 Rewrite:
^https://example\.comครอบคลุมทุกพาธและ query string ของโฮสต์นั้นอยู่แล้ว จึงไม่ต้องลงท้ายด้วย.*และ^/apiจะจับคู่ทุกคำขอที่พาธขึ้นต้นด้วย/apiURL แบบเต็มของคำขอที่ถูกถอดรหัสจะขึ้นต้นด้วย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> โดยปกติต้องใส่เครื่องหมายคำพูดครอบโปรแกรมเพราะมีช่องว่าง นอกเครื่องหมายคำพูด // หรือ # ที่ตามหลังช่องว่างจะเปิดหมายเหตุ ซึ่งทำให้โปรแกรมจบลงตรงนั้น ส่วนภายในเครื่องหมายคำพูด // คือตัวดำเนินการทางเลือก (alternative operator) ของ 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 |
โหมด Regex
ดำเนินการค้นหาและแทนที่ด้วย regex มาตรฐานบนข้อความเนื้อหาที่ถอดรหัส ใช้ 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
แก้ไขเนื้อหา JSON โดยใช้ JSONPath expressions รองรับการอ่าน ตั้งค่า และลบค่าที่เส้นทางเฉพาะ
<URL regex> jsonpath-response|jsonpath-request jsonpath <jsonpath-expression> [value]
ไวยากรณ์ JSONPath ที่รองรับ
| นิพจน์ | คำอธิบาย |
|---|---|
$.key |
เข้าถึงคุณสมบัติของอ็อบเจกต์ |
$.key.subkey |
เข้าถึงคุณสมบัติซ้อน |
$[0] |
เข้าถึงองค์ประกอบอาร์เรย์ตามดัชนี |
$.key[0].subkey |
การเข้าถึงแบบผสมระหว่างอ็อบเจกต์และอาร์เรย์ |
$.items[*].name |
Wildcard: รายการทั้งหมดในอาร์เรย์ |
$.*.value |
Wildcard: คุณสมบัติทั้งหมด |
.* จะเลือกสมาชิกทุกตัวของอ็อบเจกต์และทุกองค์ประกอบของอาร์เรย์ ดังนั้น $.items.*.name จึงเข้าถึง 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
ตัวอย่าง — การแก้ไขด้วย wildcard:
[Body Rewrite]
^https://api\.example\.com/list.* jsonpath-response jsonpath $.items[*].hidden true
ตัวอย่างการใช้งานจริง
ลบพารามิเตอร์ติดตามจากการตอบกลับ JSON
ลบฟิลด์ trackingId จากการตอบกลับ API ทั้งหมด เนื่องจากมีเพียงกฎแรกที่ตรงกันต่อทิศทางเท่านั้นที่ถูกใช้ ให้ใช้หนึ่งกฎต่อหนึ่งรูปแบบ URL:
[Body Rewrite]
^https://api\.example\.com/.* jsonpath-response jsonpath $.trackingId null
แทรกแท็กสคริปต์ในการตอบกลับ HTML
เพิ่มแท็ก <script> ที่กำหนดเองก่อน </body> ในหน้า HTML ทั้งหมด:
[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
เขียน URL CDN ใหม่ในการตอบกลับที่แคช
แทนที่การอ้างอิงทั้งหมดไปยัง CDN เก่าด้วย CDN ใหม่:
[Body Rewrite]
^https://www\.example\.com/.* response regex "https://old-cdn\.example\.com" "https://new-cdn.example.com"
ไปป์ไลน์การประมวลผล
Body Rewrite จัดการโดยอัตโนมัติ:
- Content-Encoding: รองรับ
gzipและdeflateข้ามการเข้ารหัสที่ไม่รองรับ - Transfer-Encoding: ถอด chunked transfer encoding ก่อนการประมวลผล
- การถอดรหัส: คลายการบีบอัดเนื้อหาก่อนใช้กฎการเขียนใหม่
- การเข้ารหัสใหม่: บีบอัดเนื้อหาใหม่และอัปเดต
Content-Lengthลบส่วนหัวTransfer-Encoding - Accept-Encoding: เมื่อกฎการตอบกลับจับคู่กับ URL ของคำขอ ส่วนหัว
Accept-Encodingของคำขอจะถูกเขียนใหม่เป็นgzip, deflate, identityเพื่อให้การตอบกลับยังคงอยู่ในการเข้ารหัสที่ถอดรหัสได้
ขนาดเนื้อหาสูงสุดสำหรับการประมวลผลการเขียนใหม่คือ 128KB บน HTTP/1.x (HTTP ธรรมดาและ HTTP/1.1 ที่ถอดรหัสแล้ว) เนื้อหาที่ใหญ่กว่านี้จะถูกส่งต่อโดยไม่มีการแก้ไข ส่วนข้อความ HTTP/2 ที่ถอดรหัสแล้วจะถูกบัฟเฟอร์ไว้ทั้งหมดและถูกเขียนใหม่ไม่ว่าจะมีขนาดเท่าใด
บน HTTP/1.x เนื้อหาการตอบกลับจะถูกเขียนใหม่เมื่อมาถึงครบทั้งหมดแล้วเท่านั้น หากเซิร์ฟเวอร์ปิดการเชื่อมต่อก่อน เนื้อหาที่ไม่มีทั้ง
Content-Lengthและ chunked encoding จะจบลงพร้อมการเชื่อมต่อ จึงถือว่าครบแล้วและถูกเขียนใหม่ตามปกติ ส่วนเนื้อหาที่กำหนดขอบเขตด้วยContent-Lengthหรือ chunked encoding แต่ถูกการปิดตัดขาดกลางทาง จะถูกส่งให้ไคลเอนต์ตามที่ได้รับมาทุกประการ ไม่ถูกเขียนใหม่และไม่แก้Content-Lengthจากนั้นการเชื่อมต่อจะถูกปิด เพื่อให้ไคลเอนต์รู้ได้ว่าการตอบกลับไม่ครบ
หมายเหตุ
- สำหรับทราฟฟิก HTTPS ต้องเปิดใช้งานการถอดรหัส MitM สำหรับชื่อโฮสต์ที่ตรงกัน
- การจับคู่ regex เป็นแบบไม่คำนึงถึงตัวพิมพ์เล็กใหญ่ เทมเพลตการแทนที่รองรับการอ้างอิงกลุ่มจับคู่ ICU:
$0(การจับคู่เต็ม),$1(กลุ่มแรก),$2(กลุ่มที่สอง) ฯลฯ - รูปแบบ URL หรือรูปแบบเนื้อหาที่ไม่ใช่นิพจน์ปกติที่ถูกต้อง จะทำให้บรรทัดแบบ regex หรือ JSONPath เป็นข้อผิดพลาดในการกำหนดค่า และกฎนั้นจะไม่ถูกโหลด ส่วนบรรทัด jq จะถูกข้ามพร้อมคำเตือนแทน ในคู่ที่อยู่ถัดจากคู่แรก รูปแบบที่ไม่ถูกต้องจะทำให้เฉพาะคู่นั้นถูกตัดทิ้ง พร้อมคำเตือนในบันทึก
- โหมด JSONPath ใช้ได้เฉพาะเมื่อเนื้อหาเป็น JSON ที่ถูกต้อง
- กฎ Body Rewrite ถูกใช้กับเนื้อหาข้อความที่ถอดรหัส (UTF-8)
- จะมีเพียงกฎแรกที่ตรงกันต่อทิศทาง (คำขอ / การตอบกลับ) เท่านั้นที่ถูกใช้กับข้อความหนึ่ง ๆ กำหนดกฎรวมเพียงกฎเดียวหากคุณต้องการแก้ไขหลายจุด
- การลบ JSONPath ที่ไม่มีอยู่จะทำให้เนื้อหาไม่เปลี่ยนแปลง การตั้งค่าจะสร้างคีย์เมื่ออ็อบเจกต์แม่ของมันมีอยู่ หากเส้นทางระหว่างกลางหายไป จะไม่มีอะไรเกิดขึ้น
หน้านี้เป็นฉบับแปลจากเวอร์ชันภาษาอังกฤษ หากเนื้อหาไม่ตรงกัน ให้ยึดเวอร์ชันภาษาอังกฤษเป็นหลัก