Por que escape_javascript antes de renderizar um parcial?

120

Estou vendo este episódio do Railscast e me perguntando por que a chamada para escape_javascripté necessária aqui:

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

Para que é escape_javascriptutilizado?

De acordo com a documentação do Rails :

escape_javascript (javascript)

Retorna a operadora de escape e aspas simples e duplas para segmentos JavaScript.

Mas isso não significa muito para mim.


fonte
23
Para sua informação, a resposta aceita aqui não é a resposta correta. Kikito de é
Steve

Respostas:

-3

Como você não deseja que os usuários postem JavaScript que o navegador realmente executa?

Azeem.Butt
fonte
4
Mas e quando você deseja passar e renderizar o código javascript?
berto77
Sim, na verdade é mais um método de formatação. Isso não impede que os usuários executem seu próprio javascript. Nada pode impedir isso.
LasagnaAndroid 23/02
3
Isso não ajuda. Veja a resposta do kikito .
nitsas
363

É mais fácil entender se você dividir o código em duas partes.

A primeira parte $("#reviews").append("<%= ... %>");é javascript com erb. Isso significa que o <%= ... %>será substituído por qualquer que seja o código rubi dentro dele. O resultado dessa substituição deve ser um javascript válido, caso contrário, ocorrerá um erro quando o cliente tentar processá-lo. Então essa é a primeira coisa: você precisa de um javascript válido .

Outra coisa a considerar é que tudo o que o ruby ​​gera deve estar contido em uma string javascript com aspas duplas - observe as aspas duplas ao redor do <%= ... %>. Isso significa que o javascript gerado terá a seguinte aparência:

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

Agora vamos examinar a parte do ruby ​​dentro do <%= ... %>. O querender(:partial => @review) faz? Está renderizando um parcial - o que significa que poderia renderizar qualquer tipo de código - html, css ... ou ainda mais javascript!

Então, o que acontece se o nosso parcial contiver algum html simples, como este?

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

Lembre-se de que seu javascript estava usando uma string de aspas duplas como parâmetro? Se simplesmente substituirmos o <%= ... %>código pelo parcial, teremos um problema - imediatamente após a href=aspas duplas! O javascript não será válido:

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

Para que isso não aconteça, você deseja escapar desses caracteres especiais para que sua string não seja cortada - você precisa de algo que gere isso:

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

É isso que escape_javascriptfaz. Ele garante que a string retornada não "quebre" o javascript. Se você usá-lo, obterá a saída desejada:

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

Saudações!

kikito
fonte
4
de fato, uma explicação muito boa, obrigado. Acho que usar 'escape_javascript' é meio enganoso, porque na verdade não o estamos usando para escapar do javascript real. Você pode colocar uma tag de script no parcial e executar qualquer javascript que desejar.
Steve
13
@ Steve concordou, um nome melhor seria escape_for_javascript, já que muitas vezes você está escapando de outro código (html por exemplo) para que ele não quebre o javascript.
Kikito
14
escape_javascript()agora tem um método mais curto: simpley j()(pelo menos no Rails 4).
Mjnissim
@kikito, usando esse efeito me tentando processar um html parcial que consiste em um formulário remoto? Estou tentando descobrir por que renderizar parcial com javascript que inclui outro formulário que será enviado via javascript faz com que a segunda solicitação seja html em vez de js. Se você tiver tempo, poderia examinar a pergunta que eu já postei sobre isso? Obrigado! Minha pergunta
Jake Smith
1
@JakeSmith respondeu na sua pergunta
kikito
8

os usuários podem publicar códigos maliciosos (usuários mal-intencionados) que, se deixados sem escape, serão executados potencialmente, permitindo que os usuários controlem seu aplicativo.

tente isto:

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

Não estou realmente familiarizado com a sintaxe dos trilhos, mas se você não escapar variable, uma caixa de alerta será exibida, e não acho que esse seja o comportamento pretendido.

Barkmadley
fonte
8

Se você olhar a fonte aqui , será muito mais claro.

Essa função realiza as duas coisas a seguir:

  1. Ele substitui os caracteres na sequência de entrada pelos definidos em JS_ESCAPE_MAP

    O objetivo disso é garantir que o código javascript seja serializado corretamente, sem interferir na cadeia externa na qual está sendo incorporado. Por exemplo, se você tiver uma string javascript entre aspas duplas, todas as aspas para literais de string deverão estar entre aspas simples para evitar a quebra do código.

  2. A função também verifica se a sequência resultante é segura para html. Caso contrário, ele faz o escape necessário para garantir que a string se torne segura em html e retorne o resultado.

Quando você está usando escape_javascript, ele geralmente está sendo incorporado dentro de outra string ou html existente dinamicamente. Você precisa garantir que isso não faça com que sua página inteira não seja renderizada.

Alguns aspectos dessa resposta foram apontados em outras respostas, mas eu queria reunir todos os itens, incluindo a diferença entre escape de javascript e escape de html. Além disso, algumas respostas aludem que essa função ajuda a evitar a injeção de scripts. Não acho que esse seja o objetivo dessa função. Por exemplo, em sua revisão, se ela tiver um alerta ('oi'), apenas anexá-lo ao nó não acionará o pop-up. Você não está incorporando-o a uma função que é acionada no carregamento da página ou através de algum outro evento. Apenas ter o alerta ('oi lá') como parte do seu html não significa que ele será executado como javascript.

Dito isto, não estou negando que a injeção de script não seja possível. Mas, para evitar isso, é necessário tomar medidas ao coletar os dados do usuário e armazená-los em seu banco de dados. A função e o exemplo que você está fornecendo estão relacionados à renderização das informações, que já foram salvas.

Espero que isso ajude e responda à sua pergunta.

Tabrez
fonte