I have a situation with some code where eval()
came up as a possible solution. Now I have never had
to use eval()
before but, I have come across plenty of information about the potential
danger it can cause. That said, I'm very wary about using it.
My situation is that I have input being given by a user:
datamap = raw_input('Provide some data here: ')
Where datamap
needs to be a dictionary. I searched around and found that eval()
could work this out.
I thought that I might be able to check the type of the input before trying to use the data and that
would be a viable security precaution.
datamap = eval(raw_input('Provide some data here: ')
if not isinstance(datamap, dict):
return
I read through the docs and I am still unclear if this would be safe or not. Does eval evaluate the data as soon as its entered or after the datamap
variable is called?
Is the ast
module's .literal_eval()
the only safe option?
ast.literal_eval()
only considers a small subset of Python's syntax to be valid:Passing
__import__('os').system('rm -rf /a-path-you-really-care-about')
intoast.literal_eval()
will raise an error, buteval()
will happily wipe your drive.Since it looks like you're only letting the user input a plain dictionary, use
ast.literal_eval()
. It safely does what you want and nothing more.Python's eager in its evaluation, so
eval(raw_input(...))
will evaluate the user's input as soon as it hits theeval
, regardless of what you do with the data afterwards. Therefore, this is not safe, especially when youeval
user input.Use
ast.literal_eval
.As an example, entering this at the prompt will be very, very bad for you:
If all you need is a user provided dictionary, possible better solution is
json.loads
. The main limitation is that json dicts requires string keys. Also you can only provide literal data, but that is also the case forliteral_eval
.I was stuck with
ast.literal_eval()
. I was trying it in IntelliJ IDEA debugger, and it kept returningNone
on debugger output.But later when I assigned its output to a variable and printed it in code. It worked fine. Sharing code example:
Its python version 3.6.
eval: This is very powerful, but is also very dangerous if you accept strings to evaluate from untrusted input. Suppose the string being evaluated is "os.system('rm -rf /')" ? It will really start deleting all the files on your computer.
ast.literal_eval: Safely evaluate an expression node or a string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, None, bytes and sets.
Syntax:
Example:
From python 3.7 ast.literal_eval() is now stricter. Addition and subtraction of arbitrary numbers are no longer allowed. link
datamap = eval(raw_input('Provide some data here: '))
means that you actually evaluate the code before you deem it to be unsafe or not. It evaluates the code as soon as the function is called. See also the dangers ofeval
.ast.literal_eval
raises an exception if the input isn't a valid Python datatype, so the code won't be executed if it's not.Use
ast.literal_eval
whenever you needeval
. You shouldn't usually evaluate literal Python statements.