Is my eval() safe?

2019-01-27 09:03发布

问题:

I built a dice roller here: http://howderek.com/projects/diediedie/

and I wanted to implement math so that my users could preform mathmatical operations to their rolls, which is useful for RPGs.

Instead of building a function to handle the math, or using a library like math.js, I figured that since JavaScript has math built in, this might be a good use for eval().

The reason I am concerned with the eval() however, is that appending ?q=whatever to the url of DieDieDie enters whatever into the box and passed it to DieDieDie

Now, obviously, if this was purely just an eval console, it would be easy to abuse and run malicious JavaScript through, but it's not, I use a RegEx before running eval()

From (http://howderek.com/projects/diediedie/js/diediedie.js):

if (!replaced.match(/[^0-9 | + | \- | * | \/ | ( | ) | \. | % | > | <]/g)) {
    result = eval(replaced);
} else {
    throw 'Unsafe eval (more than just math), refusing to execute.';
}

So, I was wondering if there was any way to circumvent the RegEx, and run code though that eval() just by entering text into the box.

回答1:

Complexity is the enemy of security, so I find it best to implement a simple solution that you know is secure rather than attempting to come up with something more complicated that has possibly made something safe (but no one is quite sure until an exploit is found).

A safe way to do it is that you could use a HTML5 Sandbox to load a page hosting your script, then you do not need to be concerned about whether your RegEx can be bypassed.

You will need to host the page under a different domain than your main site (e.g. script.example.com instead of www.example.com). This will prevent any XSS attack if an attacker convinces a user to visit the page directly (outside of the sandbox).

You will need to enable scripts within the IFrame by using code like this:

<iframe src="http://script.example.com/projects/diediedie/" sandbox="allow-scripts" />

This will allow scripts, but in the case of an exploit being found to your RegEx, forms and navigation outside of the IFrame will be prevented. As it is on a different domain, your main site cannot be attacked via XSS.

The HTML5 Security Cheat Sheet guidance on OWASP states this is the purpose of the sandbox:

Use the sandbox attribute of an iframe for untrusted content

As you are allowing untrusted content to run via eval (albeit "sanitised" via RegEx), this seems like an appropriate use of the sandboxed IFrame.

You should test whether sandbox is supported first, before rendering the IFrame:

<iframe src="/blank.htm" sandbox="allow-scripts" id="foo" />

var sandboxSupported = "sandbox" in document.createElement("iframe");

if (sandboxSupported) {
    document.getElementById('foo').setAttribute('src', 'http://script.example.com/projects/diediedie/');
}
else
{
    // Not safe to display IFrame
}

It is safer to do it this way by dynamically changing the src rather than redirecting away if sandboxSupported is false because then the iframe will not accidentally be rendered if the redirect doesn't happen in time.

To enable this to work cross-domain (between script.example.com and www.example.com) you will need to use HTML5's Window.postMessage functionality. This will enable secure communication between the IFrame and the outer window. Note that setting document.domain is not secure as it will defeat the purpose of hosting the page on a separate domain in the first place.