4

Say I get a response to a request for an AJAX load of data with a mix of JavaScript and HTML, e.g.:

<script>window.alert('Hello World!');</script>
<p>This is a paragraph. Lorem ipsum dolor sit amet...</p>

If I just place that response into a div or other container, the script doesn't get executed automatically. I know this can be done via the eval() function (as noted in the example below), but eval is evil, so how can I do this properly? Note: I am not using jQuery.

The following is an example of the AJAX loader:

function Load(id,url){
    var ajax=new XMLHttpRequest();
    ajax.onreadystatechange=function(){
        if(ajax.readyState!=4)return;
        var obj=document.getElementById(id);
        if(!obj)return;
        obj.innerHTML=ajax.responseText;

        // load any scripts
        var s=obj.getElementsByTagName('script');
        for(var i=0;i<s.length;++i)window.eval(s[i].innerHTML); // <-- bad
    }
    ajax.open("GET",url,true);
    ajax.send(null);
}
10
  • 3
    You'd have to go dark-side on this one if you're looking to execute the JavaScript like that Commented Nov 11, 2011 at 17:18
  • 1
    this has been asked and answed losts of times on SO Commented Nov 11, 2011 at 17:19
  • @user85569: I really hope that isn't true. I used the example loader for testing and it works. I just get a funny feeling using eval, the same feeling I get using goto in c++ Commented Nov 11, 2011 at 17:19
  • @david: I was unable to find a solution that worked for me, but there were a lot when I searched, and most were using jQuery. Commented Nov 11, 2011 at 17:21
  • 1
    jQuery is opensource, you could just see how they do it. Commented Nov 11, 2011 at 17:25

3 Answers 3

3

Please note that you're taking input from the user and running it in the context of a script on your site. So the script can do anything that JavaScript running on your browser/domain would have the ability to do (including cookie stealing, XSS, drive-by malware, etc.).

The only thing you can realistically do to mitigate the risks is to not eval() user-provided content. I'd suggest to consider the following alternatives:

  1. Use iframe as an environment to run user's script: http://dean.edwards.name/weblog/2006/11/sandbox/
  2. Use Caja. It allows websites to safely embed DHTML web applications from third parties, and enables rich interaction between the embedding page and the embedded applications. It uses an object-capability security model to allow for a wide range of flexible security policies. http://code.google.com/p/google-caja/
Sign up to request clarification or add additional context in comments.

3 Comments

Realistically, that function only loads URLs on the same domain, so it should be trustworthy... right? In fact, if I understand correctly, XMLHttpRequest can't load from other domains anyway.
@steveo225 there is a lot of histera around eval, if you know that the data trust worthy your sending to the client its ok to use eval, thought it can become a bit slow.
That is not true. He is not loading 'input from the user' - The function is called by the programmer with the URL which the programmer has given it. The file which it references is a static JavaScript file served by the programmer's server. There is no user input anywhere! So it is perfectly safe to use eval in this way. When you're embedding a script using a script tag, it also runs in the global scope - There is no difference there. You should not call eval on content which is generated by the user (fully or partially) - But it's perfectly safe for every other use case.
2

eval isn't particularly evil in this scenario, it's not a lot different than, say dynamically adding a script tag which pulls down a .js file and runs it. That said, there are other options, for instance you can dynamically create a script tag, create a text node with the contents of the script tag you pulled down, and add that to the document. Unlike the innerHTML technique, that will actually run the contents. The only advantage over eval, really, is that you might get a more meaningful stack trace etc if it crashes or has a syntax error.

var newScriptTag = document.createElement('script');
newScriptTag.appendChild(document.createTextNode(
     origScriptTag.innerHTML)
document.body.appendChild(newScriptTag);

Comments

0

I solved this today by putting my JavaScript at the bottom of the response HTML.

I had an AJAX request that returned a bunch of HTML that was displayed in an overlay. I needed to attach a click event to a button in the returned response HTML/overlay. On a normal page, I would wrap my JavaScript in a "window.onload" or "$(document).ready" so that it would attach the event handler to the DOM object after the DOM for the new overlay had been rendered, but because this was an AJAX response and not a new page load, that event never happened, the browser never executed my JavaScript, my event handler never got attached to the DOM element, and my new piece of functionality didn't work. Again, I solved my "executing JavaScript in an AJAX response problem" by not using "$(document).ready" in the head of the document, but by placing my JavaScript at the end of the document and having it run after the HTML/DOM had been rendered.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.