Reputation: 1217
The situation is this: I have some JavaScript that creates an interactive dialogue (and displays it in the form of a comic strip via dynamic element creation... it's fun). The page allows the user to adjust settings, altering the dialogue produced by the script. As a theoretical example, one of the check boxes could be "Use cussing", and the script only adds the cuss words to the returned string if this box is checked. oK, simple enough. Fun.
It currently uses just one template (the "comic strip" has a very specific and pointed purpose) to generate the dialogue; this template is hard coded into the JavaScript. I would like the user to be able to create their own template, which is then turned into a script that is executed just like the hard-coded version, and also able to be controlled by the checkbox options. Edit: To clarify, the user doesn't write script directly. They write a representation (for which I'm now considering using JSON), and when someone else opens the page with the template, the page will THEN turn it into a script and execute it.
This presents some problems. Most obvious is attack by malicious user. Edit: While the user won't be writing a script themselves, since everything's client-side they can easily see my parsing script and may be able to figure out how to insert something. Not really too worried about this, though. End edit. I'm sure there are some standard ways to deal with that, and as currently there's no interaction server-side - everything's client-side - my main concern is that such a user cannot hurt the experience of another user by sharing his bad version. Right now, I'm simply stripping the string at the outset by globally replacing all characters not within a set:
str.replace(/[^a-zA-Z...]/g,'')
.
Another problem is how to serve their template to the page for others to enjoy. As I said, there's no server-side interaction, and I'd like to keep it that way. I don't want to create MySQL tables and such to store their templates. Unfortunately, this means that the only viable method I can think of is by having their template in the query string of the URL. Nasty, that. And that does impose limits on character length - as little as 2,000 to be compatible with older IE, if I've read right. (I also thought of generating the text of an HTML file they could copy n paste, save as such, host somewhere, and send the address to my page in the URL, which is then loaded into an iFrame...... Ha. Yeah. Not as user-friendly - involves both saving as a file type they've probably never saved as before as well as figuring out how to host a file - and creates even bigger security issues.)
Third problem is once the page has received the template from them, made it secure, and transformed it into a script, how should I execute that script? I've heard since I first started Javascript that eval is evil, so I have avoided using it. Apparently doing new Function(txt)
is just as evil (though I have done that many times before). I'm willing to accept these claims of evilness..... But what alternatives are there?? I searched Google for that, and the closest to my situation I could find was this StackOverflow question, involving remote code. The accepted answer proposes dynamically creating a script tag with the textContent set to the script string. Would this also be the best solution for me?
Summary
I need to access user-generated text (preferably without storing it server-side), parse it into Javascript while avoiding attacks, and then execute it with some alternative to eval()
.
Upvotes: 4
Views: 763
Reputation: 2650
As @pst said, use a JSON representation of template features (and arguments), and only run trusted code.
Maybe something like
{
border: { color: '#BADA55' },
layout: { columns: 2, rows: 4 }
}
and then just parse it with a loop, an array of handlers, a switch...case
cascade, or similar.
Compacted a bit, this could fit a pretty detailed template in under 2000 characters.
jsfiddle safely runs untrusted code by serving it in an iframe from a different domain name, so if this is an option and you really want to eval some untrusted code, just do that. You'll still end up making a declarative representation (or trying to sanitize it perfectly until you realize you can't) if you insist on preventing "hurt experiences".
Upvotes: 3