Eval is Evil, Part Two


"urn:schemas-microsoft-com:office:office" />As
I promised, more information on why eval is evil.  (We once considered having
T-shirts printed up that said “Eval is evil!” on one side and “Script happens!” on
the other, but the PM’s never managed to tear themselves away from their web browsing
long enough to order them.)

 

 

/>Incidentally, a buddy
of mine who is one of those senior web developer kinda guys back in

Waterloo
sent me an email yesterday saying “Hello, my name is Robert and I am an evalaholic”. 
People, it wasn’t my intention to
start a twelve step program, but hey, whatever works! 

 

As
I discussed
the other day
,
eval on
the client is evil because it leads to sloppy, hard-to-debug-and-maintain programs
that consume huge amounts of memory and run unnecessarily slowly even when performing
simple tasks.  But like I said in my performance
rant
, if it’s good
enough
, then hey, it’s good enough.  Maybe
you don’t need to write maintainable,
efficient code.  Seriously! Script is
often used to write programs that are used a couple of times and then thrown away,
so who cares if they’re slow and inelegant?

 

But eval on
the server is an entirely different beast.  First
off, server scenarios are generally a lot more performance sensitive than client scenarios.  On
a client, once your code runs faster than a human being can notice the lag, there’s
usually not much point in making it faster.  But  as
I mentioned earlier
, ASP goes to a lot of work to ensure that for a given page,
the compiler only runs once. An
eval defeats
this optimization by making the compiler run every time the page runs! On a server,
going from 25 ms to 40 ms to serve a page means going from 40 pages a second to 25
pages a second, and that can be expensive in real dollar terms. 

 

But
that’s not the most important reason to eschew
eval on
the server.  Any use of
eval (or
its VBScript cousins
Eval, Execute and ExecuteGlobal)
is a potentially enormous security hole. 

 

<%

  var
Processor_ProductList;

  var
Software_ProductList;

  var
HardDisk_ProductList;

  //

  CategoryName
= Request.QueryString(“category”);

  ProductList
= eval(CategoryName & “_ProductList”);

  //

 

What’s
wrong with this picture?  The
server assumes that the client is not hostile.
  Is
that a warranted assumption?  Probably
not!  You know nothing about the client
that sent the request.  Maybe your client
page only sends strings like “Processor” and “HardDisk” to the server, but anyone
can write their own web page that sends

 

((new
ActiveXObject(‘Scripting.FileSystemObject’)).DeleteFile(‘C:*.*’,true)); Processor

 

which
will cause
eval to
evaluate

 

((new
ActiveXObject(‘Scripting.FileSystemObject’)).DeleteFile(‘C:*.*’,true)); Processor_ProductList

 

Obviously
that’s a pretty unsophisticated attack.  The
attacker can put any
code in there that they want
, and it will run in the context of the server process.  Hopefully
the server process is not a highly privileged one, but still, there’s vast potential
for massive harm here just by screwing up the logic on your server.

 

Never
trust the input to a server, and try to never use
eval on
a server. 
Eval injection
makes SQL injection look tame!

 

To
try and mitigate these sorts of problems, JScript .NET has some restrictions on its
implementation of
eval,
but that’s a topic for another entry.

 

Comments (6)

  1. Cliff says:

    Great information, but how about some advice on what to use as an alternative?  The point to Eval/Execute is to provide the ability to execute code that you wont know you need until the last minute.  I can see why Eval might be bad, but how would one go about it otherwise?

    Answers are the difference between being a thermometer & a thermostat.  Thermometers just let you know something is wrong.  A thermostat sees the problem & then takes action to actually do something to improve the situation.

  2. EricLippert says:

    How would one go about WHAT otherwise?  To answer the question, I’d have to know what eval/execute was being used for in the first place!

    That said, _most_ uses of eval that I’ve seen could be rewritten to use a lookup table, and the resulting code would be smaller, faster, easier to maintain, and have fewer security holes.  

  3. Enigmatic says:

    We are using XAML to write validation rules which are evaluated on the fly using Eval. So how would you go about evaluating at runtime a condition whose values may change depending on the input of the user?

  4. Marlin says:

    In answer to Eric's question, this worked for me in ASP classic, JScript:

    code.google.com/…/json-sans-eval

    I found it at JSON .org and I saved it as json-sans-eval.asp and edited it so that it started with <% and ended with %>

    Then in my code where I was using eval I put this at towards the top (outside of the <% %>

    <!– #include file="json_sans_eval.asp" –>

    Then instead of eval(X) is used jsonParse(X).

    Worked great.