30 votes

La création de Javascript / jQuery DOM est-elle sécurisée tant qu'elle n'a pas été ajoutée au document?

Veuillez lire attentivement cet avis: supposons avant TOUT des éléments sont ajoutés à l' document tous les éléments non sécuritaires dans $dom ont été supprimés. Mais ils ont été initialement créé. Ok, nous allons continuer....


Si un morceau de texte utilisateur est traitée et peut possiblité être chargé comme suit:

var comment = 'I\'m a naughty person!!' +
              '<script src="http://blah.com/some_naughty_javascript.js">';
var $dom = $('<div>' + comment + '</div>');

Est-ce par lui-même dangereux en aucune façon? Mon point étant, peut juste le simple fait de la création d'un DOM en quelque sorte injecter quoi que ce soit, ou est-il tout simplement traitée, et la structure est créée?

Par exemple:

var $dom = $('<script>alert("hi");</script>');

Évidemment, le message de salut ne fait pas apparaître jusqu'à ce qu'il est ajouté à l' document. Mais:

  • Peut-tag ou rien créé de cette manière-il être dangereux?
  • Toute les fonctions en javascript/jquery "regardez" pour les éléments créés de cette manière et d'agir AVANT qu'il a été dépouillé de mauvais éléments et les mettre sur le document?

Bounty Modifier

Donc, comme indiqué dans les réponses ci-dessous, il semble que cette méthode n'est pas très sûr, surtout pour une raison:

  • var $dom = $('<img src="blah.jpg"/>') -- cela demande de l'image tout de suite, peu importe si l'objet a été ajouté au document.

Cela crée un problème majeur pour traiter HTML requêtes ajax. Par exemple, si nous voulions obtenir les valeurs des entrées de la forme:

$.ajax({
  url: 'test.php',
  success: function(responseHTML) {
    var inputs = $(responseHTML).find('form input');
  }
});

Ce sera involontairement la cause de toutes les images pour être demandées par le navigateur.

Bounty est attribué à toute personne:

  • Qui peut fournir une belle, sûre façon de traiter avec des requêtes ajax sans le problème ci-dessus.
  • Idéalement ne pas fournir une regex de réponse... c'est à dire que si nous ne voulions $(responseHTML).find('img') -- suppression de balises d'image avec la regex ne peut pas être une option, donc, d'une manière discrète seraient nécessaires pour arrêter la src à partir de chargement, mais toujours les mêmes caractéristiques, de la structure, etc.

12voto

Mark Coleman Points 24469

Est-ce par lui-même dangereux à n'importe quel de la sorte? Mon point étant, peut juste l' simple fait de la création d'un DOM en quelque sorte injecter quoi que ce soit, ou est-il tout simplement de traitement et de la structure créé?

Il suffit de créer un élément sans l'ajoutant à la dom ne cause aucun script à exécuter, car il est purement un objet à ce point (HtmlScriptElement). Lorsqu'il est ajouté au dom de l'élément script sera évaluée et exécuté par le navigateur. Cela étant dit, je suppose qu' il est possible qu'une très astucieux personne pourrait exploiter un bug qui est présent dans un certain cadre ou le navigateur que vous utilisez peut-être à cause d'un résultat indésirable.

Considérons cet exemple:

<p>
    <input type="button" value="Store 'The Script' In Variable" id="store"/>
    <input type="button" value="Append 'The Script' To Dom" id="append"/>
</p>
<br/>
<p>
    <input type="button" value="Does nothing"/>
</p>
<h1>The Script</h1>
<pre id="script">
    $(function(){
        function clickIt(){
            $(this).clone().click(clickIt).appendTo("body");
        }
        $("input[type='button']").val("Now Does Something").click(clickIt);
    });
</pre>

var theScript;

$("#store").click(function() {
    theScript = document.createElement('script');
    var scriptText = document.createTextNode($("#script").text());
    theScript.appendChild(scriptText);
});

$("#append").click(function() {
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(theScript);
});

Lorsque vous cliquez sur l' store il va créer la HtmlScriptElement et la stocker dans une variable. Vous remarquerez que rien n'est couru, même si l'objet est créé. Dès que vous cliquez sur append le script est ajouté au dom et immédiatement évaluée et les boutons de faire quelque chose de différent.

Exemple de Code sur jsfiddle


Toute les fonctions en javascript/jquery "regardez" pour les éléments être créé de cette manière et de la loi sur les AVANT il a été dépouillé de mauvais les éléments et les mettre sur le document?

jQuery sorte de ne que pour vous, déjà qu'il fait un peu de script interne eval


De Karl Swedberg post sur .append()

Tous jQuery méthodes d'insertion d'utilisation un domManip fonction en interne pour nettoyer/processus d'éléments avant et après ils sont insérés dans le DOM. L'une des choses les domManip la fonction n'est de sortir un script éléments pour être inséré et exécuter grâce à un "evalScript routine" plutôt que de les injecter avec le reste le DOM fragment. Il insère l' les scripts séparément, les évalue,les et puis les supprime de la DOM. ...

Vous pourrait modifier le comportement de jQuery pour supprimer tous <script/> et désinfecter les autres éléments avec le javascript en ligne onclick, mouseover, etc lors de l'appel d' append() cependant que affectera uniquement jQuery que quelqu'un pourrait facilement utiliser la vanille javascript pour ajouter l' <script/> élément.

Dom Mutation Événements

Dom Niveau 2 n'a défini certains Dom mutation événements à capturer les éléments qui sont ajoutés à la dom ne regarde vue de l'événement, DOMNodeInserted. Toutefois, il est congédié après que l'élément a déjà été ajouté. remarque, par Raynos ceux-ci sont actuellement obsolète.

DOMNodeInserted Déclenché quand un nœud a été ajouté comme un enfant d'un autre nœud. Cet événement est distribué après la l'insertion a eu lieu. La cible de cet événement est le nœud en cours de inséré. Bulles: Oui Résiliables: Aucun Contexte Info: relatedNode détient le nœud parent

En fin de compte, il semble qu'il y est pas totalement arrêter un <script/> être ajouté au dom par le biais de certains autres javascript. (au moins, pas ce que je peux trouver).

La meilleure façon que je peux suggérer, c'est de ne jamais jamais faire confiance à l'utilisateur tous les utilisateurs d'entrée est le mal. Lorsque vous faites la manipulation dom double assurez-vous il n'y a pas interdit les balises, que ce soit <script/> ou même du simple <p/> - éléments et désinfecter tous les commentaires avant qu'il est persistant.

Aussi, comme John points, vous avez besoin de s'inquiéter à propos de tout élément qui peut s'attacher à un onclick événement ou tout gestionnaire d'événement javascript en ligne.

7voto

Sidnicious Points 15187

Une obligation de réponse à votre premier exemple

var comment = 'I\'m a naughty person!!' +
              '<script src="http://blah.com/some_naughty_javascript.js">';
var $dom = $('<div>' + comment + '</div>');

Ne pas le faire. Au lieu de cela, vous devez utiliser une API qui traite le texte comme texte et de ne pas vous exposer à une injection à tous. Dans cet exemple, vous devriez faire ceci:

var $dom = $('<div>').text(comment);

...ce qui crée un div, puis définit son contenu textuel. comment n'est jamais analysée comme HTML, de sorte qu'il n'y a aucune chance que le navigateur ne pourra jamais faire quelque chose de dangereux avec elle.

Passer à la question

Si je vous comprends bien, vous souhaitez analyser des informations de code HTML arbitraire, sans que le navigateur se préparer pour l'afficher (par exemple, par le chargement des images).

C'est délicat, parce que les Dom intégré dans les navigateurs web sont construites de traiter avec le contenu qui sera, à un certain point, être affichée. jQuery (et de toute bibliothèque qui crée des nœuds DOM) est limitée par la ce.

DOM Niveau 2 définit une API pour créer des documents qui sont complètement distincts de ceux de l'active: document.implementation.createHTMLDocument(. Dans mes tests, rien n'est chargé lorsque l' title est créé sur l'un de ces documents:

)

Ainsi, un document créé cette voie semble être un joli bac à sable pour analyser et d'explorer HTML. Vous pouvez même créer un jQuery wrapper autour des nœuds dans un autre document (img), et de l'explorer à travers jQuery Api. Lorsque vous trouvez les nœuds que vous cherchez, vous pouvez les convertir en arrière au format HTML pour l'insérer dans le document actif, ou d'utiliser des méthodes comme var doc = document.implementation.createHTMLDocument(''), img = doc.createElement('img'); img.src = 'http://example.com/image.jpg'; // Nothing happens. // Alternatively… doc.body.innerHTML = '<img src="http://example.com/image.jpg">'; // Nope. et $(doc.body) de les transférer directement dans le document actif.

Malheureusement, l'appui pour tout ce qui est nouveau. Firefox supporte importNode() dans la version 4 (similaire adoptNode() méthode, qui traite avec XML, est disponible dans les versions plus anciennes), et Internet Explorer prend en charge dans la version 9 et jusqu'. Aussi, autant que je puisse en dire, la spec ne garantit pas que les images et les scripts ne pas être préchargé sur ces documents.

Une meilleure solution est d'éviter le navigateur de l'analyseur HTML. Un certain nombre de HTML en JavaScript les analyseurs ont montré dernièrement. Le plus simple est probablement de John Resig du Pur JavaScript HTML Parser. Vous pouvez nourrir HTML, et il déclenche des rappels quand il frappe de nouveau les balises, les attributs, et le texte. À partir de ces rappels, vous pouvez créer de nouveaux HTML, construire les nœuds DOM ou enregistrer le document dans n'importe quelle forme que vous voulez, et vous pouvez ignorer les attributs et les nœuds que vous considérez comme dangereux.

Vous pouvez trouver un exemple de cela dans Dan Kaminsky est Interpolique, une preuve de concept qui vise à tuer XSS et de l'injection SQL une fois pour toutes. Le projet n'a pas décollé, mais si vous téléchargez Interpolique, vous trouverez un createHTMLDocument fonction coincés au fond de htmlparser.js qui utilise une liste de noms de balises et d'attributs, et jette tout le reste.

jsdom est complète (jusqu'à DOM Niveau 2, avec un certain Niveau 3) DOM HTML écrit en JavaScript, vous pouvez l'utiliser pour travailler avec le format HTML en toute sécurité. Vous pouvez même charger jusqu'à sa propre copie de jQuery. Cependant, il est écrit pour les CommonJS, sans la compatibilité du navigateur dans l'esprit. Je ne sais pas si cela fonctionnera dans la plupart des navigateurs web sans modification. C'est aussi une grande bibliothèque.

Si possible, la solution idéale est de servir les réponses AJAX dans un format autre que le format HTML. Avez-vous besoin d'inclure les, dangereux HTML à tous? Si vous effectuez le travail sur le serveur de retour uniquement ce dont vous aurez besoin...

createDocument

...votre travail sur le côté client devient beaucoup plus facile.

2voto

Rory McCrossan Points 69838

Excellente question. Il apparaît, il est possible d'injecter du script et de la place de gestionnaires d'événements à l'intérieur. Je l'ai testé en utilisant le code HTML suivant:

<!DOCTYPE html>
<html lang="en">
    <head>  
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
        <script type="text/javascript"> 
            <!-- 
            $(function() {
                var $dom = $('<script>$(".testbutton").live("click", function() { alert("hi") });</script>');

                $(".firstbutton").click(function() {
                    $("BODY").append($dom);
                });
            });
            -->
        </script>
    </head>

    <body style="padding:0">            
        <button class="firstbutton">Click this first</button>

        <button class="testbutton">Then this</button>
    </body>
</html>

Vous pouvez voir que le deuxième bouton n'a aucun effet jusqu'à ce que le premier bouton a été cliqué et la balise de script est ajouté au DOM.

Cela pourrait être ouverte à des abus si l'utilisateur le formulaire de saisie est prise et dynamique, inséré dans la page. Auquel cas les données epuration devrait certainement être utilisé.

C'est quelque chose que je n'avais jamais pensé merci pour le soulever.

0voto

Santosh Linkha Points 7849

Il semble que le script ne fonctionnera pas tant qu'il ne sera pas ajouté à DOM.

 $(function ()
{
    var ss = document.createElement('script');
    var scr = 'alert("bah");';
    var tt = document.createTextNode(scr);
    ss.appendChild(tt);
    var hh = document.getElementsByTagName('head')[0];
    //hh.appendChild(ss);
});
 

Et

 $(function ()
{
    var ss = document.createElement('script');
    var scr = 'alert("bah");';
    var tt = document.createTextNode(scr);
    ss.appendChild(tt);
    var hh = document.getElementsByTagName('head')[0];
    hh.appendChild(ss);
});
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X