Почему escape_javascript перед рендерингом частичного?

121

Я смотрю этот выпуск Railscast и задаюсь вопросом, зачем escape_javascriptздесь нужен звонок :

$("#reviews").append("<%= escape_javascript(render(:partial => @review)) %>");

Для чего escape_javascriptиспользуется?

Согласно документации Rails :

escape_javascript (JavaScript)

Экранированные возвраты несущей и одиночные и двойные кавычки для сегментов JavaScript.

Но для меня это мало что значит.


источник
23
К вашему сведению, принятый здесь ответ не является правильным. Kikito's
Steve

Ответы:

-3

Потому что вы не хотите, чтобы пользователи размещали JavaScript, который на самом деле выполняет браузер?

Azeem.Butt
источник
4
Но как насчет того, чтобы передать и отобразить код javascript?
berto77
Да, на самом деле это скорее метод форматирования. Это не мешает пользователям запускать собственный javascript. Ничто не может этому помешать.
LasagnaAndroid
3
Это бесполезно. Вместо этого см . Ответ кикито .
nitsas 02
364

Это легче понять, если разделить код на две части.

Первая часть $("#reviews").append("<%= ... %>");- это javascript с erb. Это означает, что <%= ... %>будет заменен тем, что возвращает код рубина внутри него. Результатом этой замены должен быть действующий javascript, иначе он выдаст ошибку, когда клиент попытается обработать его. Итак, первое: вам нужен действующий javascript .

Еще одна вещь, которую следует принять во внимание, заключается в том, что все, что генерирует рубин, должно содержаться внутри строки javascript с двойными кавычками - обратите внимание на двойные кавычки вокруг <%= ... %>. Это означает, что сгенерированный javascript будет выглядеть так:

$("#reviews").append("...");

Теперь рассмотрим рубиновую часть внутри <%= ... %>. Что render(:partial => @review)делать? Это частичный рендеринг, что означает, что он может рендерить любой код - html, css ... или даже больше javascript!

Итак, что произойдет, если наш партиал будет содержать какой-нибудь простой html, как этот?

<a href="/mycontroller/myaction">Action!</a> 

Помните, что ваш javascript использовал строку в двойных кавычках в качестве параметра? Если мы просто заменим на <%= ... %>код этого фрагмента, то у нас возникнет проблема - сразу после href=двойных кавычек! Javascript не будет действительным:

// Without escaping, you get a broken javascript string at href
$("#reviews").append("<a href="/mycontroller/myaction">Action!</a>");

Чтобы этого не произошло, вы хотите экранировать эти специальные символы, чтобы ваша строка не обрезалась - вам нужно что-то, что генерирует это вместо этого:

<a href=\"/mycontroller/myaction\">Action!</a>

Это то, что escape_javascriptделает. Это гарантирует, что возвращенная строка не «сломает» javascript. Если вы его используете, вы получите желаемый результат:

$("#reviews").append("<a href=\"/mycontroller/myaction\">Action!</a>")

С уважением!

kikito
источник
4
действительно, очень хорошее объяснение, спасибо. Полагаю, тогда использование escape_javascript вводит в заблуждение, потому что мы на самом деле не используем его для выхода из реального javascript. Вы можете поместить тег скрипта в партиал и выполнить любой JavaScript, какой захотите.
Стив
13
@Steve согласился, лучше было бы имя escape_for_javascript, так как часто вы избегаете другого кода (например, html), чтобы он не нарушал работу javascript.
kikito 04
14
escape_javascript()теперь есть более короткий метод: simpley j()(по крайней мере, в Rails 4).
mjnissim
@kikito, я с помощью этого эффекта пытаюсь отрендерить партиал html, состоящий из удаленной формы? Я пытаюсь выяснить, почему при рендеринге партиала с помощью javascript, который включает другую форму, которая будет отправлена ​​через javascript, второй запрос будет html вместо js. Если у вас есть время, не могли бы вы взглянуть на вопрос, который я уже писал по этому поводу? Спасибо! Мой вопрос
Джейк Смит
1
@JakeSmith ответил на ваш вопрос
kikito
8

пользователи могут публиковать вредоносный код (злонамеренные пользователи), который, если его не экранировать, потенциально может быть выполнен, позволяя пользователям управлять вашим приложением.

попробуй это:

<% variable = '"); alert("hi there' %>
$("#reviews").append("<%= variable %>");

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

barkmadley
источник
8

Если вы посмотрите здесь источник , он станет намного понятнее.

Эта функция выполняет следующие две задачи:

  1. Он заменяет символы во входной строке на символы, определенные в JS_ESCAPE_MAP

    Цель этого - убедиться, что код javascript правильно сериализован, не мешая внешней строке, в которую он встраивается. Например, если у вас есть строка javascript в двойных кавычках, тогда все кавычки внутри строковых литералов должны быть в одинарных кавычках, чтобы избежать нарушения кода.

  2. Функция также проверяет, безопасна ли полученная строка для HTML. Если это не так, он выполняет необходимое экранирование, чтобы убедиться, что строка становится безопасной для HTML, и возвращает результат.

Когда вы используете escape_javascript, он обычно динамически встраивается в другую строку или существующий html. Вы должны убедиться, что это не приведет к тому, что ваша страница не отобразится полностью.

Некоторые аспекты этого ответа были указаны в других ответах, но я хотел собрать все элементы вместе, включая разницу между экранированием javascript и экранированием html. Кроме того, в некоторых ответах упоминается, что эта функция помогает избежать внедрения сценария. Я не думаю, что это цель этой функции. Например, если в вашем обзоре есть предупреждение («привет!»), Простое добавление его к узлу не вызовет всплывающее окно. Вы не встраиваете его в функцию, которая запускается при загрузке страницы или каким-либо другим событием. Простое наличие предупреждения («привет») как части вашего html не означает, что он будет выполняться как javascript.

Тем не менее, я не отрицаю, что внедрение сценария невозможно. Но чтобы избежать этого, вам нужно предпринять шаги, когда вы берете данные пользователя и сохраняете их в своей базе данных. Функция и пример, которые вы предоставляете, связаны с отображением информации, которая уже была сохранена.

Надеюсь, это поможет и ответит на ваш вопрос.

Tabrez
источник