Perché escape_javascript prima di eseguire il rendering di un partial?


120

Sto guardando questo episodio di Railscast e mi chiedo perché la chiamata a escape_javascriptè necessaria qui:

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

A cosa escape_javascriptserve?

Secondo i documenti di Rails :

escape_javascript (javascript)

Evita i ritorni degli operatori di escape e le virgolette singole e doppie per i segmenti JavaScript.

Ma questo non significa molto per me.


23
Cordiali saluti, la risposta accettata qui non è la risposta corretta. Kikito è
Steve il

Risposte:


-3

Perché non vuoi che gli utenti pubblichino JavaScript che il browser esegue effettivamente?


4
Ma che ne dici di quando vuoi passare e rendere il codice javascript?
berto77

Sì, in realtà è più un metodo di formattazione. Non impedisce agli utenti di eseguire il proprio javascript. Niente può impedirlo.
LasagnaAndroid

3
Questo non è utile. Vedi invece la risposta di kikito .
nitsas

363

È più facile capire se dividi il codice in due parti.

La prima parte $("#reviews").append("<%= ... %>");è javascript con erb. Ciò significa che <%= ... %>verrà sostituito da qualunque cosa restituisca il codice ruby ​​al suo interno. Il risultato di tale sostituzione deve essere javascript valido, altrimenti genererà un errore quando il client tenta di elaborarlo. Quindi questa è la prima cosa: hai bisogno di JavaScript valido .

Un'altra cosa da tenere in considerazione è che qualsiasi cosa generata da ruby ​​deve essere contenuta all'interno di una stringa javascript con virgolette doppie: notare le virgolette doppie attorno al file <%= ... %>. Ciò significa che il javascript generato sarà simile a questo:

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

Ora esaminiamo la parte rubino all'interno del file <%= ... %>. Cosa fa render(:partial => @review)? Sta eseguendo un rendering parziale, il che significa che potrebbe eseguire il rendering di qualsiasi tipo di codice: html, css ... o anche più javascript!

Allora, cosa succede se il nostro partial contiene un semplice html, come questo?

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

Ricordi che il tuo javascript prendeva come parametro una stringa tra virgolette? Se sostituiamo semplicemente il <%= ... %>con il codice di quel parziale, allora abbiamo un problema - subito dopo href=c'è un doppio apice! Il javascript non sarà valido:

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

Affinché ciò non accada, vuoi sfuggire a questi caratteri speciali in modo che la tua stringa non venga tagliata - hai bisogno di qualcosa che generi questo invece:

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

Questo cosa escape_javascriptfa. Si assicura che la stringa restituita non "interrompa" javascript. Se lo usi, otterrai l'output desiderato:

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

Saluti!


4
anzi, spiegazione molto bella grazie. Immagino che quindi utilizzare "escape_javascript" sia un po 'fuorviante perché in realtà non lo stiamo utilizzando per sfuggire al javascript effettivo. Puoi inserire un tag script nel partial ed eseguire qualsiasi javascript desideri.
Steve il

13
@Steve ha concordato, un nome migliore sarebbe escape_for_javascript, dal momento che spesso si esegue l'escape di altro codice (html per esempio) in modo che non rompa javascript.
kikito

14
escape_javascript()ha ora un metodo più breve: simpley j()(in Rails 4 almeno).
mjnissim

@kikito, usando questo effetto provo a rendere un parziale html che consiste in un modulo remoto? Sto cercando di scoprire perché il rendering di un parziale con javascript che include un altro modulo che verrà inviato tramite javascript fa sì che la seconda richiesta sia html anziché js. Se hai tempo, potresti leggere la domanda che ho già postato in merito? Grazie! La mia domanda
Jake Smith

1
@JakeSmith ha risposto alla tua domanda
kikito

8

gli utenti possono pubblicare codice dannoso (utenti malintenzionati) che, se lasciato senza caratteri di escape, verrà potenzialmente eseguito, consentendo agli utenti di controllare la tua applicazione.

prova questo:

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

non ho molta familiarità con la sintassi di rails, ma se non variableesci verrà visualizzata una finestra di avviso e non penso che sia un comportamento previsto.


8

Se guardi la fonte qui , sarà molto più chiaro.

Questa funzione realizza le seguenti due cose:

  1. Sostituisce i caratteri nella stringa di input con quelli definiti in JS_ESCAPE_MAP

    Lo scopo di ciò è assicurarsi che il codice javascript sia serializzato correttamente senza interferire con la stringa esterna all'interno della quale viene incorporato. Ad esempio, se si dispone di una stringa javascript tra virgolette doppie, tutte le virgolette all'interno dei valori letterali stringa devono essere racchiuse tra virgolette singole per evitare che il codice si interrompa.

  2. La funzione controlla anche se la stringa risultante è sicura in html. Se non lo è, esegue l'escape necessario per assicurarsi che la stringa diventi sicura in html e restituisca il risultato.

Quando si utilizza escape_javascript, di solito viene incorporato in un'altra stringa o in un html esistente in modo dinamico. Devi assicurarti che questa operazione non impedirà il rendering dell'intera pagina.

Alcuni aspetti di questa risposta sono stati evidenziati in altre risposte, ma volevo riunire tutti gli elementi includendo la differenza tra l'escape javascript e l'escape html. Inoltre, alcune risposte alludono al fatto che questa funzione aiuta a evitare l'iniezione di script. Non credo che questo sia lo scopo di questa funzione. Ad esempio, nella tua recensione se la tua recensione ha un avviso ("ciao là"), semplicemente aggiungendolo al nodo non si attiverà il pop-up. Non lo stai incorporando all'interno di una funzione che viene attivata al caricamento della pagina o tramite qualche altro evento. Il solo fatto di avere alert ('ciao là') come parte del tuo html non significa che verrà eseguito come javascript.

Detto questo, non nego che l'iniezione di script non sia possibile. Ma per evitare che sia necessario prendere provvedimenti quando prendi i dati dell'utente e li memorizzi nel tuo database. La funzione e l'esempio che fornisci riguardano il rendering delle informazioni, che erano già state salvate.

Spero che questo aiuti e risponda alla tua domanda.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.