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
Related
I am trying to check if my input is a string with try-except block. The function runs without an error. However it checks if the input is an integer, not string. How can I inverse this?
def lexicon(word):
while True:
try:
a=str(input(word))
print("Input is a string. string = ", a)
except ValueError:
print("Oops..Input is not supposed to be a number. Try again!")
return a
b=lexicon("Enter the word you'd like: ")
As discussed with user pavel in the comments to his answer, there are two different styles to code for a problem like this: EAFP ("Easier to Ask for Forgiveness than Permission"), meaning that you make your code work on an assumption and take action if it fails; and LBYL ("Look Before You Leap"), in which you first check whether your assumption is true, and then choose the appropriate action to take.
The try/except route is EAFP, since it just executes the code in the try block without bothering to first check whether it would work. If you want to do it in LYBL style, you would explicitly need to ascertain whether the user input is a string representation of a numeric value, and then act accordingly. I'll provide skeletal code for both approaches below. However, note that Python is a little weird compared to other languages in that it seems to have a certain cultural favour for EAFP.
Also, since you are only asking about checking for integers, I will focus on that here. This means that the code will accept floats as valid inputs.
EAFP: try/except
The problem that presumably trips you up is that input always returns a string, so testing if it is a string is nonsensical and will always yield True. However, note that try/except is only an abrigded version of error handling that you can do in Python; the full version is try/except/else/finally. The else block takes effect if no except blocks are executed, and finally is always run at the end. So you could check whether your input is an integer, and make the program raise a failure if that check succeeds. I admit however that this does seem a bit backwards.
try:
a = int(input())
except ValueError:
# do whatever
else:
raise ValueError("Input must not be an integer")
LBYL: if/else
str objects have several methods to test their contents without having to run into errors. For example, .isalpha() checks if all characters are in the alphabet (which returns False however if you include spaces and special characters); isnumeric() checks whether the string is a representation of a number; etc. See a full list here. So depending on what kind of inputs you want to allow, you would need to use one of these methods, or a combination of them, in an if block. The code below essentially does the same thing as the try/except/else version above, using .isdigit() which returns True if all characters in the string are digits (i.e., the same kind of input for which int(a) would succeed).
Note also that I am making use of the new assignment operator := in this code, which is new to Python 3.8. This way, you don't need to explicitly assign the variable a first, however it's a bit harder to catch where the code actually executes an input() function. If you code for backwards compatibility, or don't like the look of this, you'd have to go with the classical a = input() first.
if (a := input()).isdigit():
raise ValueError("Input must not be an integer")
# do whatever
If you want specifically to check the value type of the string, you're better off using if/else and isinstance:
if not isinstance(word, str):
raise TypeError(f"Expecting a string as a value, not {type(word)}.")
else:
#do something
I'm beginner to Python ... I'd like to format the characters in Python using basic concepts and operations of Tuples and Lists as below ...
I enter 10 digit number and except last 4 digits remaining all the numbers should be replaced by 'X'. For e.g.
number = 1234567890
Expecting output as -
number = XXXXXX7890
How to mask entered characters / numbers in Python using Tuples/Lists concept not using by importing any modules or existing high functions. Is it possible ?
For e.g. entered some characters , those should be masked using * (asterisk) or # (hashed) while entering. For e.g.
password : pa55w0rd
Expecting output while entering password as -
password : ********
OR
password: ########
It is always better to use built-in modules for things sensitive like password. One way of doing is following:
import getpass
number = 1234567890
first = 'X' * max(0,len(str(number)[:-4]))
last = str(number)[-4:]
n = first + last
print(n)
# part 2
p = getpass.getpass(prompt='Enter the number : ')
if int(p) == 123:
print('Welcome..!!!')
else:
print('Please enter correct number..!!!')
If you don't want to display typed password just print:
print('######')
It does not have to be of the same length you just have to print something.
Break down what's needed: you need to convert to a string, to figure out how many characters to replace, generate a replacement string of that length, then include the tail of the original string. Also you need to be robust against, eg, strings too short to have any characters replaced.
'X' * max(0, len(str(number)) - 4) + str(number)[-4:]
For the second part: use a library.
Doing this directly is more complicated than it might seem to a beginner, because you're having to communicate with the systems which take text entry. It's going to depend upon the operating system, Windows vs "roughly everything else". For text entry outside of a web-browser or a GUI, most systems are emulating ancient text-only terminal devices because there's not yet enough reason to change that. Those devices have modes of text input (character at a time, line at a time, raw, etc) and changing them to not immediately "echo" the character typed involves some intricate system calls, and then other programming to echo a different character instead.
Thus you're going to want to use a library to take care of all those intricate details for you. Something around password entry. Given the security implications, using tested and hardened code instead of rolling your own is something I strongly encourage. Be aware that there are all sorts of issues around password handling too (constant time comparisons, memory handling, etc) such that as much as possible, you should avoid doing it at all, or move it to another program, and when you do handle it, use the existing libraries.
If you can, stick to the Python standard library and use getpass which won't echo anything for passwords, instead of printing stars.
If you really want the stars, then search https://pypi.org/ for getpass and see all the variants people have produced. Most of the ones I saw in a quick look didn't inspire confidence; pysectools seemed better than the others, but I've not used it.
I am teaching some neighborhood kids to program in Python. Our first project is to convert a string given as a Roman numeral to the Arabic value.
So we developed an function to evaluate a string that is a Roman numeral the function takes a string and creates a list that has the Arabic equivalents and the operations that would be done to evaluate to the Arabic equivalent.
For example suppose you fed in XI the function will return [1,'+',10]
If you fed in IX the function will return [10,'-',1]
Since we need to handle the cases where adjacent values are equal separately let us ignore the case where the supplied value is XII as that would return [1,'=',1,'+',10] and the case where the Roman is IIX as that would return [10,'-',1,'=',1]
Here is the function
def conversion(some_roman):
roman_dict = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M',1000}
arabic_list = []
for letter in some_roman.upper():
if len(roman_list) == 0:
arabic_list.append(roman_dict[letter]
continue
previous = roman_list[-1]
current_arabic = roman_dict[letter]
if current_arabic > previous:
arabic_list.extend(['+',current_arabic])
continue
if current_arabic == previous:
arabic_list.extend(['=',current_arabic])
continue
if current_arabic < previous:
arabic_list.extend(['-',current_arabic])
arabic_list.reverse()
return arabic_list
the only way I can think to evaluate the result is to use eval()
something like
def evaluate(some_list):
list_of_strings = [str(item) for item in some_list]
converted_to_string = ''.join([list_of_strings])
arabic_value = eval(converted_to_string)
return arabic_value
I am a little bit nervous about this code because at some point I read that eval is dangerous to use in most circumstances as it allows someone to introduce mischief into your system. But I can't figure out another way to evaluate the list returned from the first function. So without having to write a more complex function.
The kids get the conversion function so even if it looks complicated they understand the process of roman numeral conversion and it makes sense. When we have talked about evaluation though I can see they get lost. Thus I am really hoping for some way to evaluate the results of the conversion function that doesn't require too much convoluted code.
Sorry if this is warped, I am so . . .
Is there a way to accomplish what eval does without using eval
Yes, definitely. One option would be to convert the whole thing into an ast tree and parse it yourself (see here for an example).
I am a little bit nervous about this code because at some point I read that eval is dangerous to use in most circumstances as it allows someone to introduce mischief into your system.
This is definitely true. Any time you consider using eval, you need to do some thinking about your particular use-case. The real question is how much do you trust the user and what damage can they do? If you're distributing this as a script and users are only using it on their own computer, then it's really not a problem -- After all, they don't need to inject malicious code into your script to remove their home directory. If you're planning on hosting this on your server, that's a different story entirely ... Then you need to figure out where the string comes from and if there is any way for the user to modify the string in a way that could make it untrusted to run. Hackers are pretty clever1,2 and so hosting something like this on your server is generally not a good idea. (I always assume that the hackers know python WAY better than I do).
1http://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/
2http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
The only implementation of a safe expression evalulator that I've come across is:
https://pypi.org/project/simpleeval/
It supports a lot of basic Python-ish expressions and is quite restricted in what it allows you to do (so you don't blow up the interpreter or do something evil). It uses the python ast module for parsing, and evaluates the result itself.
Example:
from simpleeval import simple_eval
simple_eval("21 + 21")
Then you can extend it and give it access to the parts of your program that you want to:
simple_eval("x + y", names={"x": 22, "y": 48})
or
simple_eval("do_thing(11)", functions={"do_thing": my_callback})
and so on.
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.
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.