Réécriture de corps
Chute peut rechercher et remplacer du contenu dans les corps de requête et de réponse HTTP à l'aide d'expressions régulières ou d'expressions JSONPath. Cela nécessite le déchiffrement MitM pour le trafic HTTPS.
Remarque : une requête HTTP en clair n'est traitée que lorsqu'elle parvient à Chute par son proxy HTTP ; le HTTP en clair qui arrive par l'interface TUN est transmis tel quel. Chute Android fait passer tout le trafic par TUN, sauf si Proxy HTTP système est activé dans les Réglages, ce qui fournit aux apps le proxy HTTP de Chute (Android 10 et ultérieur ; désactivé par défaut).
Les programmes jq de Surge http-request-jq et http-response-jq sont également pris en charge — voir Syntaxe Surge.
Les règles de réécriture de corps sont définies dans la section [Body Rewrite]. Pour chaque direction (requête / réponse), seule la première règle correspondante est appliquée à un message. Si un script http-request ou http-response qui reçoit le corps correspond aussi au même message, la règle est appliquée d'abord et le script voit le corps réécrit ; un script http-request-before-send s'exécute après les deux.
[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
Format des règles
Chaque règle suit ce format général :
<regex d'URL> [direction] <mode> <motif> <remplacement>
Remarque : l'expression régulière d'URL est recherchée n'importe où dans l'URL complète de la requête, ainsi que dans son chemin seul, comme pour la réécriture d'URL :
^https://example\.comcouvre déjà tous les chemins et chaînes de requête de cet hôte, un.*final est donc inutile, et^/apicorrespond à toute requête dont le chemin commence par/api. L'URL complète d'une requête déchiffrée commence parhttps://, si bien qu'un motif^http://ne correspond jamais à une telle requête. Le motif conserve sa casse, si bien que\S,\D,\Wet\Bgardent leur sens ; la correspondance elle-même ignore la casse.
Un # ou un // en début de ligne ou après une espace ouvre un commentaire qui s'étend jusqu'à la fin de la ligne, sauf s'il se trouve entre guillemets doubles ; ; ne le fait jamais. Voir Commentaire.
Syntaxe Surge
La forme de ligne propre à Surge est aussi acceptée : la direction vient en premier, et le mot-clé regex est omis.
[Body Rewrite]
http-response ^https://api\.example\.com/feed "\"ads\":\s*\[.*?\]" "\"ads\":[]"
http-request ^https://api\.example\.com/submit "sensitive" "[redacted]"
Une ligne Surge peut porter plusieurs paires motif/remplacement ; elles sont appliquées de gauche à droite, chacune au résultat de la précédente. http-request-jq et http-response-jq prennent un programme jq au lieu d'un motif et d'un remplacement : <type> <URL pattern> <jq program>, le programme étant généralement entre guillemets car il contient des espaces. Hors des guillemets, un // ou un # qui suit une espace ouvre un commentaire, qui met fin au programme à cet endroit ; entre guillemets, // est l'opérateur d'alternative de jq : mettez donc entre guillemets un programme qui l'utilise. Il s'applique au corps traité comme du JSON. Un corps qui n'est pas du JSON, un programme qui lève une erreur et un programme sans sortie laissent tous le corps inchangé ; un programme invalide est signalé et seule cette règle est ignorée, sans faire échouer le reste du profil. Un programme ne peut lire ni fichiers ni environnement : import et include ne résolvent rien, et $ENV comme env sont vides.
Remarque : Chute Android exécute les programmes jq avec jackson-jq. Sa sortie est plafonnée à 4096 résultats ou 4 Mo — un programme qui en produit davantage laisse le corps inchangé — et il lui manque certaines fonctions intégrées de jq 1.7, parmi lesquelles les fonctions de date autres que
now,todateiso8601etfromdateiso8601(strftime,strptime,mktime,gmtime,todateet consorts),@base32et@base32d,abs,toarray,trim,ltrimetrtrim,IN,INDEXetJOIN,tostreametfromstream. Un programme qui appelle l'une d'elles lève une erreur à l'exécution, ce qui laisse le corps inchangé.
Direction
| Mot-clé | Description |
|---|---|
response |
S'applique au corps de la réponse (valeur par défaut si omis) |
request |
S'applique au corps de la requête |
Modes
| Mode | Description |
|---|---|
regex |
Recherche-remplacement par expression régulière |
jsonpath-response / jsonpath-request / body-jsonpath-response / body-jsonpath-request |
Modification fondée sur JSONPath |
Mode regex
Effectue une recherche-remplacement regex standard sur le texte décodé du corps. Utilise NSRegularExpression (ICU) avec une correspondance insensible à la casse. Le remplacement prend en charge les références aux groupes de capture ($1, $2, etc.).
<regex d'URL> [response|request] regex <motif> <remplacement>
Exemple — supprimer les publicités d'une réponse JSON :
[Body Rewrite]
^https://api\.example\.com/feed.* response regex "\"ads\":\s*\[.*?\]" "\"ads\":[]"
Exemple — assainir le corps d'une requête :
[Body Rewrite]
^https://api\.example\.com/submit.* request regex "\"password\":\s*\".*?\"" "\"password\":\"[FILTERED]\""
Exemple — utiliser les groupes de capture pour reformater des données :
[Body Rewrite]
// Transforme "nom, prénom" en "prénom nom"
^https://api\.example\.com/users.* response regex "\"name\":\s*\"(\w+),\s*(\w+)\"" "\"name\":\"$2 $1\""
Exemple — réécrire les URL intégrées au corps de la réponse :
[Body Rewrite]
^https://api\.example\.com.* response regex "https://old-cdn\.example\.com" "https://new-cdn.example.com"
Les jetons contenant des espaces doivent être encadrés par des guillemets doubles :
[Body Rewrite]
^https://example\.com.* response regex "old value with spaces" "new value"
Pour inclure un guillemet double littéral dans un jeton entre guillemets, échappez-le par une barre oblique inverse : \".
Mode JSONPath
Modifie les corps JSON à l'aide d'expressions JSONPath. Prend en charge la lecture, la définition et la suppression de valeurs à des chemins précis.
<regex d'URL> jsonpath-response|jsonpath-request jsonpath <expression-jsonpath> [valeur]
Syntaxe JSONPath prise en charge
| Expression | Description |
|---|---|
$.key |
Accès à une propriété d'objet |
$.key.subkey |
Accès à des propriétés imbriquées |
$[0] |
Accès à un élément de tableau par index |
$.key[0].subkey |
Accès mixte objet et tableau |
$.items[*].name |
Joker : tous les éléments d'un tableau |
$.*.value |
Joker : toutes les propriétés |
.* prend chaque membre d'un objet et chaque élément d'un tableau, si bien que $.items.*.name atteint le nom de chaque élément. En dernière étape sur un tableau, il ne change rien ; pour remplacer les éléments eux-mêmes, utilisez [*].
Types de valeur
| Valeur | Résultat |
|---|---|
string |
Définie sur une valeur chaîne — tout ce qui n'a aucune des formes ci-dessous, si bien que example.com, 1.0.0-beta et 12abc restent des chaînes |
42 |
Définie sur un entier — un token qui est en entier un nombre JSON, sans partie décimale ni exposant |
3.14 |
Définie sur un flottant — un nombre JSON avec une partie décimale ou un exposant, comme 1e3, ou un entier trop grand pour 64 bits |
true |
Définie sur le booléen vrai |
false |
Définie sur le booléen faux |
[…] ou {…} |
Sans guillemets, analysée comme du JSON et affectée comme ce tableau ou cet objet ; c'est le dernier champ, donc le reste de la ligne est pris tel quel et peut contenir des espaces. Entre guillemets, ou si ce n'est pas du JSON valide, la valeur reste une chaîne. |
null, nil ou omise |
Supprime le chemin |
Remarque : mettre une valeur entre guillemets ne force pas le type chaîne — les guillemets sont retirés lors de la tokenisation et le type est déduit du contenu restant :
"42"devient donc le nombre 42,"true"le booléen vrai, et"null"supprime le chemin ; les guillemets ne changent quelque chose que pour[…]et{…}, qui restent des chaînes entre guillemets. Les mots-clés doivent correspondre exactement, casse comprise, si bien queTrueetNULLsont des chaînes. Un nombre n'est reconnu que si le token entier en est un, écrit comme JSON écrit les nombres :+1,.5,1.et007restent des chaînes, tout comme un nombre trop grand même pour un flottant, comme1e400. Aucune écriture ne permet d'affecter une chaîne comme"42"ou"true"— utilisez plutôt une règleregex.
Exemple — définir un champ JSON :
[Body Rewrite]
^https://api\.example\.com/profile.* jsonpath-response jsonpath $.user.name "Anonymous"
Exemple — supprimer un champ JSON :
[Body Rewrite]
^https://api\.example\.com/data.* jsonpath-response jsonpath $.tracking null
Exemple — modification par joker :
[Body Rewrite]
^https://api\.example\.com/list.* jsonpath-response jsonpath $.items[*].hidden true
Exemples pratiques
Retirer les paramètres de suivi des réponses JSON
Supprimez le champ trackingId de toutes les réponses d'API. Comme une seule règle correspondante par direction est appliquée, utilisez une règle par motif d'URL :
[Body Rewrite]
^https://api\.example\.com/.* jsonpath-response jsonpath $.trackingId null
Injecter une balise script dans les réponses HTML
Ajoutez une balise <script> personnalisée avant </body> dans toutes les pages HTML :
[Body Rewrite]
^https://www\.example\.com/.* response regex "</body>" "<script>console.log('injected')</script></body>"
Masquer les champs sensibles dans les journaux de requêtes
Remplacez les clés d'API et les jetons dans les corps de requête sortants avant qu'ils n'atteignent le serveur. Comme une seule règle correspondante par direction est appliquée, combinez les deux champs dans une seule règle :
[Body Rewrite]
^https://api\.example\.com/.* request regex "\"(apiKey|token)\":\s*\"[^\"]+\"" "\"$1\":\"[REDACTED]\""
Normaliser les formats de date dans les réponses
Remplacez les dates ISO par un format plus court :
[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"
Désactiver les indicateurs de fonctionnalité dans la configuration d'une app
Forcez tous les indicateurs de fonctionnalité à false sur un point de terminaison de configuration :
[Body Rewrite]
^https://api\.example\.com/config.* jsonpath-response jsonpath $.features[*].enabled false
Réécrire les URL de CDN dans les réponses en cache
Remplacez toutes les références à un ancien CDN par un nouveau :
[Body Rewrite]
^https://www\.example\.com/.* response regex "https://old-cdn\.example\.com" "https://new-cdn.example.com"
Chaîne de traitement
La réécriture de corps gère automatiquement :
- Content-Encoding : prend en charge
gzipetdeflate. Ignore les encodages non pris en charge. - Transfer-Encoding : dé-fragmente l'encodage de transfert par blocs avant traitement.
- Décodage : décompresse les corps avant d'appliquer les règles de réécriture.
- Réencodage : recompresse les corps et met à jour
Content-Length. Supprime l'en-têteTransfer-Encoding. - Accept-Encoding : lorsqu'une règle de réponse correspond à l'URL d'une requête, l'en-tête
Accept-Encodingde la requête est réécrit engzip, deflate, identityafin que la réponse conserve un encodage décodable.
La taille maximale de corps pour le traitement de réécriture est de 128 Ko en HTTP/1.x (HTTP en clair et HTTP/1.1 déchiffré) ; les corps plus volumineux sont transmis sans modification. Un message HTTP/2 déchiffré est mis en mémoire tampon en entier et réécrit quelle que soit sa taille.
En HTTP/1.x, un corps de réponse n'est réécrit qu'une fois arrivé en entier. Si le serveur ferme la connexion avant, un corps sans
Content-Lengthni encodage par blocs est complet — la fermeture en marque la fin — et il est réécrit comme d'habitude. Un corps délimité parContent-Lengthou par l'encodage par blocs que la fermeture a tronqué est transmis au client exactement tel qu'il est arrivé, sans réécriture et avec sonContent-Lengthintact, puis la connexion est fermée, pour que le client puisse voir que la réponse est incomplète.
Remarques
- Pour le trafic HTTPS, le déchiffrement MitM doit être activé pour le nom d'hôte correspondant.
- La correspondance regex est insensible à la casse. Le modèle de remplacement prend en charge les références de groupe de capture ICU :
$0(correspondance complète),$1(premier groupe),$2(deuxième groupe), etc. - Un motif d'URL ou un motif de corps qui n'est pas une expression régulière valide fait d'une ligne regex ou JSONPath une erreur de configuration, et la règle n'est pas chargée ; une ligne jq est, elle, ignorée avec un avertissement. Dans les paires qui suivent la première, un motif invalide n'écarte que cette paire, avec un avertissement dans le journal.
- Le mode JSONPath ne s'applique que si le corps est un JSON valide.
- Les règles de réécriture de corps sont appliquées au texte décodé (UTF-8) du corps.
- Seule la première règle correspondante par direction (requête / réponse) est appliquée à un message. Définissez une règle combinée si vous devez effectuer plusieurs modifications.
- Supprimer un JSONPath inexistant laisse le corps inchangé. Définir une valeur crée la clé lorsque son objet parent existe ; si un chemin intermédiaire est absent, rien ne se passe.