[Tutor] best way to dynamically set class variables?

Steven D'Aprano steve at pearwood.info
Fri Nov 9 19:03:20 EST 2018


On Thu, Nov 08, 2018 at 11:34:35AM -0500, Avi Gross wrote:
> An interesting discussion that is outside the scope of a group like this is
> HOW malicious things can be done and perhaps how to avoid them.
> 
> Obviously some contexts are totally uncontrolled. If you write a
> "calculator" that asks the user to type in an arbitrary string like
> "2*(3+5)" or "sin(30)" and execute that string and show the result, then
> they can slip in anything like a shell command to reformat the hard disk.

If they want to reformat their own hard disk, there are much easier ways 
than slipping a shell command into a Python calculator.

The risk, tiny as it is, is that something which starts life as a 
desktop application running on the user's own computer gets extracted 
out into a library used in a web application running on somebody else's 
server. So in that sense, it is better to avoid eval/exec even on 
locally-run desktop applications.

But it is *critical* to avoid eval or exec on untrusted input running on 
a server.


> What can you do to minimize risks in such situations?

(1) Don't use eval or exec.

(2) If you must use eval or exec, consider allowing only a whitelist of 
allowed commands. You can do that by specifying the global and local 
namespace arguments:

ns = {'round': round, 'sin': math.sin, '__builtins__': None}
eval(command, ns, ns)

You must set __builtins__ to something, if it is missing, the 
interpreter will set it to the real builtins module and open the doors 
wide open.

(3) Don't use eval or exec.

(4) But even with a whitelist, it is remarkably easy to break out of the 
sandbox. Most(?) tricks for doing so involve using dunder (Double 
UNDERscore) attributes, so a quick palliative for this is to disallow 
any command that includes an underscore:

if '_' in command:
     raise InvalidCommand('syntax error: no underscores allowed')
else:
     eval(command, ns, ns)

(5) Its okay to use eval and exec for your own use, at the interactive 
interpreter, or in quick scripts you use in a trusted environment.

(6) But even if you successfully block all the escape tricks, the user 
can trivially DOS (Denial Of Service) your calculator web app:

    command = '(2**1000)**(2**1000)**(2**1000)'

so you need to run it in an environment where evaluation will timeout 
after a certain amount of time, without using up all the memory on your 
server.

(7) For experts, its okay to use eval or exec. Maybe.


For a good use of exec, see the source code to namedtuple in the 
collections module. Or this:

http://code.activestate.com/recipes/578918-yet-another-namedtuple/


-- 
Steve


More information about the Tutor mailing list