Quels caractères rendent une URL invalide?

515

Quels caractères rendent une URL invalide?

Ces URL sont-elles valides?

  • example.com/file[/].html
  • http://example.com/file[/].html
bien
la source
43
Lors de la validation, vous devez toujours "penser positif": demandez "ce qui est valide", tout le reste n'est pas valide. Tester les (quelques) caractères valides est beaucoup plus sûr (et plus facile!) Que tous les caractères invalides possibles.
mfx

Réponses:

600

En général, les URI tels que définis par la RFC 3986 (voir Section 2: Caractères ) peuvent contenir l'un des 84 caractères suivants:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=

Notez que cette liste n'indique pas où dans l'URI ces caractères peuvent apparaître.

Tout autre caractère doit être codé avec le pourcentage de codage ( %hh). Chaque partie de l'URI a des restrictions supplémentaires sur les caractères qui doivent être représentés par un mot codé en pourcentage.

Gombo
la source
31
(bien sûr, la liste des personnages n'indique pas dans l'uri ils peuvent apparaître)
Eamon Nerbonne
75
Voici une expression régulière qui déterminera si la chaîne entière ne contient que les caractères ci-dessus: / ^ [! # $ & -; =? - [] _ ​​a-z ~] + $ /
Leif Wickland
43
@techiferous, Ouais, j'ai oublié d'autoriser les caractères d'échappement "%". Cela aurait dû ressembler davantage à: /^([!#$&-;=?-[]_a-z~]|%[0-9a-fA-F]{2})+$/ Y avait-il autre chose que vous aviez trouvé qu'il aurait dû accepter? (Juste pour être clair, cette expression régulière vérifie uniquement si la chaîne contient des caractères d'URL valides, pas si la chaîne contient une URL bien formée.)
Leif Wickland
12
@Timwi RFC 3986 indique: "Un octet codé en pourcentage est codé comme un triplet de caractères, composé du caractère en pourcentage"% "suivi des deux chiffres hexadécimaux représentant la valeur numérique de cet octet." Il indique également: "Parce que le caractère pourcentage ("% ") sert d'indicateur pour les octets codés en pourcentage, il doit être codé en pourcentage comme"% 25 "pour que cet octet soit utilisé comme données dans un URI." J'ai lu cela comme disant qu'un "%" ne peut apparaître que s'il est suivi de deux chiffres hexadécimaux. Comment le lisez-vous?
Leif Wickland du
13
@Weeble Mon expression régulière a inclus ces caractères en utilisant des plages. Entre et ';' et entre '?' et '[' vous trouverez tous ces personnages que vous n'avez pas vus.
Leif Wickland
195

Pour ajouter des éclaircissements et répondre directement à la question ci-dessus, il existe plusieurs classes de caractères qui causent des problèmes pour les URL et les URI.

Certains caractères sont interdits et ne doivent jamais apparaître dans une URL / URI, des caractères réservés (décrits ci-dessous) et d'autres caractères qui peuvent provoquer des problèmes dans certains cas, mais sont marqués comme «imprudents» ou «dangereux». Les explications pour lesquelles les caractères sont restreints sont clairement énoncées dans la RFC-1738 (URL) et la RFC-2396 (URI). Notez que la nouvelle RFC-3986 (mise à jour de la RFC-1738) définit la construction des caractères autorisés dans un contexte donné, mais l'ancienne spécification offre une description plus simple et plus générale de quels caractères ne sont pas autorisés avec les règles suivantes.

Caractères US-ASCII exclus non autorisés dans la syntaxe URI:

   control     = <US-ASCII coded characters 00-1F and 7F hexadecimal>
   space       = <US-ASCII coded character 20 hexadecimal>
   delims      = "<" | ">" | "#" | "%" | <">

Le caractère "#" est exclu car il est utilisé pour délimiter un URI d'un identifiant de fragment. Le caractère de pourcentage "%" est exclu car il est utilisé pour le codage des caractères d'échappement. En d'autres termes, les "#" et "%" sont des caractères réservés qui doivent être utilisés dans un contexte spécifique.

La liste des caractères imprudents est autorisée mais peut provoquer des problèmes:

   unwise      = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"

Caractères réservés dans un composant de requête et / ou ayant une signification particulière dans un URI / URL:

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

La classe de syntaxe "réservée" ci-dessus fait référence aux caractères autorisés dans un URI, mais qui peuvent ne pas l'être dans un composant particulier de la syntaxe URI générique. Les caractères de l'ensemble "réservé" ne sont pas réservés dans tous les contextes . Le nom d'hôte, par exemple, peut contenir un nom d'utilisateur facultatif, ce qui pourrait être quelque chose comme ftp://user@hostname/où le caractère «@» a une signification spéciale.

Voici un exemple d'URL qui a des caractères invalides et imprudents (par exemple '$', '[', ']') et doit être correctement encodé:

http://mw1.google.com/mw-earth-vectordb/kml-samples/gp/seattle/gigapxl/$[level]/r$[y]_c$[x].jpg

Certaines restrictions de caractères pour les URI / URL dépendent du langage de programmation. Par exemple, le '|' (0x7C) caractère bien que marqué comme « imprudents » dans la spécification URI jetteront un URISyntaxException dans Java java.net.URI constructeur si une URL comme http://api.google.com/q?exp=a|bn'est pas autorisée et doit être codé au lieu que http://api.google.com/q?exp=a%7Cbsi vous utilisez Java avec une instance d'objet URI.

JasonM1
la source
2
Excellente réponse approfondie, la seule à répondre directement à la vraie question. La section réservée peut avoir besoin de travail, par exemple, le littéral ?est très bien dans la section de requête, mais impossible avant, et je ne pense pas qu'il @appartient à aucune de ces listes. Oh, et au lieu de %25dans la dernière chaîne, tu ne veux pas dire %7C?
Bob Stein
1
Merci. Bonne capture: le% 25 était une faute de frappe dans l'exemple. Ajout d'une note de bas de page à la description de la syntaxe "réservée" directement à partir de la RFC-2396.
JasonM1
1
Cette réponse n'est pas mauvaise , mais il y a des confusions et des erreurs. Vous confondez initialement les caractères interdits et réservés (choses très différentes), vous faites trop de distinction entre les caractères "imprudents" et les autres caractères interdits (supprimés dans la RFC 3986 et non pertinents sur le plan syntaxique même dans la RFC 2396), et vous présentez une liste confuse de tous les caractères réservés comme la liste réservée "dans un composant de requête" .
Mark Amery
1
Merci, je ne voulais pas regrouper les personnes non autorisées et réservées comme les mêmes. Mis à jour la réponse. Les règles IMHO de la RFC-2396, bien qu'anciennes, sont plus simples à comprendre que les règles mises à jour de 3986. La réponse reflète davantage les caractères qui peuvent être gênants en général plutôt que le contexte exact où elle est autorisée ou non.
JasonM1
1
Il est à noter que Tomcat dans les versions récentes (7.0.73+, 8.0.39+, 8.5.7+) a commencé à rejeter les demandes avec des caractères de la catégorie "imprudent" avec des erreurs HTTP 400: "Caractère non valide trouvé dans la cible de la demande. Le les caractères valides sont définis dans les RFC 7230 et RFC 3986 "
Philip
101

La plupart des réponses existantes ici ne sont pas pratiques car elles ignorent totalement l'utilisation dans le monde réel d'adresses comme:

Tout d'abord, une digression dans la terminologie. Quelles sont ces adresses? S'agit-il d'URL valides?

Historiquement, la réponse était "non". Selon la RFC 3986 , à partir de 2005, ces adresses ne sont pas des URI (et donc pas des URL, car les URL sont un type d'URI ). Selon la terminologie des normes IETF 2005, nous devrions les appeler correctement IRI (Internationalized Resource Identifiers), tels que définis dans la RFC 3987 , qui ne sont techniquement pas des URI mais qui peuvent être convertis en URI simplement en encodant en pourcentage tous les caractères non ASCII dans l'IRI .

Selon les spécifications modernes, la réponse est "oui". Le WHATWG Living Standard classe simplement tout ce qui serait auparavant appelé "URI" ou "IRI" comme "URL". Cela aligne la terminologie spécifiée sur la façon dont les personnes normales qui n'ont pas lu la spécification utilisent le mot "URL", qui était l'un des objectifs de la spécification .

Quels caractères sont autorisés en vertu du niveau de vie WHATWG?

Selon cette nouvelle signification de "URL", quels caractères sont autorisés? Dans de nombreuses parties de l'URL, telles que la chaîne de requête et le chemin, nous sommes autorisés à utiliser des "unités d'URL" arbitraires , qui sont

Points de code URL et octets codés en pourcentage .

Que sont les «points de code URL»?

Les points de code URL sont alphanumériques ASCII, U + 0021 (!), U + 0024 ($), U + 0026 (&), U + 0027 ('), U + 0028 PARENTHÈSE GAUCHE, U + 0029 PARENTHÈSE DROITE, U + 002A (*), U + 002B (+), U + 002C (,), U + 002D (-), U + 002E (.), U + 002F (/), U + 003A (:), U + 003B (;), U + 003D (=), U + 003F (?), U + 0040 (@), U + 005F (_), U + 007E (~) et points de code dans la plage U + 00A0 à U + 10FFFD, inclus, à l'exclusion des substituts et des non-caractères.

(Notez que la liste des "points de code URL" ne comprend pas %, mais que les %s sont autorisés dans les "unités de code URL" s'ils font partie d'une séquence de codage en pourcentage.)

Le seul endroit où je peux repérer où la spécification autorise l'utilisation de tout caractère qui n'est pas dans cet ensemble est dans l' hôte , où les adresses IPv6 sont incluses entre les caractères [et ]. Partout ailleurs dans l'URL, les unités d'URL sont autorisées ou un ensemble de caractères encore plus restrictif.

Quels caractères étaient autorisés dans les anciens RFC?

Par souci d'histoire, et comme cela n'est pas exploré complètement ailleurs dans les réponses ici, examinons ce qui était autorisé sous l'ancienne paire de spécifications.

Tout d'abord, nous avons deux types de caractères réservés RFC 3986 :

  • :/?#[]@, qui font partie de la syntaxe générique d'un URI défini dans la RFC 3986
  • !$&'()*+,;=, qui ne font pas partie de la syntaxe générique de la RFC, mais sont réservés à une utilisation en tant que composants syntaxiques de schémas URI particuliers. Par exemple, des points - virgules et les virgules sont utilisés dans le cadre de la syntaxe des URIs de données , et &et =sont utilisés dans le cadre de l'omniprésent ?foo=bar&qux=bazformat dans les chaînes de requête (qui ne sont pas spécifié par la RFC 3986).

N'importe lequel des caractères réservés ci-dessus peut être légalement utilisé dans un URI sans codage, soit pour servir leur objectif syntaxique, soit comme caractères littéraux dans les données à certains endroits où une telle utilisation ne peut pas être mal interprétée comme le caractère servant son objectif syntaxique. (Par exemple, bien qu'il /ait une signification syntaxique dans une URL, vous pouvez l'utiliser non codé dans une chaîne de requête, car il n'a pas de signification dans une chaîne de requête.)

La RFC 3986 spécifie également certains caractères non réservés , qui peuvent toujours être utilisés simplement pour représenter des données sans aucun encodage:

  • abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~

Enfin, le %caractère lui-même est autorisé pour les encodages en pourcentage.

Cela ne laisse que les caractères ASCII suivants qui sont interdits d'apparaître dans une URL:

  • Les caractères de contrôle (caractères 0-1F et 7F), y compris la nouvelle ligne, la tabulation et le retour chariot.
  • "<>\^`{|}

Tout autre caractère ASCII peut légalement figurer dans une URL.

La RFC 3987 étend ensuite cet ensemble de caractères non réservés avec les plages de caractères unicode suivantes:

  %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD

Ces choix de bloc de l'ancienne spécification semblent bizarres et arbitraires étant donné les dernières définitions de bloc Unicode ; cela est probablement dû au fait que les blocs ont été ajoutés au cours de la décennie écoulée depuis la rédaction de la RFC 3987.


Enfin, il convient peut-être de noter que le simple fait de savoir quels caractères peuvent légalement apparaître dans une URL n'est pas suffisant pour reconnaître si une chaîne donnée est une URL légale ou non, car certains caractères ne sont légaux que dans des parties particulières de l'URL. Par exemple, les caractères réservés [et ]sont autorisés dans le cadre d'un hôte littéral IPv6 dans une URL telle que http: // [1080 :: 8: 800: 200C: 417A] / foo mais ne sont pas autorisés dans un autre contexte, de sorte que le L'exemple d'OP http://example.com/file[/].htmlest illégal.

Mark Amery
la source
3
plus un pour des références exhaustives (par exemple, RFC)
Yan Foto
19

Dans votre question supplémentaire, vous avez demandé si l' www.example.com/file[/].htmlURL était valide.

Cette URL n'est pas valide car une URL est un type d'URI et un URI valide doit avoir un schéma comme http:(voir RFC 3986 ).

Si vous vouliez demander si http://www.example.com/file[/].htmlune URL est valide, la réponse est toujours non, car les caractères entre crochets ne sont pas valides à cet endroit.

Les caractères entre crochets sont réservés aux URL dans ce format: http://[2001:db8:85a3::8a2e:370:7334]/foo/bar(c'est-à-dire un littéral IPv6 au lieu d'un nom d'hôte)

Il vaut la peine de lire attentivement la RFC 3986 si vous voulez bien comprendre le problème.

Dominic Sayers
la source
Après avoir lu la RFC, je suis plus enclin à être d'accord avec une explication plus détaillée de @Stephen C.
skolima
Une URL n'est pas un sous-ensemble d'URI. L' URI [et ]ne sont pas valides pour presque les analyseurs que j'ai vus. Cela m'a en fait vissé dans le monde réel: stackoverflow.com/questions/11038967/…
Adam Gent
Les URL @AdamGent sont en grande partie un sous-ensemble d'URI. La seule différence entre eux est de savoir s'ils décrivent l'emplacement de la ressource - qui est une distinction sémantique et non syntaxique. Si les analyseurs que vous avez vus qui se sont étiquetés comme des analyseurs "URI" ont traité les crochets différemment de ceux qui se sont étiquetés comme des analyseurs "URL", alors c'est une pure coïncidence, pas causée par une différence entre les URL et les URI.
Mark Amery
@Mark Amery, c'est analogue à dire que C ++ est un surensemble de C. C'est pour la plupart mais pas entièrement vrai parce que (URL et C) est beaucoup plus ancien, ils doivent inclure un comportement moins strict. Le problème est que les analyseurs d'URL analyseront des choses qui ne sont pas des URI valides ... Et je veux dire la plupart d'entre eux (franchement, je suis tellement fatigué de le signaler dans tant de langues) Ce n'est pas un hasard si c'est une compatibilité descendante. Pouvons-nous convenir que les spécifications d'URL sont au moins plus anciennes?
Adam Gent
@MarkAmery C'est à partir de Python, C #, Java et de certaines bibliothèques C que les analyseurs prendront Unwisetrès au sérieux pour les URI et pourtant seront très bien avec les bibliothèques d'URL. C'est qu'il n'y a pas de drapeau à ignorer Unwise. Je vais devoir vérifier ce que Rust lang (car il est construit pour un navigateur, je suis curieux de savoir ce qu'il fait) pour les URL. Cependant, la plupart des navigateurs passeront volontiers "[", "]". Donc, en théorie, comme je l'ai dit avec C / C ++, ils sont sub / super mais la réalité n'est pas si vraie. Il dépend fortement de l'interprétation de la spécification et de la sémantique du super / sous-ensemble.
Adam Gent
12

Tous les caractères valides qui peuvent être utilisés dans un URI (une URL est un type d' URI ) sont définis dans la RFC 3986 .

Tous les autres caractères peuvent être utilisés dans une URL à condition qu'ils soient d'abord "URL encodés". Cela implique de modifier le caractère non valide pour des "codes" spécifiques (généralement sous la forme du symbole de pourcentage (%) suivi d'un nombre hexadécimal).

Ce lien, HTML URL Encoding Reference , contient une liste des encodages pour les caractères non valides.

CraigTP
la source
Et pour les caractères Unicode , l'article de Wikipedia à codage en pourcentage dit ce qui suit: "La syntaxe générique d'URI stipule que les nouveaux schémas d'URI qui fournissent la représentation des données de caractères dans un URI doivent, en effet, représenter les caractères de l'ensemble non réservé sans traduction, et devrait convertir tous les autres caractères en octets selon UTF-8, puis encoder en pourcentage ces valeurs . "
DavidRR
9

Plusieurs des plages de caractères Unicode sont HTML5 valides , bien que ce ne soit toujours pas une bonne idée de les utiliser.

Par exemple, les hrefdocuments indiquent http://www.w3.org/TR/html5/links.html#attr-hyperlink-href :

L'attribut href sur les éléments a et area doit avoir une valeur qui est une URL valide potentiellement entourée d'espaces.

Ensuite, la définition de "URL valide" pointe vers http://url.spec.whatwg.org/ , qui dit qu'elle vise à:

Alignez la RFC 3986 et la RFC 3987 avec les implémentations contemporaines et obsolètes dans le processus.

Ce document définit les points de code URL comme:

ASCII alphanumérique, "!", "$", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/" , ":", ";", "=", "?", "@", "_", "~" et les points de code dans les plages U + 00A0 à U + D7FF, U + E000 à U + FDCF , U + FDF0 à U + FFFD, U + 10000 à U + 1FFFD, U + 20000 à U + 2FFFD, U + 30000 à U + 3FFFD, U + 40000 à U + 4FFFD, U + 50000 à U + 5FFFD, U +60000 à U + 6FFFD, U + 70000 à U + 7FFFD, U + 80000 à U + 8FFFD, U + 90000 à U + 9FFFD, U + A0000 à U + AFFFD, U + B0000 à U + BFFFD, U + C0000 vers U + CFFFD, U + D0000 vers U + DFFFD, U + E1000 vers U + EFFFD, U + F0000 vers U + FFFFD, U + 100000 vers U + 10FFFD.

Le terme "points de code URL" est ensuite utilisé dans la déclaration:

Si c n'est pas un point de code URL et non "%", erreur d'analyse.

dans plusieurs parties de l'algorithme d'analyse, y compris le schéma, l'autorité, le chemin relatif, les états de requête et de fragment: donc fondamentalement l'URL entière.

De plus, le validateur http://validator.w3.org/ passe pour les URL comme "你好", et ne passe pas pour les URL avec des caractères comme des espaces"a b"

Bien sûr, comme l'a mentionné Stephen C, il ne s'agit pas seulement de personnages mais aussi de contexte: il faut comprendre tout l'algorithme. Mais puisque la classe "URL code points" est utilisée sur les points clés de l'algorithme, elle donne une bonne idée de ce que vous pouvez utiliser ou non.

Voir aussi: Caractères Unicode dans les URL

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
5

Je dois sélectionner un caractère pour fractionner les URL en chaîne, j'ai donc décidé de créer une liste de caractères qui ne pouvaient pas être trouvés dans l'URL par moi-même:

>>> allowed = "-_.~!*'();:@&=+$,/?%#[]?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
>>> from string import printable
>>> ''.join(set(printable).difference(set(allowed)))
'`" <\x0b\n\r\x0c\\\t{^}|>'

Ainsi, les choix possibles sont la nouvelle ligne, tabulation, espace, barre oblique inverse et "<>{}^|. Je suppose que j'irai avec l'espace ou la nouvelle ligne. :)

Bunyk
la source
2

Pas vraiment une réponse à votre question, mais la validation des URL est vraiment un problème sérieux Vous êtes probablement mieux de valider le nom de domaine et de laisser une partie de la requête de l'URL. Telle est mon expérience. Vous pouvez également recourir à la commande ping de l'URL et voir si elle aboutit à une réponse valide, mais cela peut être trop pour une tâche aussi simple.

Les expressions régulières pour détecter les URL sont abondantes, google it :)

ChrisR
la source
Cette réponse indique que la validation d'URL est un travail non pas pour une expression régulière, mais pour une bibliothèque spécifique à une langue / plate-forme .
DavidRR
0

J'implémente un ancien lecteur / rédacteur de requêtes et de réponses http (0.9, 1.0, 1.1). L'URI de demande est l'endroit le plus problématique.

Vous ne pouvez pas simplement utiliser RFC 1738, 2396 ou 3986 tel quel. Il existe de nombreux anciens clients et serveurs HTTP qui autorisent plus de caractères. J'ai donc fait la recherche basée sur les journaux d'accès du serveur Web accidentellement publié: "GET URI HTTP/1.0" 200.

J'ai trouvé que les caractères non standard suivants sont souvent utilisés dans l'URI:

\ { } < > | ` ^ "

Ces caractères ont été décrits dans la RFC 1738 comme dangereux .

Si vous souhaitez être compatible avec tous les anciens clients et serveurs HTTP - vous devez autoriser ces caractères dans l'URI de demande.

Veuillez lire plus d'informations sur cette recherche dans http-og .

puchu
la source
-4

J'ai trouvé quelques expressions régulières pour PHP qui convertiront les URL du texte en balises d'ancrage. (D'abord, il convertit toutes les URL www. En http: // puis convertit toutes les URL avec https?: // en liens href = ... html

$string = preg_replace('/(https?:\/\/)([!#$&-;=?\-\[\]_a-z~%]+)/sim', '<a href="$1$2">$2</a>', preg_replace('/(\s)((www\.)([!#$&-;=?\-\[\]_a-z~%]+))/sim', '$1http://$2', $string) );

relipse
la source
4
-1; au-delà du fait qu'ils impliquent tous les deux des URL à un certain titre, cela n'a rien à voir avec la question qui a été posée.
Mark Amery