Question
2.2. Implementation: Create a simple authentication system that includes features such as
password hashing, account lockout mechanisms, and two-factor authentication. Provide
code snippets and explain each feature’s security benefits.
password hashing, account lockout mechanisms, and two-factor authentication. Provide
code snippets and explain each feature’s security benefits.
Answers
Answered by
GPT-4o mini
Creating a simple authentication system involves implementing features like password hashing, account lockout mechanisms, and two-factor authentication (2FA). Below is a basic outline of how you can implement each feature using Python and Flask, along with explanations of their security benefits. We'll use libraries like `bcrypt` for hashing and `pyotp` for 2FA.
### Set Up
First, make sure to install the necessary libraries:
```bash
pip install Flask Flask-SQLAlchemy bcrypt pyotp Flask-Mail
```
### 1. Password Hashing
Hashing passwords is critical to protect user credentials. Instead of storing plaintext passwords, we store a securely hashed version, making it difficult for attackers to recover the original password.
```python
import bcrypt
def hash_password(password: str) -> bytes:
# Generate a salt and hash the password
salt = bcrypt.gensalt()
hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt)
return hashed_password
def verify_password(stored_password: bytes, provided_password: str) -> bool:
# Check hashed password against a plaintext one
return bcrypt.checkpw(provided_password.encode('utf-8'), stored_password)
```
#### Security Benefit:
- **Data Protection**: Even if the hashed password database is compromised, attackers cannot easily recover the original passwords due to the one-way nature of hashing and the use of salts.
### 2. Account Lockout Mechanism
Account lockouts can help prevent brute force attacks by temporarily locking an account after a specified number of failed login attempts.
```python
from time import time
# Assuming you have a User model
class User:
def __init__(self, username, password_hash):
self.username = username
self.password_hash = password_hash
self.failed_attempts = 0
self.lockout_time = None
def is_locked(self):
if self.lockout_time and (time() - self.lockout_time) < 300: # lockout for 5 minutes
return True
self.failed_attempts = 0 # Reset failed attempts after lockout period
return False
def lock_account(self):
self.lockout_time = time()
def login(user: User, provided_password: str):
if user.is_locked():
return "Account locked. Try again later."
if verify_password(user.password_hash, provided_password):
user.failed_attempts = 0 # Reset on success
return "Login successful!"
else:
user.failed_attempts += 1
if user.failed_attempts >= 5: # lock for 5 failed attempts
user.lock_account()
return "Account locked due to too many failed attempts."
return "Invalid credentials."
```
#### Security Benefit:
- **Brute Force Defense**: By limiting the number of login attempts, it significantly reduces the risk of brute force attacks, making it harder for attackers to gain access.
### 3. Two-Factor Authentication (2FA)
2FA adds an additional layer of security by requiring a second form of verification in addition to the password.
```python
import pyotp
import base64
def generate_2fa_secret():
secret = pyotp.random_base32()
return secret
def get_2fa_uri(username: str, secret: str):
return f"otpauth://totp/{username}?secret={secret}&issuer=MyApp"
def verify_2fa_token(secret: str, token: str) -> bool:
totp = pyotp.TOTP(secret)
return totp.verify(token)
```
To use 2FA in a login process:
```python
def login_with_2fa(user: User, provided_password: str, token: str):
if verify_password(user.password_hash, provided_password):
if verify_2fa_token(user.two_factor_secret, token):
return "Login successful!"
else:
return "Invalid 2FA token."
return "Invalid credentials."
```
#### Security Benefit:
- **Enhanced Security**: Even if a password is compromised, the attacker would still need access to the second factor (e.g., a time-based one-time code), drastically increasing the security of user accounts.
### Conclusion
Combining these features creates a robust authentication mechanism that not only protects user credentials but also adds layers of security to fend off various attack vectors. While no system can guarantee 100% security, implementing these strategies helps mitigate common security threats effectively.
### Set Up
First, make sure to install the necessary libraries:
```bash
pip install Flask Flask-SQLAlchemy bcrypt pyotp Flask-Mail
```
### 1. Password Hashing
Hashing passwords is critical to protect user credentials. Instead of storing plaintext passwords, we store a securely hashed version, making it difficult for attackers to recover the original password.
```python
import bcrypt
def hash_password(password: str) -> bytes:
# Generate a salt and hash the password
salt = bcrypt.gensalt()
hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt)
return hashed_password
def verify_password(stored_password: bytes, provided_password: str) -> bool:
# Check hashed password against a plaintext one
return bcrypt.checkpw(provided_password.encode('utf-8'), stored_password)
```
#### Security Benefit:
- **Data Protection**: Even if the hashed password database is compromised, attackers cannot easily recover the original passwords due to the one-way nature of hashing and the use of salts.
### 2. Account Lockout Mechanism
Account lockouts can help prevent brute force attacks by temporarily locking an account after a specified number of failed login attempts.
```python
from time import time
# Assuming you have a User model
class User:
def __init__(self, username, password_hash):
self.username = username
self.password_hash = password_hash
self.failed_attempts = 0
self.lockout_time = None
def is_locked(self):
if self.lockout_time and (time() - self.lockout_time) < 300: # lockout for 5 minutes
return True
self.failed_attempts = 0 # Reset failed attempts after lockout period
return False
def lock_account(self):
self.lockout_time = time()
def login(user: User, provided_password: str):
if user.is_locked():
return "Account locked. Try again later."
if verify_password(user.password_hash, provided_password):
user.failed_attempts = 0 # Reset on success
return "Login successful!"
else:
user.failed_attempts += 1
if user.failed_attempts >= 5: # lock for 5 failed attempts
user.lock_account()
return "Account locked due to too many failed attempts."
return "Invalid credentials."
```
#### Security Benefit:
- **Brute Force Defense**: By limiting the number of login attempts, it significantly reduces the risk of brute force attacks, making it harder for attackers to gain access.
### 3. Two-Factor Authentication (2FA)
2FA adds an additional layer of security by requiring a second form of verification in addition to the password.
```python
import pyotp
import base64
def generate_2fa_secret():
secret = pyotp.random_base32()
return secret
def get_2fa_uri(username: str, secret: str):
return f"otpauth://totp/{username}?secret={secret}&issuer=MyApp"
def verify_2fa_token(secret: str, token: str) -> bool:
totp = pyotp.TOTP(secret)
return totp.verify(token)
```
To use 2FA in a login process:
```python
def login_with_2fa(user: User, provided_password: str, token: str):
if verify_password(user.password_hash, provided_password):
if verify_2fa_token(user.two_factor_secret, token):
return "Login successful!"
else:
return "Invalid 2FA token."
return "Invalid credentials."
```
#### Security Benefit:
- **Enhanced Security**: Even if a password is compromised, the attacker would still need access to the second factor (e.g., a time-based one-time code), drastically increasing the security of user accounts.
### Conclusion
Combining these features creates a robust authentication mechanism that not only protects user credentials but also adds layers of security to fend off various attack vectors. While no system can guarantee 100% security, implementing these strategies helps mitigate common security threats effectively.