Які символи роблять URL-адресу недійсною?


514

Які символи роблять URL-адресу недійсною?

Це дійсні URL-адреси?

  • example.com/file[/].html
  • http://example.com/file[/].html

42
Під час перевірки слід завжди "думати позитивно": запитувати "що справедливо", все інше недійсне. Тестування на (кількох) дійсних символах набагато безпечніше (і простіше!), Ніж усі можливі недійсні.
— mfx

Відповіді:


600

Загалом URI, визначені RFC 3986 (див. Розділ 2: Символи ), можуть містити будь-який із наступних 84 символів:

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

Зауважте, що в цьому списку не вказано, де в URI можуть виникати ці символи.

Будь-який інший символ повинен бути кодований відсотковим кодуванням ( %hh). Кожна частина URI має додаткові обмеження щодо того, які символи мають бути представлені у відсотках закодованим словом.


31
(звичайно, у списку символів не
— вказано,

75
Ось регулярний вираз, який визначає, чи містить весь рядок лише символи вище: / ^ [! # $ & -; =? - [] _ ​​a-z ~] + $ /
— Leif Wickland

43
@techiferous, Так, я забув дозволити "%" втікаючим символам. Це повинно було виглядати більше так: /^([!#$&-;=?-[]_a-z~]|%[0-9a-fA-F]{2})+$/ Чи було щось інше, що ви виявили, що воно повинно було прийняти? (Просто для того, щоб зрозуміти, що регулярний вираз перевіряє, чи містить рядок дійсні символи URL-адреси, а не, якщо рядок містить добре сформовану URL-адресу.)
— Leif Wickland

12
@Timwi RFC 3986 говорить: "Октет, кодований у відсотках, кодується як триплет символів, що складається з відсоткових символів"% ", а потім двох шестинадцяткових цифр, що представляють числове значення цього октету". Він також говорить: "Оскільки символ відсотка ("% ") служить індикатором для кодованих відсотками октетів, він повинен бути кодований у відсотках як"% 25 ", щоб цей октет використовувався як дані в URI". Я прочитав це, як кажучи, що "%" може з'являтися, лише якщо за ним слід дві шістнадцяткові цифри. Як ти це читаєш?
— Лейф Вікленд

13
@Weeble Мій регекс включив ці символи, використовуючи діапазони. Між '&' та ';' і між "?" і "[" ви знайдете всіх тих символів, яких ви не бачили.
— Лейф Вікленд

193

Щоб додати деякі пояснення та безпосередньо вирішити це питання вище, існує кілька класів символів, які спричиняють проблеми для URL-адрес та URI-адрес.

Є деякі символи, які заборонені і ніколи не повинні відображатися в URL / URI, зарезервовані символи (описані нижче) та інші символи, які можуть викликати проблеми в деяких випадках, але позначені як "нерозумні" або "небезпечні". Пояснення, чому символи обмежені, чітко прописані в RFC-1738 (URL-адреси) та RFC-2396 (URI). Зауважте, що новіший RFC-3986 (оновлення до RFC-1738) визначає побудову того, які символи дозволені в даному контексті, але старша специфікація пропонує більш простий і більш загальний опис, який символів заборонено, за допомогою наступних правил.

Виключені символи US-ASCII, заборонені в синтаксисі URI:

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

Символ "#" виключається, оскільки він використовується для розмежування URI від ідентифікатора фрагмента. Значок "%" у відсотках виключається, оскільки він використовується для кодування уникнутих символів. Іншими словами, "#" і "%" є зарезервованими символами, які повинні використовуватися в конкретному контексті.

Список нерозумних символів дозволений, але може спричинити проблеми:

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

Символи, які зарезервовані в компоненті запиту та / або мають спеціальне значення в URI / URL:

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

Вище "зарезервований" клас синтаксису відноситься до тих символів, які дозволені в URI, але які можуть бути дозволені в певному компоненті загального синтаксису URI. Символи в "зарезервованому" наборі зарезервовані не у всіх контекстах . Наприклад, ім'я хоста може містити необов'язкове ім'я користувача, щоб воно могло бути чимось таким, ftp://user@hostname/де символ "@" має особливе значення.

Ось приклад URL-адреси, що містить недійсні та нерозумні символи (наприклад, '$', '[', ']') і має бути правильно закодована:

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

Деякі обмеження символів для URI / URL-адрес залежать від мови програмування. Наприклад, "|" Символ (0x7C), хоча в специфіці URI лише позначений як "нерозумний", передасть URISyntaxException в конструкторі Java java.net.URI, щоб така URL-адреса http://api.google.com/q?exp=a|bне була дозволена і повинна бути закодована замість цього, як http://api.google.com/q?exp=a%7Cbякщо б використовується Java з екземпляром об'єкта URI.


2
Відмінна, ретельна відповідь, єдина, яка безпосередньо відповість на актуальне питання. Зарезервований розділ може потребувати роботи, наприклад, буквальний ?просто в розділі запитів, але перед ним неможливо, і я не думаю, що він @належить до жодного з цих списків. О, і замість %25останнього рядка, ти це не маєш на увазі %7C?
— Боб Штейн

1
Дякую. Хороший улов:% 25 був помилковим прикладом. Додано виноску до "застереженого" опису синтаксису безпосередньо з RFC-2396.
— JasonM1

1
Ця відповідь непогана , але є деякі плутанини та помилки. Ви спочатку поєднуєте заборонені та зарезервовані символи (дуже різні речі), ви робите занадто велику різницю між "нерозумними" символами та іншими забороненими символами (випадає в RFC 3986 і синтаксично не має значення навіть у RFC 2396), і ви заплутано представляєте список всі зарезервовані символи як список, зарезервований "у складі запиту" .
— Марк Амері

1
Дякую, не означало групувати заборонених і зарезервованих як однакових. Оновлено відповідь. Правила IMHO в RFC-2396, хоча і старші, простіші для розуміння, ніж оновлені правила 3986. Відповідь відображає більше, які символи можуть бути проблемними в цілому, а не саме те, в якому контексті це дозволено чи не дозволено.
— JasonM1

1
Примітно, що Tomcat в останніх випусках (7.0.73+, 8.0.39+, 8.5.7+) почав відхиляти запити символів із категорії "нерозумно" з помилками HTTP 400: "Недійсний символ знайдено в цілі запиту. дійсні символи визначені в RFC 7230 та RFC 3986 "
— Філіп

100

Більшість наявних відповідей тут недоцільні, оскільки вони повністю ігнорують використання реальних адрес таких адрес:

По-перше, відступ до термінології. Що є ці адреси? Чи дійсні URL-адреси?

Історично відповідь була "ні". За даними RFC 3986 , з 2005 року такі адреси не є URI-адресами (і, отже, не URL-адресами, оскільки URL-адреси є типом URI ). Відповідно до термінології стандартів IETF 2005 року, ми повинні належним чином називати їх IRI (Інтернаціоналізовані ідентифікатори ресурсів), визначені в RFC 3987 , які технічно не є URI, але можуть бути перетворені в URI просто шляхом процентного кодування всіх символів, що не мають ASCII в IRI .

Відповідно до сучасної специфікації, відповідь "так". WHATWG Living Standard просто класифікує все , що було раніше називатися «URIs» або «ІРІС» , як «URL - адреса». Це узгоджує вказану термінологію з тим, як звичайні люди, які не читали специфікацію, використовують слово "URL", що було однією з цілей специфікації .

Які символи дозволені відповідно до життєвого стандарту WHATWG?

Які нові символи "URL" дозволяють використовувати відповідно до цього нового значення "URL"? У багатьох частинах URL-адреси, таких як рядок запиту та шлях, ми можемо використовувати довільні "URL-адреси" , які є

Точки коду URL та байти, кодовані у відсотках .

Що таке "URL-адреси коду"?

В точки URL коду є ASCII алфавітно - цифровий, U + 0021 (!), U + 0024 ($), U + 0026 (&), U + 0027 ( '), U + 0028 дужка, U + 0029 закриває дужка, 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 (~) та кодові точки в діапазоні U + 00A0 до U + 10FFFD, включно, за винятком сурогатів та нехарактерних ознак.

(Зверніть увагу, що список "точок коду URL-адреси" не включає %, але %це дозволено в "одиницях коду URL-адреси", якщо вони є частиною послідовності кодування відсотків.)

Єдине місце, де я можу помітити, де специфікація дозволяє використовувати будь-який символ, якого немає в цьому наборі, - це хост , де IPv6 адреси вкладені [та ]символи. Повсюдно в URL-адресі дозволені або блоки URL-адрес, або деякий, навіть більш обмежений набір символів.

Які символи були дозволені за старими RFC?

Заради історії, і оскільки це не досліджено повністю в інших місцях у відповідях тут, давайте розглянемо, як було дозволено за старішою парою специфікацій.

Перш за все, у нас є два типи зарезервованих символів RFC 3986 :

  • :/?#[]@, які є частиною загального синтаксису для URI, визначеного в RFC 3986
  • !$&'()*+,;=, які не входять до загального синтаксису RFC, але зарезервовані для використання як синтаксичні компоненти конкретних схем URI. Наприклад, точка з коми і коми використовуються в якості частини синтаксису URI , даних , а також &і =використовуються в якості частини повсюдного ?foo=bar&qux=bazформату в рядках запиту (який НЕ вказаний в RFC 3986).

Будь-який із вищезазначених зарезервованих символів може бути законно використаний в URI без кодування, або для того, щоб служити їх синтаксичному призначенню, або так само як буквальні символи в даних, де таке використання не може бути неправильно інтерпретоване як символ, що обслуговує його синтаксичне призначення. (Наприклад, хоча /в URL-адресі є синтаксичне значення, ви можете використовувати його некодованим у рядку запиту, оскільки він не має значення в рядку запиту.)

RFC 3986 також визначає деякі незарезервовані символи, які завжди можна використовувати просто для представлення даних без будь-якого кодування:

  • abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~

Нарешті, сам %персонаж дозволений для кодування відсотків.

Це залишає лише такі символи ASCII, яким заборонено з’являтись у URL-адресі:

  • Контрольні символи (символи 0-1F та 7F), включаючи нову лінію, вкладку та повернення каретки.
  • "<>\^`{|}

Кожен інший символ із ASCII може юридично містити URL-адресу.

Тоді RFC 3987 розширює цей набір незарезервованих символів на такі діапазони символів унікоду:

  %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

Цей вибір блоку зі старої специфікації здається химерним та довільним, враховуючи останні визначення блоку Unicode ; це, мабуть, тому, що блоки були додані в десятиліття з моменту написання RFC 3987.


Нарешті, можливо, варто відзначити, що просто знати, які символи можуть легально відображатися в URL-адресі, недостатньо, щоб визнати, чи є певна рядок законною URL-адресою чи ні, оскільки деякі символи є легальними лише в окремих частинах URL-адреси. Наприклад, зарезервовані символи [та ]є легальними як частина прямого хоста IPv6 у URL-адресі, як http: // [1080 :: 8: 800: 200C: 417A] / foo, але не є законними в будь-якому іншому контексті, тому Приклад ОП - http://example.com/file[/].htmlце незаконне.


3
plusone для вичерпних посилань (наприклад, RFC)
— Yan Foto

19

У своєму додатковому запитанні ви запитали, чи www.example.com/file[/].htmlдійсна URL-адреса.

Ця URL-адреса недійсна, оскільки URL-адреса є типом URI, і дійсний URI повинен мати схему типу http:(див. RFC 3986 ).

Якщо ви хотіли запитати, чи http://www.example.com/file[/].htmlє дійсною URL-адресою, відповідь все ще ні, тому що символи квадратних дужок не дійсні.

Символи квадратної дужки зарезервовані для URL-адрес у такому форматі: http://[2001:db8:85a3::8a2e:370:7334]/foo/bar(тобто літерал IPv6 замість імені хоста)

Варто уважно прочитати RFC 3986, якщо ви хочете зрозуміти проблему повністю.


Прочитавши RFC, я більше схильний погодитися з @Stephen C з більш детальним поясненням.
— Сколіма

URL-адреси не є підмножиною URI. [І ]НЕ URI дійсні в протягом майже аналізаторів , які я бачив. Це насправді накрутило мене в реальному світі: stackoverflow.com/questions/11038967/…
— Адам Гент

URL-адреси @AdamGent дуже багато - це підмножина URI. Єдина відмінність між ними полягає в тому, чи описують вони розташування ресурсу - це семантичне відмінність, а не синтаксичне. Якщо парсери, які ви бачили, що позначили себе аналізаторами "URI", трактували квадратні дужки по-різному, ніж ті, що називали себе "URL" аналізаторами, то це чистий збіг, не викликаний різницею між URL-адресами та URI.
— Марк Амері

@ Марк Амеррі аналогічно тому, що C ++ - це суперкомплект C. Це здебільшого, але не зовсім вірно, оскільки (URL і C) набагато старші, вони повинні включати поведінку, яка менш сувора. Проблема полягає в тому, що URL-аналізатори розберуть речі, які не відповідають дійсності URI ... І я маю на увазі більшість із них (відверто кажучи, мені так набридло вказувати це на стільки мов). Не випадково це зворотна сумісність. Чи можемо ми погодитися, що специфікація URL старіша принаймні?
— Адам Ґент

@MarkAmery. Це з бібліотек Python, C #, Java та деяких C, парсери Unwiseдуже серйозно сприйматимуть URI, але все-таки будуть добре працювати з бібліотеками URL. Тобто немає прапора, який ігнорувати Unwise. Мені доведеться перевірити, що таке Rust lang (оскільки він створюється для браузера, мені цікаво, що він робить) для URL-адрес. Однак більшість браузерів із задоволенням також передасть "[", "]". Тож теоретично, як я вже сказав із C / C ++, вони є суб / супер, але реальність не така правда. Це сильно залежить від інтерпретації специфіки та семантики супер / підмножини.
— Адам Гент

12

Усі дійсні символи, які можна використовувати в URI ( URL-адреса - це тип URI ), визначені в RFC 3986 .

Усі інші символи можуть бути використані в URL-адресі за умови, що вони спочатку "кодовані URL-адресою". Це передбачає зміну недійсного символу для конкретних "кодів" (як правило, у вигляді відсотка символу (%) з наступним шістнадцятковим числом).

Це посилання, HTML Посилання на кодування URL-адреси , містить список кодувань для недійсних символів.


А для символів Unicode у статті Вікіпедії " Процент кодування" йдеться про таке: "Загальний синтаксис URI передбачає, що нові схеми URI, які передбачають представлення символьних даних в URI, по суті повинні представляти символи з незарезервованого набору без перекладу, і повинен перетворити всі інші символи в байти відповідно до UTF-8, а потім відсотковим кодувати ці значення . "
— DavidRR

9

Кілька діапазонів символів Unicode є дійсним HTML5 , хоча, можливо, все-таки не дуже корисно їх використовувати.

Наприклад, hrefдокументи кажуть http://www.w3.org/TR/html5/links.html#attr-hyperlink-href :

Атрибут href для елементів а та області повинен мати значення, яке є дійсною URL-адресою, потенційно оточеною пробілами.

Тоді визначення "дійсної URL-адреси" вказує на http://url.spec.whatwg.org/ , де зазначено, що воно спрямоване на:

Вирівняйте RFC 3986 та RFC 3987 із сучасними реалізаціями та застарійте їх у процесі.

Цей документ визначає URL-адреси коду як:

Буквено-цифрові ASCII, "!", "$", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/" , ":", ";", "=", "?", "@", "_", "~" та кодові точки в діапазонах 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 до U + CFFFD, U + D0000 до U + DFFFD, U + E1000 до U + EFFFD, U + F0000 до U + FFFFD, U + 100000 до U + 10FFFD.

Термін "Точки коду URL-адреси" потім використовується у виписці:

Якщо c не є кодовою точкою URL-адреси та не "%", помилка розбору.

у кількох частинах алгоритму розбору, включаючи схему, повноваження, відносний шлях, запити та фрагменти: так в основному вся URL-адреса.

Також валідатор http://validator.w3.org/ передає такі URL-адреси, як "你好"і не передає URL-адреси з символами, як пробіли."a b"

Звичайно, як згадував Стівен С, мова йде не лише про символи, а й про контекст: ви повинні розуміти весь алгоритм. Але оскільки клас "URL-адреси коду" використовується в ключових точках алгоритму, він дає гарне уявлення про те, що ви можете використовувати чи ні.

Дивіться також: символи Unicode в URL-адресах


5

Мені потрібно вибрати символ, щоб розділити URL-адреси в рядку, тому я вирішив створити список символів, які не вдалося знайти в URL-адресі самостійно:

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

Отже, можливими варіантами є новий рядок, вкладка, пробіл, зворотний кут і "<>{}^|. Я думаю, я піду пробілом або новим рядком. :)


2

Насправді не є відповіддю на ваше запитання, але перевірка URL-адреси - це справді серйозна піта. Ви, мабуть, просто краще перевірити доменне ім’я та залишити запит частиною URL-адреси. Це мій досвід. Ви також можете вдатися до пінг-адреси URL-адреси і побачити, чи це призводить до правильної відповіді, але це може бути занадто багато для такої простої задачі.

Регулярні вирази для виявлення URL-адрес є рясними, google it :)



Ця відповідь говорить про те, що перевірка URL-адреси - це завдання не для регулярного вираження, а для бібліотеки, орієнтованої на мову / платформу .
— DavidRR

0

Я реалізую старий http (0.9, 1.0, 1.1) запит і відповідь читача / запису. Запити URI - найбільш проблемне місце.

Ви не можете просто використовувати RFC 1738, 2396 або 3986 як є. Існує багато старих клієнтів і серверів HTTP, що дозволяє отримати більше символів. Таким чином , я зробив дослідження на основі випадково опублікованих журналів доступу веб - сервера: "GET URI HTTP/1.0" 200.

Я виявив, що в URI часто використовуються такі нестандартні символи:

\ { } < > | ` ^ "

Ці символи були описані в RFC 1738 як небезпечні .

Якщо ви хочете бути сумісними зі всіма старими клієнтами та серверами HTTP - ви повинні дозволити цим символам у URI запиту.

Детальніше про це дослідження читайте на http-og .


-4

Я придумав пару регулярних виразів для PHP, які перетворять URL-адреси в тексті в якірні теги. (Спочатку він перетворює всі www. Urls в http: // потім перетворює всі URL-адреси з https?: // в 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) );


4
-1; окрім того, що вони обидва залучають URL-адреси в певній якості, це не має нічого спільного з питанням, яке було задано.
— Марк Амері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.