it’s late at night, and somewhere in a dimly lit room, clicks from a keyboard can be heard. Its someone behind a desk typing away, attempting to gain access to your personal accounts.
Their tool of choice? A simple text file.
Rockyou.txt
RockYou was a company that developed widgets for MySpace and implemented applications for various social networks and Facebook. In 2009 following a security breach at RockYou that exposed millions of real user passwords (In Plain text!).
The exposed passwords were compiled into a “Wordlist”, now known as the RockYou.txt file. A word list famous in the world of cybersecurity.
With this word list in hand, anyone with a little bit of knowledge of the command line and a few prebuilt tools like Johntheripper, Hashcat or Hydra can perform brute force attacks to crack passwords at an alarming rate.
Exploiting the all-too-common human habit of choosing simple and memorable passwords that are unfortunately also simple to guess.
If your password is “password123” or something equally easy to guess, it might as well be on a billboard for threat actors to see. The strength of your password can be the thin line between your personal security and vulnerability.
Current password advice almost begs users to create identical passwords. Things like requiring a number, a capital letter or a special character are useless. The majority of users will just capitalize the first letter put a “1” and a “!” on the end of their password and call it a day. Sure this can defeat a dictionary attack but folding instantly to a password dictionary.
This brings us to the reason for today’s post: building a Python-based password strength checker. By understanding and using such tools, you can ensure that your passwords are robust enough to stand up against common and advanced custom Wordlists & Rule sets that would be used to crack the weakest of passwords.
Step 1: Setting Up Your Python Environment
Before we can start coding our password strength checker, make sure you have Python installed on your machine. For this tutorial, we’ll be using Python 3. If you haven’t already, you can download it from the official Python website. Additionally, we’ll use a few libraries to help us handle data and perform checks efficiently. You can install them using pip:
pip install numpy pandas
Step 2: Understanding What Makes a Password Strong
A strong password is your first line of defense against potential security breaches. Here are the key characteristics of a strong password:
- Length: Aim for at least 12 characters.
- Complexity: Include numbers, symbols, and both uppercase and lowercase letters.
- Unpredictability: Avoid common words and phrases, sequential letters and numbers, and repeated characters.
Step 3: Implementing the Password Strength Checker
Now, let’s get to the fun part—coding our tool. We will create a function that checks a password against these criteria and rates its strength.
We are going to start by opening the text editor of our choice anything you like can work, I will be using nano, but you can write and save it in something as simple as notepad (mac) text edit (windows).
nano password_checker.py
The first thing we are going to do is check for our password against the earlier topic of this post rockyou.txt.
import sys
import re
- Importing Necessary Modules:
import sys
: This imports thesys
module, which provides access to some variables used or maintained by the Python interpreter and to functions that interact strongly with the interpreter. It’s used here for accessing command-line arguments.import re
: This imports there
module, which provides support for regular expressions in Python. Regular expressions are used for pattern matching, which can be useful for password validation.
def load_compromised_passwords(file_path):
try:
with open(file_path, 'r', encoding='latin-1') as file:
return set(password.strip() for password in file)
except FileNotFoundError:
print("rockyou.txt file not found. Please ensure it's in the correct path.")
return set()
2. Function to Load Compromised Passwords
The load_compromised_passwords
function reads a file containing compromised passwords and returns them as a set for fast lookups:
file_path
: Parameter specifying the location of the password file.- Tries to open the specified file and read passwords line by line, stripping any whitespace and adding them to a set.
- Handles the
FileNotFoundError
if the specified file is not found and notifies the user.
def check_password_strength(password, compromised_passwords):
issues = []
if password in compromised_passwords:
issues.append('This password is compromised. Please choose a different one.')
if issues:
return 'Weak:\n' + '\n'.join(issues)
else:
return 'Strong: Your password is well-secured!'
3. Function to Check Password Strength
The check_password_strength
function assesses the security of a provided password:
password
: The password to be checked.compromised_passwords
: A set of compromised passwords loaded previously.- Checks if the password is in the set of compromised passwords and if so, adds a corresponding message to the
issues
list. - Returns a formatted string indicating whether the password is “Strong” or “Weak” along with the reason
if len(sys.argv) > 1:
compromised_passwords = load_compromised_passwords('/usr/share/wordlists/rockyou.txt') # Ensure the correct path
print(check_password_strength(sys.argv[1], compromised_passwords))
else:
print("Please provide a password to check.")
4. Main Script Logic
This part of the script executes when run directly from the command line:
- Checks if a password has been provided as a command-line argument.
- If a password is provided, it loads the compromised passwords from the specified path (
/usr/share/wordlists/rockyou.txt
) and checks the strength of the provided password. - If no password is provided, it prompts the user to provide one.
We can actually test our password checker right now to see if our password is found in the Rockyou Wordlist.
Most complicated part of our checker is finished
Moving on with the rest of our password checker we are going to add conditional statements that it will check for
- Password length
- Case checking (for both upper and lower case letters)
- Check for numbers
- Check for special charachters / symbols
- Common Password Paterns
Adding a check for password length
if len(password) < 12:
issues.append('Your password must be at least 12 characters long.')
Explanation:
- This line checks if the password length is less than 12 characters.
- Short passwords are easier to crack using brute-force methods; therefore, a minimum length of 12 characters is often recommended to increase security.
- If the password is too short, a message is added to the
issues
list.
This is easy to add and so will be the following checks for password complexity.
We can again run our script and see if our new check for password length is working
Check for Lowercase Letters
if not re.search("[a-z]", password):
issues.append('Your password needs lowercase letters.')
- Uses a regular expression (
[a-z]
) to check if there is at least one lowercase letter in the password. - Lowercase letters are a basic component of password complexity, adding to the number of possible combinations and making the password harder to guess.
Check for Uppercase Letters
if not re.search("[A-Z]", password):
issues.append('Your password needs uppercase letters.')
Explanation:
- Similar to the lowercase check, this line uses a regular expression (
[A-Z]
) to ensure there is at least one uppercase letter. - Uppercase letters increase the complexity and security of the password
Check for Numbers
if not re.search("[0-9]", password):
issues.append('Your password needs at least one number.')
Explanation:
- Checks for the presence of digits (
[0-9]
) in the password. - Including numbers enhances password strength by expanding the character set used, thereby increasing the effort needed for a successful brute-force attack
Check for Symbols
if not re.search("[!@#$%^&*(),.?\":{}|<>]", password):
issues.append('Your password needs at least one symbol.')
Explanation:
- This regex searches for any commonly used special characters.
- Symbols add another layer of complexity to passwords, significantly improving their resistance to cracking attempts.
Checking for Common Patterns
if re.search(r'^[A-Z][a-z]+[0-9]+[!@#$%^&*()]$', password):
issues.append('Your password follows a common pattern and might be easily guessed.')
Explanation:
"[A-Z]"
matches any single uppercase letter from ‘A’ to ‘Z’. This ensures the password starts with an uppercase letter."[a-z]+"
matches one or more lowercase letters following the initial uppercase letter."[0-9]+"
matches one or more numeric characters following the lowercase letters."[!@#$%^&*()]"
matches exactly one of the specified symbols at the end of the password.- Usage: This regex checks if the password strictly adheres to this sequence, which might be commonly used and easier to guess than more randomized combinations. If this pattern is detected, an issue is logged to suggest avoiding such predictable structures.
Suggesting the Addition of Symbols
if re.match(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{12,}$", password) and not re.search("[!@#$%^&*(),.?\":{}|<>]", password):
issues.append('Try adding symbols to increase strength.')
"(?=.*[a-z])"
ensures at least one lowercase letter exists anywhere in the password."(?=.*[A-Z])"
ensures at least one uppercase letter exists anywhere in the password."(?=.*\d)"
ensures at least one digit exists anywhere in the password."[a-zA-Z\d]{12,}"
matches a sequence of 12 or more characters that can be uppercase letters, lowercase letters, or digits.- Usage: This regex is used to confirm the password includes a mix of uppercase, lowercase, and numeric characters and is of sufficient length. If all these conditions are met but the password still lacks any special characters (
"[!@#$%^&*(),.?\":{}|<>]"
), it suggests adding symbols to further enhance the password’s strength.
This is what our code should look like now after adding out conditional statements.
import sys
import re
def load_compromised_passwords(file_path):
try:
with open(file_path, 'r', encoding='latin-1') as file:
return set(password.strip() for password in file)
except FileNotFoundError:
print("rockyou.txt file not found. Please ensure it's in the correct path.")
return set()
def check_password_strength(password, compromised_passwords):
issues = []
if password in compromised_passwords:
issues.append('Your password is too common and has been exposed in breaches.')
if len(password) < 12:
issues.append('Your password must be at least 12 characters long.')
if not re.search("[a-z]", password):
issues.append('Your password needs lowercase letters.')
if not re.search("[A-Z]", password):
issues.append('Your password needs uppercase letters.')
if not re.search("[0-9]", password):
issues.append('Your password needs at least one number.')
if not re.search("[!@#$%^&*(),.?\":{}|<>]", password):
issues.append('Your password needs at least one symbol.')
if re.search(r'^[A-Z][a-z]+[0-9]+[!@#$%^&*()]$', password):
issues.append('Your password follows a common pattern and might be easily guessed.')
if re.match(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{12,}$", password) and not re.search("[!@#$%^&*(),.?\":{}|<>]", password):
issues.append('Try adding symbols to increase strength.')
if issues:
return 'Weak:\n' + '\n'.join(issues)
else:
return 'Strong: Your password is well-secured!'
if len(sys.argv) > 1:
compromised_passwords = load_compromised_passwords('/usr/share/wordlists/rockyou.txt') # Path to your rockyou.txt file
print(check_password_strength(sys.argv[1], compromised_passwords))
else:
print("Please provide a password to check.")
Checking to make sure we have a secure password using our new python password checker
Thank you for reading!
Thank you for following along as we explored the development of a Python-based password strength checker. By jumping into the fundamentals of password security and leveraging Python’s capabilities, we’ve taken another step towards increasing our online privacy and security.
We’re not done yet and in a future post I will go over the hint shared in the images above with password_gen.py
If you would like to check if you may have a password that has been leaked in a data breach like the Rockyou data breach you can visit haveibeenpwned