web-dev-qa-db-fra.com

Pourquoi escape_javascript avant de rendre un partiel?

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

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

Quel est escape_javascript utilisé pour?

Selon the Rails docs :

escape_javascript (javascript)

Retourne transporteur et guillemets simples et doubles pour les segments JavaScript.

Mais cela ne signifie pas grand chose pour moi.

119
Lee Tang

Il est plus facile de 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 renverra. Le résultat de ce remplacement doit être un code JavaScript valide. Sinon, une erreur sera générée lorsque le Le client essaie de le traiter. C'est donc la première chose à faire: il vous faut javascript valide.

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

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

Examinons maintenant la partie Ruby à l'intérieur du <%= ... %>. Qu'est-ce que render(:partial => @review) fait?)? Il rend un partiel - ce qui signifie qu'il pourrait rendre n'importe quel type de code - html, css ... ou même plus javascript!

Alors, que se passe-t-il si notre partial contient du code HTML simple, comme celui-ci?

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

Rappelez-vous que votre javascript prenait une chaîne entre guillemets doubles 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 double guillemet! 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_javascript Fait. Il s'assure que la chaîne retournée ne "brisera" pas le javascript. Si vous l'utilisez, vous obtiendrez le résultat souhaité:

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

Cordialement!

357
kikito

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 cette opération est de s’assurer que le code javascript est sérialisé correctement sans interférer avec la chaîne externe dans laquelle il est incorporé. Par exemple, si vous avez une chaîne javascript entre guillemets, toutes les citations contenues dans les littéraux de chaîne doivent être entre guillemets simples pour éviter la rupture du code.

  2. La fonction vérifie également si la chaîne résultante est sécurisée pour le langage 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é de manière dynamique dans une autre chaîne ou dans du code HTML existant. Vous devez vous assurer que cela ne créera pas le rendu de votre page entière.

Certains aspects de cette réponse ont été soulignés dans d'autres réponses mais je voulais rassembler tous les éléments, notamment 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 commentaire, si votre avis est alerté ("Salut là-bas"), son ajout au nœud ne déclenche pas la fenêtre contextuelle. Vous ne l'intégrez pas dans une fonction déclenchée au chargement de la page ou par un autre événement. Le simple fait d’avoir alerté ('hi there') dans 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 déjà enregistrées.

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

8
Tabrez

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

essaye ça:

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

pas vraiment familier avec la syntaxe de Rails, mais si vous n'échappez pas variable, un message d'alerte s'affichera, et je ne pense pas que ce soit le comportement voulu.

8
barkmadley