Security of Python's eval() on untrusted strings?
You cannot secure eval with a blacklist approach like this. See Eval really is dangerous for examples of input that will segfault the CPython interpreter, give access to any class you like, and so on.
Is there a way to secure strings for Python's eval?
Here you have a working "exploit" with your restrictions in place - only contains lower case ascii chars or any of the signs +-*/() .
It relies on a 2nd eval layer.
def mask_code( python_code ):
s="+".join(["chr("+str(ord(i))+")" for i in python_code])
return "eval("+s+")"
bad_code='''__import__("os").getcwd()'''
masked= mask_code( bad_code )
print masked
print eval(bad_code)
output:
eval(chr(111)+chr(115)+chr(46)+chr(103)+chr(101)+chr(116)+chr(99)+chr(119)+chr(100)+chr(40)+chr(41))
/home/user
This is a very trivial "exploit". I'm sure there's countless others, even with further character restrictions.
It bears repeating that one should always use a parser or ast.literal_eval(). Only by parsing the tokens can one be sure the string is safe to evaluate. Anything else is betting against the house.
Safety of Python 'eval' For List Deserialization
It is indeed dangerous and the safest alternative is ast.literal_eval
(see the ast module in the standard library). You can of course build and alter an ast
to provide e.g. evaluation of variables and the like before you eval the resulting AST (when it's down to literals).
The possible exploit of eval
starts with any object it can get its hands on (say True
here) and going via .__class_ to its type object, etc. up to object
, then gets its subclasses... basically it can get to ANY object type and wreck havoc. I can be more specific but I'd rather not do it in a public forum (the exploit is well known, but considering how many people still ignore it, revealing it to wannabe script kiddies could make things worse... just avoid eval
on unsanitized user input and live happily ever after!-).
How safe is expression evaluation using eval?
It's completely unsafe to use eval
, even with built-ins emptied and blocked -- the attacker can start with a literal, get its __class__
, etc, etc, up to object
, its __subclasses__
, and so forth... basically, Python introspection is just too strong to stand up to a skilled, determined attacker.
ast.literal_eval
is safe, if you can live by its limitations...
Why is using 'eval' a bad practice?
Yes, using eval
is a bad practice. Just to name a few reasons:
- There is almost always a better way to do it
- Very dangerous and insecure
- Makes debugging difficult
- Slow
In your case you can use setattr instead:
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
setattr(self, att.lower(), None)
def setDetail(self, key, val):
if key in self.attsToStore:
setattr(self, key.lower(), val)
There are some cases where you have to use eval
or exec
. But they are rare. Using eval
in your case is a bad practice for sure. I'm emphasizing on bad practice because eval
and exec
are frequently used in the wrong place.
Replying to the comments:
It looks like some disagree that eval
is 'very dangerous and insecure' in the OP case. That might be true for this specific case but not in general. The question was general and the reasons I listed are true for the general case as well.
Math Eval String in DataFrame Python
Although there are security concerns, you can use eval
to evaluate each element using a lambda
expression.
df = pd.DataFrame({'X': ['25+4', '25+5', '15+3', '20+2', '20+3']})
>>> df
X
0 25+4
1 25+5
2 15+3
3 20+2
4 20+3
>>> df.X.apply(lambda x: eval(x))
0 29
1 30
2 18
3 22
4 23
Name: X, dtype: int64
For a description of security concerns, see:
Security of Python's eval() on untrusted strings?
https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
Using python's eval() vs. ast.literal_eval()?
Change string to list datatype
The string you have is valid json, so you can just parse it:
import json
x = '["a","b"]'
l = json.loads(x)
print(l)
# ['a', 'b']
print(type(l))
# <class 'list'>
Related Topics
Executable Python Program with All Dependencies for Linux
Find Out Who Is Logged in on Linux Using Python
Can't Start Foreman in Heroku Tutorial Using Python
Cannot Open Include File: 'Io.H': No Such File or Directory
How to Round to 2 Decimals with Python
Error: Pandas Hashtable Keyerror
How to Hide the Console When I Use Os.System() or Subprocess.Call()
Is There a Simple Way to Delete a List Element by Value
How to Preserve Timezone When Parsing Date/Time Strings with Strptime()
Iterate an Iterator by Chunks (Of N) in Python
Set Bash Variable from Python Script
Crontab Failed to Run Python Script at Reboot
Distributing Ruby/Python Desktop Apps
Security of Python's Eval() on Untrusted Strings
CSV in Python Adding an Extra Carriage Return, on Windows
Converting a Pandas Groupby Output from Series to Dataframe