1

I'm creating a subclass of ConfigParser that is easier for me to use throughout my project:

class MyConfiguration(ConfigParser.ConfigParser):

    def __init__(self, filename):
        ConfigParser.ConfigParser.__init__(self)
        self.readfp(open(filename))

    def get(self, section, option):
        return eval(ConfigParser.ConfigParser.get(self, section, option))

Question: are there any downsides (security, unintended consequences) to overriding the get() method with one that includes eval?

I'd rather bake the eval into the MyConfiguration class because I want to use Python data types (tuples, etc.) in my config files but I don't want to deal with evals all over my project code.

MikeRand
  • 4,788
  • 9
  • 41
  • 70

2 Answers2

1

I am not sure if it is a good idea to eval an arbitary text that may be contained in the config file. A normal call to eval is usually considered unsafe.

See:

  1. Security of Python's eval() on untrusted strings?
  2. Use of eval in Python?

If you want to use python data types, then it is much better to store it as a python module and import it. This might be a better solution in this case.

You can split up the config file as those containing python data types in a python module and keeping the rest as config file that can be parsed by configparser.

Community
  • 1
  • 1
pyfunc
  • 65,343
  • 15
  • 148
  • 136
  • So is the typical use of ConfigParser to create and use configuration files with basic data types (i.e. those for which there is a specific get() method, such as str, int, float, boolean)? Or are containers allowed, but the eval is usually done in the calling class (which probably has a better way of handling the eval)? – MikeRand Nov 14 '10 at 16:33
  • @MikeRand: Yes, it is better to call eval in the calling class. While my answer points to issues with eval, aaronasterling provides a better answer. You can use that. – pyfunc Nov 14 '10 at 17:17
1

If your only interest in eval is literal values as you seem to indicate, then you can use ast.literal_eval

This will read tuple literals, list literals and others and is safe to use because it is selective about what it will accept.

>>> import ast
>>> a = ast.literal_eval('(1, 2, 3)')
>>> a
(1, 2, 3)
>>> b = ast.literal_eval('__import__("evil")')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/ast.py", line 68, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib/python2.6/ast.py", line 67, in _convert
    raise ValueError('malformed string')
ValueError: malformed string

Use cases like this are exactly what this function is intended for.

aaronasterling
  • 68,820
  • 20
  • 127
  • 125