I currently teach first year university students python, and I was surprised to learn that the seemingly innocuous input function, that some of my students had decided to use (and were confused by the odd behaviour), was hiding a call to eval behind it.
So my question is, why does the input function call eval, and what would this ever be useful for that it wouldn't be safer to do with raw_input? I understand that this has been changed in Python 3, but it seems like an unusual design decision in the first place.
Python 2.x input function documentation
Is it ever useful to use Python 2's input over raw_input?
No.
input() evaluates the code the user gives it. It puts the full power of Python in the hands of the user. With generator expressions/list comprehensions, __import__, and the if/else operators, literally anything Python can do can be achieved with a single expression. Malicious users can use input() to remove files (__import__('os').remove('precious_file')), monkeypatch the rest of the program (setattr(__import__('__main__'), 'function', lambda:42)), ... anything.
A normal user won't need to use all the advanced functionality. If you don't need expressions, use ast.literal_eval(raw_input()) – the literal_eval function is safe.
If you're writing for advanced users, give them a better way to input code. Plugins, user modules, etc. – something with the full Python syntax, not just the functionality.
If you're absolutely sure you know what you're doing, say eval(raw_input()). The eval screams "I'm dangerous!" to the trained eye. But, odds are you won't ever need this.
input() was one of the old design mistakes that Python 3 is solving.
Python Input function returns an object that's the result
of evaluating the expression.
raw_input function returns a string
name = "Arthur"
age = 45
first = raw_input("Please enter your age ")
second = input("Please enter your age again ")
# first will always contain a string
# second could contain any object and you can even
# type in a calculation and use "name" and "age" as
# you enter it at run time ...
print "You said you are",first
print "Then you said you are",second
examples of that running:
Example: 1
Prompt$ python yraw
Please enter your age 45
Please enter your age again 45
You said you are 45 Then you said you are 45
Example: 2
Prompt$ python yraw
Please enter your age 45 + 7
Please enter your age again 45 + 7
You said you are 45 + 7 Then you said you are 52
Prompt$
Q. why does the input function call eval?
A. Consider the scenario where user inputs an expression '45 + 7' in input, input will give correct result as compared to raw_input in python 2.x
input is pretty much only useful as a building block for an interactive python shell. You're certainly right that it's surprising it works the way it does, and is rather too purpose-specific to be a builtin - which I presume is why it got removed from Python 3.
raw_input is better, It always returns the input of the user without changes.
Conversely The input() function will try to convert things you enter as if they were Python code, and it has security problems so you should avoid it.
In real program don't use input(), Parse your input with something that handles the specific input format you're expecting, not by evaluating the input as Python code.
Related
I recently tried to find polynomials with given points and stumbled upon the problem that I can’t use strings like normal mathematical operations: "3 + 1" + "2 + 1" because it will return "3 + 12 + 1". I than tried to just iterate over the string but had the next difficulty that I cant just unstringify operations like "+" or "-".
Does anyone know how to do solve the problem?
eval() is very dangerous
It can execute any commands, including unsafe or malicious strings.
Use Pyparsing (more info here and another question and example here).
Another option is the ast module (good example here). If you want more functionality, ast can open up more commands, but pyparsing should work well.
A third, more lightweight option is this single file parser
If this calculation will exist purely within the code, with the user having no direct access, then you can use eval().
Example:
print(eval("3 + 4"))
Output:
7
The point of eval() is to execute Python code that is stored as a string. If the user is inputting values to be used within an eval() statement, you should absolutely do some error-checking to make sure the user is inputting numbers. If your program was intended to be released for commercial use, say, you run the risk of a user inputting Python code that can be executed using eval().
I'm working through Python Programming: An Introduction to Computer Science (2nd edition). At the end of the second chapter, one of the exercises is to design a calculator. Prior to this, he has been using eval() to do calculations. I know that using eval is bad for security, but I dont know how to get around using it. I could always use it now and worry about it later, but I want to build good habits.
I want the user to enter their desired calculation as one line, like this:
>>> input('Input your expression: ')
Input your expression: 4 * 5 / 2
I've already looked at this post Pros and Cons on designing a calculator with eval . The answer gave him a link that showed how you could get around it. The way he did it seemed quite convoluted, and I don't understand how he did it.
I think I need eval() for this. My code for the calculator is below. Thank you for the help!
# Calculator.py
# This program will allow the user to input a mathematical expression (using python syntax)
# it will then evaluate the expression and print the result. It will unfortunately use eval
# but I dont know how to get around this problem. The program will loop to allow for
# multiple calculations.
expression = 'blank'
print('Calculator')
print(' ')
print('Welcome! Please input your desired expression, using python syntax.')
print('When you are finished, input end, and the program will finish.')
# Until the user inputs end, the calculator will continue to repeat.
while expression != 'end':
print('')
expression= input('Input your expression: ')
# Checks if the last digit of expression is a digit. I think this is fairly foolproof.
# I used last digit instead of first, bc a negative sign could have been in the first digit.
if expression[len(expression)-1].isdigit():
print('= ', eval(expression))
# A way to distinguish between 'end' and other strings. After this prints and loops back,
# program should end.
elif expression == 'end':
print('Shutting down... ')
# If the user inputs something where the last digit is not a digit, and is
# not end, the program will notify them and repeat.
else:
print('Enter with only digits and operators!')
eval is probably what you want here. eval is mainly discouraged because it allows any users of your app to execute arbitrary code, which obviously leads to security vulnerabilities. However, since you're doing this for learning experience, not in a publicly released app, this isn't really a concern for you. Especially if you are just learning, I'd ignore this for now (definitely don't do this in a production app).
You'll want to do: eval(input('please enter a expression')), which allows you to execute an arbitrary expression.
In the article you link, they explain that eval takes two more optional parameters, that allow you to restrict what expressions can be executed by the eval.
He sets the second parameter to {"__builtins__":None} to restrict you from using any global functions (if it is set to {}, builtin functions like abs are still available).
He sets the third parameter to a dictionary of all functions he'd like to allow the user to execute, since he just restricted the user to not being able to run any global functions previously.
Ive heard that using "input" was unsafe for password use because it interprets the input as code, and thus someone could bypass the security.
How would you go around doing that? For example, how would you do it to something like this?
password = 1234
pass_true = input("What is the password?")
if password == pass_true:
print("Access granted.")
else:
print ("Access denied.")
It's simple: To get past your check, just type password at the prompt :-) Try it!
What is the password?password
Access granted.
Explanation: input reads what you type, evaluates it as python code, and assigns the result to pass_true. So in the above, I just told it to assign the value of the variable password (which holds the real password) to pass_true.
But this code is broken even for regular use: If you type anything that doesn't look like a valid python expression, it'll trigger an error. Your example uses numbers as "passwords", but you couldn't use the same approach for arbitrary-text passwords: It wouldn't work at all, even with the correct password.
Another kind of problem is typing something damaging like os.remove(".profile") (or something worse and more elaborate) at the prompt. It won't log them in but you can see the damage it can do. Evaluating user input is just wrong, unless you're writing an interactive python interpreter.
Python 2 has raw_input() which just reads input. (In python 3, raw_input() has been renamed to input() and the old input() is gone).
So I was just reading this and if you're using Python 3.x, you'll be fine.
Otherwise, if you use input(), then you could just type password and be done.
Again, if you're using Python 3.x, don't worry.
The idea is not to keep passwords at all. You have to create hash out of input and check whether it's equal to your password's hash. But if you're just a beginner it's okay to do what you do.
The side-channel attack sboutzen mentioned is a real threat, and can be exploited using time(), from linux command-line
This article explains it in more detail
https://blog.sqreen.com/developer-security-best-practices-protecting-against-timing-attacks/
The hash could be compromised by identifying the hash used byte by byte. You would have the hash of the real password instead of the password itself, but that is why dictionary attacks are useful.
Another problem you will have with that approach is that when you compare two strings like that, you leak information and set yourself up for a side-channel attack.
The string comparison will compare the two strings one byte at a time, and if one of the bytes don't match, it returns. However, this means that an attacker knows exactly which part, of the password he is testing, is correct, and which part is not. Therefore he can reduce the entropy of a given password to 2 to the power of the length of the set of characters allowed.
When comparing passwords you should compare the two strings bytewise like so:
result = 0;
for (int i = 0; i < storedUserPass.length; i++) {
result |= storedUserPass[i] ^ incomingPasswordBytes[i];
}
When it is done, if result is equal to 0, all the bytes match, if not, they dont. This is a constant time calculation, which doesn't leak any information
I'm new to programming and I need some help for a ai robot I just started on
Here is my code:
complements = "nice" and "happy" and "good" and "smart" and "wonderful"
var = "You are a "+ complements
input = raw_input
if var in input:
print "Thank you!"
else:
print "Wuhhhhh?"
If I type in something other than "nice" it goes to the else statement.
Or statements don't work
First, the and keyword does not do what you want. It is used as a binary comparison. Due to the inner workings of Python, your variable complements will receive the value "wonderful". You want to put these words in a list (see here). You will then be able to manipulate these words using concatenation as such (for example):
var = "You are a " + ", ".join(complements)
Furthermore, raw_input is a function. It must be called as such: raw_input(). Otherwise, you just create an alias of the function which you named input. You would still have to call it by appending () to it in order to receive the user input.
I also don't understand your if var in input: statement. var is a sentence you made, why would you search it in the user input? It would be clearer to do if raw_input() in complements, or something along the lines of it.
If you are beginning to learn Python, I would recommend you to use Python 3 instead of Python 2. raw_input() was renamed input() in Python 3.
Is it possible to define input times, like time, date, currency or that should be verified manually? Like for example:
morning = input('Enter morning Time:')
evening = input('Enter evening Time:')
.. I need (only) time here, how do I make sure that user enters input in xx:xx format where xx are integers only.
input (in Python 2.any) will return the type of whatever expression the user types in. Better (in Python 2.any) is to use raw_input, which returns a string, and do the conversion yourself, catching the TypeError if the conversion fails.
Python 3.any's input works like 2.any's raw_input, i.e., it returns a string.
You can't really force the input function to return a certain type. It's best you write some kind of a wrapper that reads some input from the user and then converts it to an appropriate type for your application (or throw an exception in case of an error).
Also, as Alex said, it's better to use raw_input for user input since it will always return the entered value as a string. Much more manageable.