Using Python for date calculations

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Nov 21 09:55:29 EST 2014


random832 at fastmail.us wrote:


> Out of curiosity, is there a way to use eval "safely" (i.e. strictly
> limiting what it has access to) across a privilege boundary? This also
> comes up for pickle and other serialization formats that can store
> arbitrary classes (i.e. call arbitrary constructors).

Not really. If there is, it is very hard.

Ned has a good write-up here:

http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html

Some years ago, Tav made an attempt to secure the interpreter against file
system writes:

http://tav.espians.com/a-challenge-to-break-python-security.html

That didn't work so well, although Tav's efforts towards building a
Capabilities version of Python are promising:

http://tav.espians.com/paving-the-way-to-securing-the-python-interpreter.html


Without a full parser, it's hard to defend against Denial Of Service attacks
like this:

    # don't try this at home
    eval("100**100**100")


We can *mitigate* the danger in a number of ways:

- Combination of blacklists and whitelists.

- Avoid *easy* access to built-ins by specifying the namespace that the code
should be executed in:

    eval("code goes here", {'__builtins__'={}})


- If you need access to specific built-ins, add them to your namespace:

    eval("code goes here", {'__builtins__'={}, 'int'=int})

- Disallow any expression which includes underscore _ characters, this will
make it harder (but maybe not impossible?) for an attacker to break out of
your sandbox.

- Have a short limit on the length of the expression. The shorter the
expression, the less surface an attacker has to attack. (An attacker may
find some clever trick to escape the sandbox, but it's harder to do so in
20 characters than in 200.)

- Run untrusted code in a separate process, with a timeout.

- Use your OS facilities to run that process in a chroot jail.


But even better is to avoid eval completely. If all you want is to evaluate
a few simple constant expressions:

py> from ast import literal_eval
py> literal_eval('[None, 23, "hello", {0.5: "x"}]')
[None, 23, 'hello', {0.5: 'x'}]


-- 
Steven




More information about the Python-list mailing list