Кодировать ли амперсанды в <a href…>?


157

Я пишу код, который автоматически генерирует HTML, и я хочу, чтобы он правильно кодировал вещи.

Допустим, я создаю ссылку на следующий URL:

http://www.google.com/search?rls=en&q=stack+overflow

Я предполагаю, что все значения атрибутов должны быть в кодировке HTML. (Пожалуйста, исправьте меня, если я ошибаюсь.) Таким образом, это означает, что если я помещаю вышеупомянутый URL в тег привязки, я должен закодировать амперсанд &amp;следующим образом:

<a href="http://www.google.com/search?rls=en&amp;q=stack+overflow">

Это правильно?



6
@CiroSantilli: это фактические строки URL; это о том, как они кодируются, когда они появляются в атрибутах HTML.
JW.

Как я вижу, кодирование амперсандов не всегда требуется в HTML5, и ответы устарели.
qdinar

1
вопрос для html5: stackoverflow.com/questions/19441750/…
qdinar

Ответы:


175

Да, это так. Сущности HTML анализируются внутри атрибутов HTML, и отклонение &может привести к неоднозначности. Вот почему вы всегда должны писать, &amp;а не только &внутри всех атрибутов HTML.

Тем не менее, только &и кавычки должны быть закодированы. Если у вас есть специальные символы, такие как éв вашем атрибуте, вам не нужно кодировать их для соответствия анализатору HTML.

Раньше было так, что URL-адреса требовали специальной обработки с не-ASCII символами, например é. Вы должны были закодировать тех, кто использует процент-экранирование, и в этом случае это дало бы %C3%A9, потому что они были определены RFC 1738 . Однако RFC 1738 был заменен RFC 3986 (URI, унифицированными идентификаторами ресурсов) и RFC 3987 (IRI, интернационализированными идентификаторами ресурсов), на которых WhatWG основывал свою работу, чтобы определить, как должны вести себя браузеры, когда они видят URL с не-ASCII символы в нем начиная с HTML5 . Поэтому теперь безопасно включать не-ASCII символы в URL, в процентах или нет.


1
Я был почти уверен в этом, но у меня был редкий момент сомнения. Спасибо за подтверждение.
JW.

1
Вы также можете закодировать пробелы как «+», а не% 20, что облегчает чтение URL.
NickG

1
+ не соблюдается в ссылках mailto в родном почтовом клиенте iPhone, как бы то ни было.
Райан Олсон

1
éвсе еще нуждается в кодировке: stackoverflow.com/questions/2742852/unicode-characters-in-urls
lulalala

4
Я хотел бы добавить (как я только что попал в эту ошибку), что если вы полагаетесь на механизм шаблонов, вы должны проверить, если это автоматически заботится о выходе из сущностей HTML или нет. В моем случае это делал Twig , и я ошибочно дважды избегал записи &amp;в атрибут tag вместо прямого использования &.
Kamafeather

24

Согласно действующим официальным рекомендациям HTML, амперсанд должен быть экранирован, например, &amp;в подобных ситуациях. Однако браузеры не требуют этого, и HTML5 CR предлагает сделать это правилом , чтобы специальные значения применялись в значениях атрибутов. Текущие валидаторы HTML5 в этом отношении устарели (см. Сообщение об ошибке с комментариями).

По-прежнему будет возможно избежать амперсандов в значениях атрибутов, но, кроме проверки с помощью текущих инструментов, нет практической необходимости избегать их в hrefзначениях (и существует небольшой риск допустить ошибки, если вы начнете экранировать их).


4
XHTML ( настоящий XHTML, отправленный как application/xhtml+xml), скорее всего, всегда будет нуждаться в этом, хотя.
zneak

4
Одним из предостережений к этому изменению, которое все еще обсуждается, обсуждается и неправильно понимается, является то, что &сейчас все должно быть в порядке, пока оно « не двусмысленно». Один очевидный способ сделать амперсанд двусмысленным - следовать за ним сначала непробельными символами, а затем точкой с запятой. Это амперсанд сейчас неоднозначна, и будет вызывать ошибку синтаксического анализа.
Мэтти

Как сказал Юкка, безусловно, существует риск кодирования всех амперсандов, поэтому подумайте, насколько вероятно, что один из ваших URL-адресов href содержит точку с запятой. Довольно маловероятно, поскольку я не уверен, что когда-либо видел URL с точкой с запятой. Не то чтобы это не могло быть сделано. Таким образом, на практике я не думаю, что наше использование &будет неоднозначным. Поэтому мы продолжаем использовать его без кодирования в атрибутах href.
Мэтти

Вся причина побега необходима именно из-за возможности двусмысленности . Эта конкретная проблема может не заключаться в представлении векторов атак XSS, плохом рендеринге или каких-либо воздействиях в 99,99% случаев, но это не является причиной, чтобы не беспокоить. Правильно сбежать - сложно, и всегда есть возможность ошибиться.
Фил

5

Я публикую новый ответ, потому что обнаружил, что в ответе zneak недостаточно примеров, он не показывает обработку HTML и URI как различные аспекты и стандарты, а некоторые мелочи отсутствуют.

У вас есть два стандарта, касающиеся URL в ссылках ( <a href).

Первым стандартом является RFC 1866 (HTML 2.0), где в «3.2.1. Символы данных» вы можете прочитать символы, которые необходимо экранировать при использовании в качестве значения для атрибута HTML. (Сами атрибуты вообще не допускают специальных символов, например <a hr&ef="http://..., не разрешены и не разрешены <a hr&amp;ef="http://....)

Позже это вошло в стандарт HTML 4 , символы, которые вы должны экранировать:

<   to   &lt;
>   to   &gt;
&   to   &amp;
"   to   &quote;
'   to   &apos;

Другим стандартом является RFC 3986 «Общий стандарт URI», где обрабатываются URL-адреса (это происходит, когда браузер собирается перейти по ссылке, потому что пользователь нажал на элемент HTML).

reserved    = gen-delims / sub-delims

gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"

sub-delims  = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

Важно избегать этих символов, чтобы клиент знал, представляют ли они данные или разделитель.

Пример unescaped:

https://example.com/?user=test&password&te&st&goto=https://google.com

Пример, полностью допустимый URL

https://example.com/?user=test&password&te%26st&goto=https%3A%2F%2Fgoogle.com

Пример полностью допустимого URL в значении атрибута HTML:

https://example.com/?user=test&amp;password&amp;te%26st&amp;goto=https%3A%2F%2Fgoogle.com

Также важны сценарии:

  • Javascript как значение:

    <img src="..." onclick="window.location.href = &quot;https://example.com/?user=test&amp;password&amp;te%26st&amp;goto=https%3A%2F%2Fgoogle.com&quot;;">...</a>(Да, ;;это правильно.)

  • JSON как значение:

    <a href="..." data-analytics="{&quot;event&quot;: &quot;click&quot;}">...</a>

  • Экранированные вещи внутри экранированных вещей, двойное кодирование, URL внутри URL внутри параметра и т. Д., ...

    http://x.com/?passwordUrl=http%3A%2F%2Fy.com%2F%3Fuser%3Dtest&amp;password=&quot;&quot;123


3

Да, вы должны преобразовать &в &amp;.

Этот инструмент проверки html от W3C полезен для вопросов, подобных этому. Он расскажет вам об ошибках и предупреждениях для конкретной страницы.


1
Я не уверен, что валидатор W3C обнаруживает это (без экранирования &в href) как ошибку.
ChrisW

6
В настоящее время валидатор W3C принимает неэкранированный и действительный. Означает ли это, что стандарт изменился и кодировка больше не требуется? (делая большинство ответов здесь устаревшими)? Если да, то относится ли это только к href или какому-либо другому атрибуту?
Маттео
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.