Pourquoi escape_javascript avant de rendre un partiel?

120

Je regarde cet épisode de Railscast et je me demande pourquoi l'appel à escape_javascriptest nécessaire ici:

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

À quoi escape_javascriptsert-il?

Selon la documentation Rails :

escape_javascript (javascript)

Escape carrier renvoie et guillemets simples et doubles pour les segments JavaScript.

Mais cela ne veut pas dire grand-chose pour moi.


la source
23
Pour info, la réponse acceptée ici n'est pas la bonne réponse. Kikito's is
Steve

Réponses:

-3

Parce que vous ne voulez pas que les utilisateurs publient du JavaScript que le navigateur exécute réellement?

Azeem.Butt
la source
4
Mais qu'en est-il lorsque vous souhaitez transmettre et rendre du code javascript?
berto77
Ouais, en fait c'est plus une méthode de formatage. Cela n'empêche pas les utilisateurs d'exécuter leur propre javascript. Rien ne peut empêcher cela.
LasagnaAndroid
3
Ce n'est pas utile. Consultez plutôt la réponse de kikito .
nitsas
363

C'est plus facile à comprendre si vous divisez le code en deux parties.

La première partie $("#reviews").append("<%= ... %>");est javascript avec erb. Cela signifie que le <%= ... %>sera remplacé par tout ce que le code ruby ​​à l'intérieur de celui-ci renvoie. Le résultat de ce remplacement doit être un javascript valide, sinon il générera une erreur lorsque le client essaiera de le traiter. C'est donc la première chose: vous avez besoin d' un javascript valide .

Une autre chose à prendre en compte est que tout ce que ruby ​​génère doit être contenu dans une chaîne javascript avec des guillemets - notez les guillemets autour du <%= ... %>. Cela signifie que le javascript généré ressemblera à ceci:

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

Examinons maintenant la partie rubis à l'intérieur du fichier <%= ... %>. Que fait render(:partial => @review)-on? C'est un rendu partiel - ce qui signifie qu'il pourrait être rendu n'importe quel type de code - html, css ... ou même plus javascript!

Alors, que se passe-t-il si notre partiel contient du html simple, comme celui-ci?

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

Rappelez-vous que votre javascript prenait une chaîne entre guillemets comme paramètre? Si nous remplaçons simplement le <%= ... %>par le code de ce partiel, nous avons un problème - immédiatement après le, href=il y a un guillemet double! Le javascript ne sera pas valide:

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

Pour que cela ne se produise pas, vous voulez échapper ces caractères spéciaux afin que votre chaîne ne soit pas coupée - vous avez besoin de quelque chose qui génère ceci à la place:

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

C'est ce que escape_javascriptfait. Il s'assure que la chaîne retournée ne "cassera" pas le javascript. Si vous l'utilisez, vous obtiendrez la sortie souhaitée:

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

Cordialement!

kikito
la source
4
en effet, très belle explication merci. Je suppose qu'alors, utiliser «escape_javascript» est un peu trompeur car nous ne l'utilisons pas réellement pour échapper au javascript réel. Vous pouvez mettre une balise de script dans le partiel et exécuter le javascript de votre choix.
Steve le
13
@Steve était d'accord, un meilleur nom serait escape_for_javascript, car souvent vous échappez à un autre code (html par exemple) pour qu'il ne casse pas le javascript.
kikito le
14
escape_javascript()a maintenant une méthode plus courte: simpley j()(dans Rails 4 au moins).
mjnissim
@kikito, est-ce que l'utilisation de cet effet me permet de rendre un partiel html constitué d'un formulaire distant? J'essaie de savoir pourquoi le rendu d'un partiel avec javascript qui inclut un autre formulaire qui sera soumis via javascript fait que la deuxième demande est html au lieu de js. Si vous avez le temps, pourriez-vous consulter la question que j'ai déjà posée à ce sujet? Merci! Ma question
Jake Smith
1
@JakeSmith a répondu à votre question
kikito
8

les utilisateurs peuvent publier un code malveillant (utilisateurs malveillants) qui, s'il n'est pas échappé, sera potentiellement exécuté, permettant aux utilisateurs de contrôler votre application.

essaye ça:

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

pas vraiment familier avec la syntaxe des rails, mais si vous ne vous échappez pas, variableune boîte d'alerte apparaîtra, et je ne pense pas que ce soit le comportement prévu.

barkmadley
la source
8

Si vous regardez la source ici , ce sera beaucoup plus clair.

Cette fonction accomplit les deux choses suivantes:

  1. Il remplace les caractères de la chaîne d'entrée par ceux définis dans JS_ESCAPE_MAP

    Le but de ceci est de s'assurer que le code javascript est correctement sérialisé sans interférer avec la chaîne externe dans laquelle il est incorporé. Par exemple, si vous avez une chaîne javascript entre guillemets, tous les guillemets à l'intérieur des chaînes littérales doivent être entre guillemets simples pour éviter que le code ne se brise.

  2. La fonction vérifie également si la chaîne résultante est sécurisée pour le HTML. Si ce n'est pas le cas, il effectue l'échappement nécessaire pour s'assurer que la chaîne devient sécurisée pour le HTML et renvoie le résultat.

Lorsque vous utilisez escape_javascript, il est généralement intégré dans une autre chaîne ou dans un code HTML existant de manière dynamique. Vous devez vous assurer que cela ne rendra pas votre page entière non rendue.

Certains aspects de cette réponse ont été soulignés dans d'autres réponses, mais je voulais rassembler tous les éléments, y compris la différence entre l'échappement javascript et l'échappement html. De plus, certaines réponses indiquent que cette fonction permet d'éviter l'injection de script. Je ne pense pas que ce soit le but de cette fonction. Par exemple, dans votre avis, si votre avis a une alerte ("salut,"), le simple fait de l'ajouter au nœud ne déclenchera pas la fenêtre contextuelle. Vous ne l'incorporez pas dans une fonction déclenchée lors du chargement de la page ou via un autre événement. Le simple fait d'avoir une alerte («bonjour») dans le cadre de votre code HTML ne signifie pas qu'il s'exécutera en javascript.

Cela dit, je ne nie pas que l'injection de script n'est pas possible. Mais pour éviter cela, vous devez prendre des mesures lorsque vous prenez les données utilisateur et les stockez dans votre base de données. La fonction et l'exemple que vous fournissez sont liés au rendu des informations, qui ont déjà été enregistrées.

J'espère que cela aide et répond à votre question.

Tabrez
la source