8

I have a form field on my page, which if the user types a simple math equation into it, I would like to replace the value with the solution. So if the user types 1 + 2 into the field and hits enter I replace the input value with 3.

Currently I only evaluate the equation if it matches this regex:

/^[\d. \+/\*-]+$/

That is, if the entire string is made up of digits, spaces, plus, minus, multiply, or divide characters.

I then eval the value like such:

(new Function('try {var a = ' + val + '; return a;} catch(e) {return -1;}'))()

This form field can be pre-populated by a query string param and the client will attempt to execute it. AKA a potential atack would be mysite.com?inputVal=cookieStealingProgram. I don't want users to be able to link to exploiting code.

I would like to add parenthesis and exponents to the regex so the user could put in (1 + 2) / 3 ^ 5 for example. While I'm fairly certain no exploits are possible with just numbers and operators, I'm not sure about a case with parenthesis.

I am aware that using only combinations of the characters ! [ ] + ( ) you can create a fully executable javascript program. I have also tried searching for "javascript exploit characters" and various combinations in Google but it's not a straightforward thing to find.

My specific question is can an arbitrary javascript program be written using only 0-9 . + - / * ( ) ^ (space character allowed)? Since it is a bit open ended, if no example can be provided after a few days, I'm fine closing this question.

I am NOT implementing nor making a parser to do this. That is irrelevant to the question

Andy Ray
  • 30,372
  • 14
  • 101
  • 138
  • 1
    You can make any program you want, see http://patriciopalladino.com/files/hieroglyphy/ . For example, you could steal the user's cookies. You can definitely do many "useful" things if you can exploit a javascript eval. – Andy Ray Nov 27 '12 at 23:07
  • 3
    XSS is either stored or reflected, if neither is possible it doesn't matter. I'd write a custom parser anyway, `^` is the XOR operator, so you can't use eval anyway if you want to support exponentiation – Esailija Nov 27 '12 at 23:07
  • I think the main point is that regardless of what the script can do, if the script isn't being served to anyone else and is run in a safe environment on the server, who cares? – thedan Nov 27 '12 at 23:08
  • 1
    `return -1` in your catch is not useful. If the user evals `2-3` he should get the same result. It's better to return `undefined`, `NaN`, or something that reflects an error message. – vol7ron Nov 27 '12 at 23:13
  • +vol7ron in this case it doesn't matter, it's a price field, so we only deal with positive numbers. that sanitization happens at a later step. – Andy Ray Nov 27 '12 at 23:18
  • 1
    Just to add, if you test your link in newer browsers, the JavaScript engine has changed and that "exploit" no longer works, but it doesn't really matter anyhow since eval is running client-side code. --- To put what nnnnnn was saying in another way, users can technically make their own front-end to your website - they can code any bit of JavaScript they want - it's up to your server-side code to do the cleaning, which would effect your site's users. – vol7ron Nov 27 '12 at 23:21
  • 1
    One way to (try) to avoid the possibility of an exploit is to just use a parser generator. Such beasts exist for Javascript. [Here](http://zaach.github.com/jison/demos/calc/) is a working demo of a calculator that supports most of what you appear to want, using the Jison parser generator. – ig0774 Nov 27 '12 at 23:37
  • 1
    My apologies for having misunderstood your point about the query string; I've deleted my previous comments to try to tidy up a bit now that your question explicitly gives an example similar to the one in my last comment. For the characters you want to allow I think you'll be OK. (Hypothetically if there was a potential exploit I think you'd still be OK if you limited the length of the string to be `eval`ed.) But don't forget Esailija's point that `^` is the XOR operator so you will need to do at least some pre-processing before the `eval`... – nnnnnn Nov 27 '12 at 23:47

4 Answers4

2

Answer 1. Using only the symbols you've listed, you can't make identifiers, so the only programs possible are arithmetic expressions. To answer the narrow question, the answer is no.

Yet Stack Overflow is read by many, and there are some closely related issue that would change the consequences in similar situations.

Answer 2. Answer 1 is best used when the code base is maintained by a single person who knows what they're doing. If someone came along later and wanted the user (say) to be able to symbolically reference a price elsewhere, now you have identifiers. If a later change were simply to add characters to a regex, because that's the simplest way to get it working, then you're at risk. While I am generally not a fan of language features that attempt to prevent stupidity, this is a particular way of writing code for a specific task that seems far too prone to bad modification.

Answer 3. The original reference implementation of the JSON parser actually uses eval(), but it guards that statement with a JSON syntax verifier that ensures that the input is well-formed. It does this without a parser, but rather by some cleverly written regular expressions that recognize valid substrings and compact them. It's somewhat analogous to a reduce operation in syntax-directed translation, but without actually evaluating the expression. In the present situation, a regex substitution such as /[0-9]+\+[0-9]+/0/ rewrites a primitive addition as 0. Write one rule for each possible reduction, and put them all in a loop. The loop terminates when the initial string length is the same as that of the final string. The acceptance pattern after the rewrite would then be /[0-9]+/, and usually just 0.

Answer 4. Using a parser generator is often the best solution for this class of problems if there's any possibility that the kinds of expressions ever need identifiers. I wouldn't trust a regex rewriting system to be maintained correctly in such a case. Admittedly it seems like overkill for the question exactly as posed.

I recommend Answer 3 for production code.


Answer 2 Expansion. The biggest identifiable risk (a subset of all risks) is that you someone adds $ to the accepted list of characters, because it's a price field, after all, and "users have complained". $ is a valid identifier (frequently assigned as jQuery), but so is $0, and $0() is a valid function call. Although this is not a proximate risk, it is a contributory one, say, if there's some other security defect that allows defining, but not calling, the property window.$0. Such code would be a security defect, even if it does not by itself lead to a security breach.
eh9
  • 7,340
  • 20
  • 43
1

The comments have some valid points.

To answer your question though, limit the size of the equation that can be entered.

This document.getElementsByTagName("body")[0].style.display = "none";

Is converted to this:

[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]](([][[]]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+([][[]]+[])[!+[]+!![]])+([][[]]+[])[!+[]+!![]+!![]]+([][[]]+[])[+!![]]+(!![]+[])[+[]]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+[])+([][[]]+[])[!+[]+!![]+!![]])+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![

The above is only a fraction of what it gets turned into. The total script is 48,000 characters. Stack wouldn't even let me post it all

And that is about as basic as it gets for a script that is "fully functional", I doubt any user would want to enter a equation of length even close to that.

Ryan
  • 5,644
  • 3
  • 38
  • 66
  • this answer should be a comment, but it is not relevant. a tinyurl can turn a huge malicious cookie stealing link into a tiny one. – Andy Ray Nov 27 '12 at 23:37
  • 2
    But Andy you couldn't use a tinyurl in this context without first entering a large string of code that could be `eval`ed into a statement that caused the browser to navigate to the tinyurl... – nnnnnn Nov 27 '12 at 23:51
  • what @nnnnnn said, If it takes over 48,000 characters to do this simple thing, I'm sorry but I just don't consider this type of scripting attack to be a real threat. and just to point out if you try to enter the above into tinyurl (remember the above is over 18,000 less characters then what is actually required for the script) you get a tinyurl error. – Ryan Nov 28 '12 at 00:00
  • who cares? just use a different url shortener or make your own. think like an attacker. – Andy Ray Nov 29 '12 at 03:02
1

Eval is very dangerous as you have learned. The modern browser escape-hatch for not having to use eval client-side, the JSON object, won't serve your needs because you need to evaluate expressions, which JSON doesn't permit.

On the plus side, you really only want to allow a few operators, + - / * ^ and parenthesis, which is not a very complex expression language.

Instead of trying to use regular expressions to validate the input to eval, I suggest you simply implement an expression evaluator, either in JavaScript client-side, or in the language of your choice server side.

Googling will find you lots of different ones with slightly different capabilities, or you can take it as a learning exercise to roll your own.

SAJ14SAJ
  • 1,698
  • 1
  • 13
  • 32
  • Stop dodging the question ;) – Andy Ray Nov 27 '12 at 23:36
  • 1
    In my mind, this answer is correct. Don't use `eval`; instead, implement your own expression parser and interpreter. – nibot Nov 27 '12 at 23:38
  • In my mind this answer has nothing to do with whether or not a full program can be written using PEMDAS – Andy Ray Nov 27 '12 at 23:39
  • Well, you are the OP, so I guess your view is by definition the correct one. (-: – nibot Nov 27 '12 at 23:40
  • Your parser will encode the PEMDAS rules. There are several methods, such as operator precedence parsers, or for this very simple grammar, a recursive decent grammar encoding the PEMDAS rules will suffice. – SAJ14SAJ Nov 27 '12 at 23:42
-1

The answer to the question is no, it is impossible to create an arbirtary program using the given inputs, including parenthesis. In order to create a program, you must be able to create strings. The closest you can get with these restrictions is NaN and Infinity however it is impossible to cast either of those to a string without allowing for quotes or braces.

tl;dr you are blocked because you can't make strings.

Andy Ray
  • 30,372
  • 14
  • 101
  • 138