How to Securely Handle Username and Password Input in Python
This guide explains how to prompt for and handle username and password input in Python, emphasizing secure practices. We'll cover:
- Taking username input (which is generally not sensitive).
- Taking password input securely (without echoing to the console).
- Limiting login attempts.
- Important Security Considerations
Basic Username and Password Input
The standard way to handle this is to use input()
for the username (since it's generally not considered sensitive) and getpass.getpass()
for the password (to avoid displaying it on the screen):
import getpass
username = input('Enter your username: ')
print(username) # Only for illustration. Don't normally print usernames.
password = getpass.getpass('Enter your password: ')
print(password) # Only for illustration. In real code, do NOT print passwords
input('Enter your username: ')
: This displays the prompt"Enter your username: "
and waits for the user to type something and press Enter. The entered text (as a string) is returned.getpass.getpass('Enter your password: ')
: This also displays a prompt, but it does not echo the characters the user types to the console. This is crucial for password security. The entered text is returned as a string.
Limiting Login Attempts
To prevent brute-force attacks, it's essential to limit the number of login attempts:
import getpass
attempts = 0
max_attempts = 3
while attempts < max_attempts:
username = input('Enter your username: ')
password = getpass.getpass('Enter your password: ')
if username == 'user123' and password == 'password123':
print('You have successfully logged in.')
break # Exit the loop on successful login
else:
attempts += 1
print(f'Incorrect credentials. You have {max_attempts - attempts} attempts remaining.')
# Optionally, add a short delay here (e.g., time.sleep(1))
# to further slow down brute-force attempts.
else:
# This `else` block runs if the loop completes *without* hitting a `break`.
print("Too many incorrect attempts. Account locked.")
attempts = 0
: Initializes a counter for login attempts.while attempts < max_attempts:
: The loop continues as long as the number of attempts is less than the maximum allowed.if username == ... and password == ...
: This is where you'd actually check the credentials against a database or other secure storage (see Security Considerations below!). Never store passwords in plain text.break
: If the credentials are correct,break
exits thewhile
loop.attempts += 1
: Increments the attempt counter.else
(on thewhile
loop): This is a crucial part of the logic. Theelse
block associated with awhile
(orfor
) loop runs only if the loop completes without encountering abreak
statement. This is how we detect that the user has exhausted all their attempts.- You can also add a delay to further slow down attempts, using the
time.sleep()
function.
Displaying Asterisks (Less Secure, but sometimes useful)
For a slightly better user experience (though not significantly more secure), you can display asterisks (*
) instead of hiding the input completely. Use the pwinput
library for this:
pip install pwinput
import pwinput
password = pwinput.pwinput(prompt='Enter your password: ', mask='*')
print(password) # Only for demonstration; don't print passwords!
pwinput.pwinput(prompt='...', mask='*')
: This function works similarly togetpass.getpass()
, but displays the specifiedmask
character for each character typed.
While this visually obscures the password, it doesn't make it cryptographically secure. An attacker with access to the process's memory could still potentially retrieve the password.
Security Considerations (Very Important)
- Never Store Passwords in Plain Text: This is a fundamental security rule. Always hash passwords using a strong, one-way hashing algorithm (like bcrypt, scrypt, or Argon2) before storing them.
- Salt Passwords: Use a unique, random "salt" for each password before hashing. This prevents attackers from using pre-computed tables of common password hashes (rainbow tables).
- Use a Strong Hashing Algorithm: Avoid MD5 and SHA-1, which are considered cryptographically broken. Use a modern, secure algorithm like:
- bcrypt: A good, widely-used choice.
- scrypt: Designed to be computationally expensive, making brute-force attacks harder.
- Argon2: The winner of the Password Hashing Competition, considered very strong.
- Rate Limiting: Implement rate limiting on your login attempts to slow down brute-force attacks. This is in addition to limiting the number of attempts within a single session.
- Input sanitation: The input from the user should always be validated and sanitized, as anything the user types will be directly passed into your code.
Conclusion
This guide demonstrated how to take username and password input in Python, emphasizing security best practices.
- Use
input()
for usernames andgetpass.getpass()
for passwords. - Limit login attempts to prevent brute-force attacks.
- Most importantly, never store passwords in plain text. Always hash and salt passwords using a strong, modern algorithm.
pwinput
can provide a slightly better user experience, but it does not provide cryptographic security. - Remember to always validate and sanitize user input.