Какой EncodeFor для данных - атрибуты с URL
Я пытаюсь вставить URL в data-
приписывать. Особенно
<tr data-href="/page.cfm?Id=#EncodeForHTMLAttribute(ID)#">
...
ИЛИ возможно это должно быть
<tr data-href="/page.cfm?Id=#EncodeForURL(ID)#">
...
Обратите внимание, что идентификатор может содержать специальные символы
Редактировать:
Много позже я собираюсь
$("tr").click(function() { window.location = $(this).data("href"); });
1 ответ
Давайте проанализируем некоторые сценарии:
Вообще не кодирует
<!--- our "tricky" ID --->
<cfset ID = '"><script>alert("my evil script");</script><div foo="'>
<!--- we are closing the data-href attribute, injecting our JS and start a new tag to complete the remaining tag --->
<cfoutput>
<div data-href="page.cfm?Id=#ID#"></div>
<!--- [data-href] is printed as: page.cfm?Id="><script>alert("my evil script");</script><div foo=" --->
</cfoutput>
Результат
Появляется диалоговое окно с предупреждением "Мой злой сценарий".
Заключение
Никогда не оставляйте пользовательский ввод незашифрованным! (Вы уже знали это.)
Кодирование строки запроса для вывода в виде HTML
Примечание. Вы всегда должны кодировать полное значение атрибута HTML, а не только его части.
<!--- our "tricky" ID --->
<cfset ID = "&a=b?c">
<!--- we are having some reserved characters here that will confuse the browser's query string parser --->
<cfoutput>
<div data-href="#encodeForHtmlAttribute("page.cfm?Id=#ID#")#"></div>
<!--- [data-href] is printed as: page.cfm?Id=&a=b?c --->
<script>
var attr = document.getElementsByTagName('div')[0].getAttribute('data-href');
console.log(attr); <!--- page.cfm?Id=&a=b?c --->
<cfif structIsEmpty(URL)> <!--- test related: to prevent infinite redirection --->
location.href = attr;
</cfif>
</script>
</cfoutput>
<cfdump var="#URL#">
Результат
При запросе page.cfm
мы будем перенаправлены на page.cfm?Id=&a=b?c
, простая стоимость data-href
приписывать. Тем не менее, объем дампа URL
представит нам пары ключ-значение:
Id: [empty string]
a: b?c
Что и следовало ожидать, потому что парсер строки запроса браузера не мог различить буквальное значение и техническое назначение символов. Я недавно ответил на это здесь.
Заключение
Кодирование выходных данных недостаточно при наличии нескольких контекстов (здесь: HTML & URL/QueryString).
Кодирование строки запроса в виде URL
<!--- our "tricky" ID --->
<cfset ID = 'a&b="><script>alert("my evil script");</script><div foo="'>
<!--- we are mixing in both contexts now --->
<cfoutput>
<div data-href="page.cfm?Id=#encodeForUrl(ID)#"></div>
<!--- [data-href] is printed as: page.cfm?Id=a%26b%3D%22%3E%3Cscript%3Ealert%28%22my+evil+script%22%29%3B%3C%2Fscript%3E%3Cdiv+foo%3D%22 --->
<script>
var attr = document.getElementsByTagName('div')[0].getAttribute('data-href');
console.log(attr); <!--- page.cfm?Id=a%26b%3D%22%3E%3Cscript%3Ealert%28%22my+evil+script%22%29%3B%3C%2Fscript%3E%3Cdiv+foo%3D%22 --->
<cfif structIsEmpty(URL)> <!--- test related: to prevent infinite redirection --->
location.href = attr;
</cfif>
</script>
</cfoutput>
<cfdump var="#URL#">
Результат
При запросе page.cfm
мы будем перенаправлены на page.cfm?Id=a%26b%3D%22%3E%3Cscript%3Ealert%28%22my+evil+script%22%29%3B%3C%2Fscript%3E%3Cdiv+foo%3D%22
, простая стоимость data-href
приписывать. Объем свалки URL
представит нам пару ключ-значение:
Id: a&b="><script>alert("my evil script");</script><div foo="
На этот раз парсер строки запроса браузера мог различать буквальное значение и техническое назначение символов. Но как насчет HTML-контекста здесь? Ну, процентное кодирование сделано encodeForUrl()
не конфликтует с зарезервированными символами HTML, потому что %
не имеет технического назначения в HTML и ничего не нарушает.
Заключение
Теоретически мы сделали здесь. Нет необходимости HTML-кодировать значение в кодировке URL, поскольку нет перекрытия двух кодировок.
Кодирование строки запроса в виде URL - И - для вывода в виде HTML
<!--- our "tricky" ID --->
<cfset ID = 'a&b="><script>alert("my evil script");</script><div foo="'>
<!--- we are mixing in both contexts again --->
<cfoutput>
<div data-href="#encodeForHtmlAttribute("page.cfm?Id=#encodeForUrl(ID)#")#"></div>
<!--- [data-href] is printed as: page.cfm?Id=a%26b%3D%22%3E%3Cscript%3Ealert%28%22my+evil+script%22%29%3B%3C%2Fscript%3E%3Cdiv+foo%3D%22 --->
<script>
var attr = document.getElementsByTagName('div')[0].getAttribute('data-href');
console.log(attr); <!--- page.cfm?Id=a%26b%3D%22%3E%3Cscript%3Ealert%28%22my+evil+script%22%29%3B%3C%2Fscript%3E%3Cdiv+foo%3D%22 --->
<cfif structIsEmpty(URL)> <!--- test related: to prevent infinite redirection --->
location.href = attr;
</cfif>
</script>
</cfoutput>
<cfdump var="#URL#">
Результат
При запросе page.cfm
мы будем перенаправлены на page.cfm?Id=a%26b%3D%22%3E%3Cscript%3Ealert%28%22my+evil+script%22%29%3B%3C%2Fscript%3E%3Cdiv+foo%3D%22
, простая стоимость data-href
приписывать. Объем свалки URL
представит нам пару ключ-значение:
Id: a&b="><script>alert("my evil script");</script><div foo="
Кажется, ничего не изменилось, верно? Не совсем. Это то, что наш data-href
теперь выглядит как в окончательном выводе HTML:page.cfm?Id=a%26b%3D%22%3E%3Cscript%3Ealert%28%22my+evil+script%22%29%3B%3C%2Fscript%3E%3Cdiv+foo%3D%22
Как видите, кодирование процентов теперь дополнительно кодируется для HTML (%
был закодирован в его шестнадцатеричном представлении %
).
Заключение
Значение теперь безопасно для обоих контекстов.
Есть больше кодировок, которые могут смешаться (подумайте о encodeForJavaScript()
), Но ты получил идею. Это всегда о том, какие символы в значении требуют, чтобы кодировка была неверно истолкована для их технического назначения. Это может привести к тому, что будет иметь от 3 до 4 вложенных кодировок. Но опять же: обычно эти кодировки не конфликтуют друг с другом, поэтому не обязательно кодировать их для всех контекстов.