Rexact
Cheatsheet

Regex URL web

Un commentaire à 15 votes sur la question de référence (779 000 vues) cite une regex tirée d'une ancienne page de documentation Microsoft comme « la bonne ». Notre analyse ReDoS la classe pourtant vulnérable, complexité exponentielle, avec une chaîne d'attaque concrète. Voici le motif « web URL » de Diego Perini (1600+ étoiles sur GitHub), comparé à 3 tentatives réellement copiées.

/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9¡-￿][a-z0-9¡-￿_-]{0,62})?[a-z0-9¡-￿]\.)+(?:[a-z¡-￿]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i
passe 20/20 cas

Comparatif des patterns existants

SourcepatternScore sur le corpusReDoS
Stack Overflow — commentaire citant une regex Microsoft (page MSDN retirée), 15 votes^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_]*)?$11 / 20vulnérable (ftp://psssssssssssssssssssssssssssssssssssssssssssssssssssss…)
Stack Overflow — réponse de Divya-Systematix (classe de caractères mal formée)^(http|https):\/\/+[\www\d]+\.[\w]+(\/[\w\d]+)?$13 / 20sûr
Stack Overflow — le motif « en une ligne » très largement copié^(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6}|:[0-9]{3,4})\b([-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)$13 / 20indéterminé

Implémentation

const re = new RegExp("^(?:(?:(?:https?|ftp):)?\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z0-9¡-￿][a-z0-9¡-￿_-]{0,62})?[a-z0-9¡-￿]\\.)+(?:[a-z¡-￿]{2,}\\.?))(?::\\d{2,5})?(?:[/?#]\\S*)?$", "i");
re.test(input);

Limites

  • Le port n'est vérifié que par son nombre de chiffres (2 à 5), pas par sa plage réelle : « https://example.com:99999 » passe alors que ce port n'existe pas (les ports réels vont de 0 à 65535).
  • Exclut volontairement les noms à un seul label comme « localhost » — un choix assumé pour une URL web publique, pas adapté à un contexte de développement local.
  • Exclut les adresses IP privées ou réservées (10.x, 172.16-31.x, 192.168.x…) : une URL techniquement valide sur un réseau interne sera rejetée, un comportement volontaire pour éviter qu'un formulaire public pointe vers un réseau local.
  • Accepte la forme protocole-relatif (« //example.com ») et l'authentification intégrée à l'URL (« user:pass@… »), deux formes valides mais dont la seconde est dépréciée par les navigateurs modernes pour des raisons de sécurité.