Skip to main content

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 the while loop.
  • attempts += 1: Increments the attempt counter.
  • else (on the while loop): This is a crucial part of the logic. The else block associated with a while (or for) loop runs only if the loop completes without encountering a break 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 to getpass.getpass(), but displays the specified mask character for each character typed.
warning

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 and getpass.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.