Aller au contenu

Séquences d'échappement

Presque chaque bug d'échappement est une erreur de contexte plutôt qu'une erreur de syntaxe. Le caractère est connu — un guillemet, une barre oblique inverse, une esperluette — et ce qui n'est pas clair, c'est laquelle des six règles conflictuelles s'applique où la chaîne est sur le point de descendre.

Donc cette table est organisée par contexte, pas par caractère. Le même guillemet est doublé dans une cellule CSV, échappé par barre oblique inverse en JSON, transformé en " en HTML et laissé complètement seul à l'intérieur de guillemets simples dans un shell. Quatre lignes, quatre règles, un caractère.

La règle qui compte le plus est celle que les gens recherchent en dernier : échapper à la limite que la valeur traverse, et l'échapper une fois. Un texte échappé deux fois — un & dans la source de la page, un \\n dans le fichier de sortie — est la signature d'une valeur qui a traversé deux encodeurs qui chacun supposaient qu'ils étaient en premier.

Chaînes JSON

10

JSON permet exactement ces échappements. Une nouvelle ligne ou une tabulation littérale à l'intérieur d'une chaîne est invalide.

ÉchappementSignifieQuand vous en avez besoinEn contexte
\""Un guillemet double à l'intérieur d'une chaîne"say \"hi\""
\\\Une barre oblique inverse littéraleLa raison pour laquelle les chemins Windows cassent JSON."C:\\dir"
\//Une barre oblique — optionnelleLégale mais inutile ; une habitude d'incorporer JSON dans les balises <script>."a\/b"
\nU+000AUn flux de ligne"line\nline"
\rU+000DUn retour à la chariot
\tU+0009Une tabulation
\bU+0008Un retour arrière
\fU+000CUn saut de formulaire
\u00e9éTout caractère par son point de code à quatre chiffres"caf\u00e9"
\ud83d\ude00😀Un caractère au-dessus de U+FFFF, sous forme de paire de remplacementJSON n'a pas de forme \u{…}, donc les caractères astraux prennent deux échappements.

Chaînes JavaScript

10

Un sur-ensemble de JSON, plus les échappements littérals de modèle.

ÉchappementSignifieQuand vous en avez besoinEn contexte
\''Un guillemet simple à l'intérieur d'une chaîne entre guillemets simples
\""Un guillemet double à l'intérieur d'une chaîne entre guillemets doubles
\``Un backtick à l'intérieur d'un littéral de modèle
\${${Un littéral ${ à l'intérieur d'un littéral de modèleSans la barre oblique inverse, il démarre une interpolation.
\nU+000AUn flux de ligne
\xe9éUn caractère par deux chiffres hexadécimaux, jusqu'à U+00FF
\u00e9éUn caractère par quatre chiffres hexadécimaux
\u{1f600}😀N'importe quel point de code, quelle que soit sa longueurN'a pas besoin d'une paire de remplacement, contrairement à la forme à quatre chiffres.
\0U+0000Un caractère nul
\u2028U+2028Séparateur de ligneValide dans une chaîne JS mais pas en JSON — une cassure JSONP classique.

Texte et attributs HTML

8

Seuls & et < doivent strictement être échappés dans le texte ; les guillemets importent à l'intérieur des attributs.

ÉchappementSignifieQuand vous en avez besoinEn contexte
&amp;&Une esperluetteÉchappez celui-ci d'abord, ou chaque autre échappement double.
&lt;<Un signe moins-que, pour qu'il ne commence pas une balise
&gt;>Un signe supérieur à
&quot;"Un guillemet double à l'intérieur d'un attribut
&#39;'Un guillemet simple à l'intérieur d'un attribut&apos; fonctionne aussi en HTML5, mais la forme numérique est sûre partout.
&nbsp;U+00A0Un espace insécable
&#233;éN'importe quel caractère par point de code décimal
&#xE9;éN'importe quel caractère par point de code hexadécimal

URL (codage en pourcentage)

9

Les caractères qui ont besoin d'échappement dépendent de la partie de l'URL dans laquelle ils se trouvent.

ÉchappementSignifieQuand vous en avez besoinEn contexte
%20 Un espace, valide partout dans une URL
+ Un espace, mais seulement dans une chaîne de requête codée en formulaireDans un segment de chemin c'est un signe plus littéral.
%25%Un signe pour cent littéralManquez cela et la valeur se décode deux fois.
%2F/Une barre oblique à l'intérieur d'un segment de chemin unique
%3F?Un point d'interrogation à l'intérieur d'une valeur
%26&Une esperluette à l'intérieur d'une valeur de paramètre
%3D=Un signe égal à l'intérieur d'une valeur de paramètre
%23#Un hachage, pour qu'il ne commence pas le fragment
%C3%A9éUn caractère non-ASCII, sous forme d'octets UTF-8Un caractère peut devenir deux, trois ou quatre groupes de pour cent.

Champs CSV

5

RFC 4180 : enveloppez le champ, puis doublez tous les guillemets intérieurs. Les barres obliques inverses ne signifient rien.

ÉchappementSignifieQuand vous en avez besoinEn contexte
"""Un guillemet à l'intérieur d'un champ entre guillemets — doublez-le"say ""hi"""
"a,b",Un champ contenant le délimiteur — enveloppez le champ
"a b"U+000AUn champ contenant un saut de ligne — enveloppez le champ
" a" Préservez les espaces de début ou de finNon cités, de nombreux analyseurs les coupent.
'=SUM(A1)=Arrêtez un tableur exécutant la cellule en tant que formuleS'applique aux valeurs commençant par =, +, - ou @. C'est une injection de formule.

Littéraux SQL et identifiants

6

Lisez ceux-ci ; ne les écrivez pas. Utilisez des requêtes paramétrées à la place.

ÉchappementSignifieQuand vous en avez besoinEn contexte
'''Un guillemet à l'intérieur d'une chaîne littérale — doublez-le'O''Brien'
"order"orderUn mot réservé utilisé comme nom de colonneLes guillemets doubles sont la norme ; SQL Server utilise [brackets].
`order`orderLa même chose dans MySQL et MariaDB
\%%Un % littéral à l'intérieur d'un motif LIKE
\__Un _ littéral à l'intérieur d'un motif LIKE
$tag$ … $tag$'Guillemets à dollars PostgreSQL — pas d'échappement du tout à l'intérieurUtile pour les corps de code, où doubler chaque guillemet est illisible.

Arguments Shell

6

Les guillemets simples sont littéraux, les guillemets doubles développent toujours les variables.

ÉchappementSignifieQuand vous en avez besoinEn contexte
'…'$ ` \Tout à l'intérieur est littéralLe devis le plus sûr qu'il y ait — mais il ne peut pas contenir un guillemet simple.
"…"* ? spaceLes globs et les espaces sont sûrs, les variables se développent toujoursAlways quote variables: "$var", never bare $var.
\ Un espace dans un nom de fichier non cité
\$$Un signe dollar littéral à l'intérieur de guillemets doubles
\``Un backtick littéral, pas une substitution de commande
'\'''Un guillemet simple à l'intérieur de guillemets simplesFermer, s'échapper, rouvrir — il n'y a pas moyen de le nicher directement.

FAQ

Pourquoi mon JSON casse-t-il sur un chemin de fichier Windows ?
Parce qu'une barre oblique inverse démarre une séquence d'échappement dans une chaîne JSON, donc C:\dir est lu comme C, puis un échappement invalide. Écrit correctement, la valeur est "C:\\dir" — deux barres obliques inverses dans le fichier, une dans la chaîne analysée. Les barres obliques avant fonctionnent aussi sur Windows et évitent entièrement le problème.
Est-ce que %20 ou + est correct pour un espace dans une URL ?
Les deux, à des endroits différents. %20 est correct partout dans une URL. Le signe plus signifie un espace uniquement à l'intérieur d'une chaîne de requête codée en application/x-www-form-urlencoded — dans un segment de chemin, c'est un plus littéral. Utilisez %20 quand vous n'êtes pas sûr, car c'est juste partout.
Comment mettre un guillemet à l'intérieur d'un champ CSV ?
Enveloppez le champ entre guillemets et doublez celui de l'intérieur : "dire ""bonjour""". C'est RFC 4180, et c'est pourquoi un CSV plein de guillemets doublés n'est pas corrompu. Une barre oblique inverse ne signifie rien pour un analyseur CSV conforme.
Quel est l'apostrophe de début dans la ligne de formule CSV ?
Il désarme une injection de formule. Une cellule commençant par =, +, - ou @ est exécutée comme une formule quand le fichier est ouvert dans un tableur, donc une valeur comme =SUM(A1) d'une source non approuvée devient du code. Préfixer une apostrophe force la cellule à être lue comme du texte.
Dois-je échapper SQL à la main ?
Non. Doubler un guillemet est documenté ici parce que vous devez lire du SQL échappé, pas parce que vous devriez l'écrire — utilisez des requêtes paramétrées et laissez le pilote gérer la valeur. L'échappement manuel est d'où vient l'injection SQL, et il n'existe pas de version qui soit sûre par inspection.