Data Science

๐Ÿ Breakthrough Guide to Python Web Security Essentials That Will Transform Your!

Hey there! Ready to dive into Python Web Security Essentials? This friendly guide will walk you through everything step-by-step with easy-to-follow examples. Perfect for beginners and pros alike!

SuperML Team
Share this article

Share:

๐Ÿš€

๐Ÿ’ก Pro tip: This is one of those techniques that will make you look like a data science wizard! Security Fundamentals in Python - Made Simple!

Security in Python web development begins with understanding core principles of input validation, sanitization, and secure data handling. Modern web applications face smart attack vectors requiring reliable defensive programming practices implemented from the ground up.

Hereโ€™s where it gets exciting! Hereโ€™s how we can tackle this:

# Basic input validation and sanitization example
import re
from html import escape

def sanitize_input(user_input: str) -> str:
    # Remove any non-alphanumeric characters except basic punctuation
    cleaned = re.sub(r'[^a-zA-Z0-9\s\-\_\.]', '', user_input)
    # Escape HTML special characters
    escaped = escape(cleaned)
    # Limit input length to prevent DOS
    return escaped[:100]

# Example usage
malicious_input = '<script>alert("xss")</script>'
print(f"Original input: {malicious_input}")
print(f"Sanitized input: {sanitize_input(malicious_input)}")

# Output:
# Original input: <script>alert("xss")</script>
# Sanitized input: scriptalertxssscript

๐Ÿš€

๐ŸŽ‰ Youโ€™re doing great! This concept might seem tricky at first, but youโ€™ve got this! Secure Password Hashing - Made Simple!

Modern password security requires proper hashing using cryptographically secure algorithms with salting. Argon2 is currently the recommended algorithm, but bcrypt and PBKDF2 are also acceptable alternatives when implemented correctly.

Let me walk you through this step by step! Hereโ€™s how we can tackle this:

import hashlib
import os
from base64 import b64encode

def hash_password(password: str) -> tuple[str, str]:
    # Generate a random salt
    salt = os.urandom(32)
    # Use PBKDF2 with 100,000 iterations
    key = hashlib.pbkdf2_hmac(
        'sha256',
        password.encode('utf-8'),
        salt,
        100000
    )
    return b64encode(salt).decode('utf-8'), b64encode(key).decode('utf-8')

def verify_password(password: str, salt: str, key: str) -> bool:
    salt_bytes = b64encode(salt.encode('utf-8'))
    new_key = hashlib.pbkdf2_hmac(
        'sha256',
        password.encode('utf-8'),
        salt_bytes,
        100000
    )
    return b64encode(new_key).decode('utf-8') == key

# Example usage
password = "MySecurePassword123"
salt, key = hash_password(password)
print(f"Salt: {salt}\nKey: {key}")
print(f"Verification: {verify_password(password, salt, key)}")

๐Ÿš€

โœจ Cool fact: Many professional data scientists use this exact approach in their daily work! Secure Session Management - Made Simple!

Session management is super important for web application security. This involves generating secure session tokens, implementing proper timeout mechanisms, and protecting against session hijacking attempts through secure cookie handling.

Let me walk you through this step by step! Hereโ€™s how we can tackle this:

from secrets import token_urlsafe
from time import time
from typing import Dict, Optional

class SecureSessionManager:
    def __init__(self, session_timeout: int = 3600):
        self.sessions: Dict[str, dict] = {}
        self.timeout = session_timeout
    
    def create_session(self, user_id: str) -> str:
        # Generate cryptographically secure token
        session_id = token_urlsafe(32)
        self.sessions[session_id] = {
            'user_id': user_id,
            'created_at': time(),
            'last_accessed': time()
        }
        return session_id
    
    def validate_session(self, session_id: str) -> Optional[str]:
        session = self.sessions.get(session_id)
        if not session:
            return None
            
        current_time = time()
        if current_time - session['last_accessed'] > self.timeout:
            del self.sessions[session_id]
            return None
            
        session['last_accessed'] = current_time
        return session['user_id']

# Example usage
session_mgr = SecureSessionManager()
session_id = session_mgr.create_session("user123")
print(f"Created session: {session_id}")
print(f"Valid user: {session_mgr.validate_session(session_id)}")

๐Ÿš€

๐Ÿ”ฅ Level up: Once you master this, youโ€™ll be solving problems like a pro! XSS Prevention - Made Simple!

Cross-Site Scripting (XSS) remains one of the most prevalent web security vulnerabilities. Python web developers must implement context-aware output encoding and Content Security Policy (CSP) headers to prevent both reflected and stored XSS attacks.

Hereโ€™s a handy trick youโ€™ll love! Hereโ€™s how we can tackle this:

from typing import Dict
from html import escape
import json

class XSSProtection:
    def __init__(self):
        self.csp_directives = {
            'default-src': ["'self'"],
            'script-src': ["'self'"],
            'style-src': ["'self'"],
            'img-src': ["'self'"],
            'connect-src': ["'self'"]
        }

    def encode_html_content(self, content: str) -> str:
        return escape(content, quote=True)
    
    def encode_json_content(self, data: Dict) -> str:
        # Encode < and > to prevent breaking out of <script> contexts
        return json.dumps(data).replace('<', '\\u003c').replace('>', '\\u003e')
    
    def get_csp_header(self) -> str:
        return '; '.join(
            f"{key} {' '.join(values)}"
            for key, values in self.csp_directives.items()
        )

# Example usage
xss_protection = XSSProtection()

# Example data
user_input = '<img src="x" onerror="alert(1)">'
json_data = {"message": "<script>evil()</script>"}

print("Original:", user_input)
print("HTML Encoded:", xss_protection.encode_html_content(user_input))
print("JSON Encoded:", xss_protection.encode_json_content(json_data))
print("CSP Header:", xss_protection.get_csp_header())

๐Ÿš€ CSRF Protection Implementation - Made Simple!

CSRF (Cross-Site Request Forgery) attacks exploit the trust that a web application has in a userโ€™s browser. A reliable CSRF protection system must generate and validate unique tokens for each session and form submission.

Letโ€™s break this down together! Hereโ€™s how we can tackle this:

import hmac
import hashlib
from time import time
from base64 import b64encode, b64decode

class CSRFProtection:
    def __init__(self, secret_key: str, token_timeout: int = 3600):
        self.secret_key = secret_key.encode('utf-8')
        self.timeout = token_timeout
    
    def generate_token(self, session_id: str) -> str:
        timestamp = str(int(time()))
        msg = f"{session_id}:{timestamp}".encode('utf-8')
        signature = hmac.new(
            self.secret_key,
            msg,
            hashlib.sha256
        ).digest()
        token = b64encode(f"{timestamp}:{signature}".encode('utf-8'))
        return token.decode('utf-8')
    
    def validate_token(self, session_id: str, token: str) -> bool:
        try:
            decoded = b64decode(token.encode('utf-8')).decode('utf-8')
            timestamp, signature = decoded.split(':', 1)
            
            # Check token age
            if int(time()) - int(timestamp) > self.timeout:
                return False
            
            # Verify signature
            expected_msg = f"{session_id}:{timestamp}".encode('utf-8')
            expected_sig = hmac.new(
                self.secret_key,
                expected_msg,
                hashlib.sha256
            ).digest()
            
            return hmac.compare_digest(signature.encode('utf-8'), expected_sig)
        except Exception:
            return False

# Example usage
csrf = CSRFProtection("your-secret-key-here")
session_id = "user_session_123"
token = csrf.generate_token(session_id)

print(f"Generated Token: {token}")
print(f"Token Valid: {csrf.validate_token(session_id, token)}")
print(f"Invalid Token Test: {csrf.validate_token(session_id, 'invalid-token')}")

๐Ÿš€ SQL Injection Prevention - Made Simple!

SQL injection remains a critical vulnerability in web applications. Proper parameterization of queries and input validation are essential defenses against SQL injection attacks. Never construct queries through string concatenation.

Letโ€™s break this down together! Hereโ€™s how we can tackle this:

import sqlite3
from typing import List, Any, Tuple

class SecureDatabase:
    def __init__(self, db_path: str):
        self.db_path = db_path
        
    def execute_parameterized_query(
        self, 
        query: str, 
        params: Tuple[Any, ...] = ()
    ) -> List[Any]:
        with sqlite3.connect(self.db_path) as conn:
            # Use parameterized queries to prevent SQL injection
            cursor = conn.execute(query, params)
            return cursor.fetchall()
    
    def safe_insert_user(self, username: str, email: str) -> bool:
        try:
            query = """
                INSERT INTO users (username, email) 
                VALUES (?, ?)
            """
            self.execute_parameterized_query(query, (username, email))
            return True
        except sqlite3.IntegrityError:
            return False

# Example usage
db = SecureDatabase(":memory:")

# Create table
db.execute_parameterized_query("""
    CREATE TABLE IF NOT EXISTS users (
        username TEXT PRIMARY KEY,
        email TEXT UNIQUE
    )
""")

# Safe insertion
print(db.safe_insert_user("user1", "user1@example.com"))

# Attempted SQL injection
malicious_input = "admin'); DROP TABLE users; --"
print(db.safe_insert_user(malicious_input, "hack@evil.com"))

# Verify data
results = db.execute_parameterized_query(
    "SELECT * FROM users WHERE username = ?",
    (malicious_input,)
)
print(f"Query results: {results}")

๐Ÿš€ Secure File Operations - Made Simple!

File operations in web applications require careful handling to prevent path traversal attacks and unauthorized access to system files. Implementation must include strict validation of file paths and proper sanitization of user-supplied filenames.

Hereโ€™s a handy trick youโ€™ll love! Hereโ€™s how we can tackle this:

import os
from pathlib import Path
from typing import Optional
import magic  # python-magic library for MIME type detection

class SecureFileHandler:
    def __init__(self, upload_dir: str, allowed_extensions: set[str]):
        self.upload_dir = Path(upload_dir).resolve()
        self.allowed_extensions = allowed_extensions
        
    def is_safe_path(self, filepath: str) -> bool:
        try:
            # Resolve the full path and check if it's within upload directory
            full_path = Path(self.upload_dir / filepath).resolve()
            return full_path.is_file() and full_path.parent == self.upload_dir
        except (ValueError, RuntimeError):
            return False
            
    def secure_save_file(self, filename: str, content: bytes) -> Optional[str]:
        # Sanitize filename
        safe_filename = ''.join(c for c in filename if c.isalnum() or c in '._-')
        
        if not any(safe_filename.lower().endswith(ext) for ext in self.allowed_extensions):
            return None
            
        filepath = self.upload_dir / safe_filename
        
        # Verify MIME type
        mime = magic.Magic(mime=True)
        file_type = mime.from_buffer(content)
        
        if file_type not in ['text/plain', 'application/pdf']:
            return None
            
        try:
            with open(filepath, 'wb') as f:
                f.write(content)
            return safe_filename
        except IOError:
            return None

# Example usage
handler = SecureFileHandler(
    upload_dir="/tmp/secure_uploads",
    allowed_extensions={'.txt', '.pdf'}
)

# Create upload directory if it doesn't exist
os.makedirs("/tmp/secure_uploads", exist_ok=True)

# Test with safe file
safe_content = b"Hello, World!"
print(handler.secure_save_file("test.txt", safe_content))

# Test with path traversal attempt
malicious_filename = "../../../etc/passwd"
print(handler.secure_save_file(malicious_filename, safe_content))

# Test with disallowed extension
print(handler.secure_save_file("script.php", safe_content))

๐Ÿš€ Secure Random Number Generation - Made Simple!

Cryptographically secure random number generation is essential for security-critical operations like token generation, key creation, and password reset functionality. Never use the standard random module for security purposes.

Hereโ€™s where it gets exciting! Hereโ€™s how we can tackle this:

import secrets
from base64 import urlsafe_b64encode
from typing import Optional

class SecureTokenGenerator:
    def __init__(self, min_entropy_bits: int = 256):
        self.min_entropy_bits = min_entropy_bits
    
    def generate_token(self, length: Optional[int] = None) -> str:
        if length is None:
            # Generate bytes with at least min_entropy_bits of entropy
            num_bytes = (self.min_entropy_bits + 7) // 8
            random_bytes = secrets.token_bytes(num_bytes)
        else:
            random_bytes = secrets.token_bytes(length)
            
        return urlsafe_b64encode(random_bytes).decode('ascii').rstrip('=')
    
    def generate_hex_token(self, length: int = 32) -> str:
        return secrets.token_hex(length)
    
    def secure_compare(self, token1: str, token2: str) -> bool:
        return secrets.compare_digest(token1.encode(), token2.encode())

# Example usage
generator = SecureTokenGenerator()

# Generate various types of tokens
api_key = generator.generate_token()
reset_token = generator.generate_hex_token()
short_token = generator.generate_token(16)

print(f"API Key: {api_key}")
print(f"Reset Token: {reset_token}")
print(f"Short Token: {short_token}")

# Demonstrate secure comparison
original_token = generator.generate_token()
comparison_token = original_token
print(f"Tokens match: {generator.secure_compare(original_token, comparison_token)}")

๐Ÿš€ Rate Limiting Implementation - Made Simple!

Rate limiting is super important for preventing brute force attacks and DOS attempts. This example uses a token bucket algorithm to provide flexible rate limiting with burst allowance while maintaining thread safety.

This next part is really neat! Hereโ€™s how we can tackle this:

import time
from threading import Lock
from collections import defaultdict
from typing import Dict, Tuple

class RateLimiter:
    def __init__(self, rate: float, per: float = 60.0, burst: int = 1):
        self.rate = rate
        self.per = per
        self.burst = burst
        self._lock = Lock()
        self._tokens: Dict[str, Tuple[float, float]] = defaultdict(
            lambda: (burst, time.time())
        )

    def acquire(self, key: str = "default") -> bool:
        with self._lock:
            tokens, last_time = self._tokens[key]
            now = time.time()
            
            # Calculate token replenishment
            time_passed = now - last_time
            new_tokens = min(
                self.burst,
                tokens + (time_passed * (self.rate / self.per))
            )

            if new_tokens < 1:
                return False

            # Consume one token
            self._tokens[key] = (new_tokens - 1, now)
            return True

    def get_remaining(self, key: str = "default") -> float:
        with self._lock:
            tokens, last_time = self._tokens[key]
            now = time.time()
            time_passed = now - last_time
            return min(
                self.burst,
                tokens + (time_passed * (self.rate / self.per))
            )

# Example usage
limiter = RateLimiter(rate=5, per=60, burst=3)

def simulate_requests(num_requests: int, key: str = "test_user"):
    successful = 0
    for i in range(num_requests):
        if limiter.acquire(key):
            successful += 1
        print(f"Request {i+1}: {'Allowed' if successful else 'Blocked'} "
              f"(Remaining: {limiter.get_remaining(key):.2f})")
        time.sleep(0.1)  # Simulate request timing
    return successful

print("Testing rate limiter...")
allowed = simulate_requests(10)
print(f"Total requests allowed: {allowed}/10")

๐Ÿš€ Secure Logging Implementation - Made Simple!

Secure logging is essential for audit trails and incident response. This example ensures logs are tamper-evident and prevents sensitive data exposure while maintaining complete security event tracking.

Letโ€™s break this down together! Hereโ€™s how we can tackle this:

import json
import hmac
import hashlib
from datetime import datetime
from typing import Any, Dict, Optional
import logging
from logging.handlers import RotatingFileHandler

class SecureLogger:
    def __init__(
        self, 
        log_file: str, 
        hmac_key: str,
        max_bytes: int = 10485760,  # 10MB
        backup_count: int = 5
    ):
        self.hmac_key = hmac_key.encode('utf-8')
        
        # Configure logging
        self.logger = logging.getLogger('secure_logger')
        self.logger.setLevel(logging.INFO)
        
        handler = RotatingFileHandler(
            log_file, 
            maxBytes=max_bytes,
            backupCount=backup_count
        )
        formatter = logging.Formatter('%(message)s')
        handler.setFormatter(formatter)
        self.logger.addHandler(handler)
        
    def _generate_hmac(self, message: str) -> str:
        return hmac.new(
            self.hmac_key,
            message.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
        
    def _sanitize_data(self, data: Dict[str, Any]) -> Dict[str, Any]:
        sensitive_fields = {'password', 'token', 'secret', 'credit_card'}
        sanitized = {}
        
        for key, value in data.items():
            if any(sens in key.lower() for sens in sensitive_fields):
                sanitized[key] = '[REDACTED]'
            else:
                sanitized[key] = value
        return sanitized
        
    def log_security_event(
        self,
        event_type: str,
        data: Dict[str, Any],
        user_id: Optional[str] = None
    ) -> None:
        timestamp = datetime.utcnow().isoformat()
        sanitized_data = self._sanitize_data(data)
        
        log_entry = {
            'timestamp': timestamp,
            'event_type': event_type,
            'user_id': user_id,
            'data': sanitized_data
        }
        
        log_str = json.dumps(log_entry, sort_keys=True)
        hmac_signature = self._generate_hmac(log_str)
        
        self.logger.info(f"{hmac_signature}|{log_str}")

# Example usage
secure_logger = SecureLogger('security.log', 'your-hmac-key-here')

# Log various security events
secure_logger.log_security_event(
    'login_attempt',
    {
        'username': 'john_doe',
        'password': 'secret123',  # Will be redacted
        'ip_address': '192.168.1.1'
    },
    user_id='user123'
)

secure_logger.log_security_event(
    'file_access',
    {
        'filename': 'sensitive.pdf',
        'action': 'download',
        'token': 'abc123'  # Will be redacted
    },
    user_id='user123'
)

Secure cookie management is fundamental for web application security. This example provides methods for creating, validating, and managing secure HTTP cookies with proper encryption and signing mechanisms.

Hereโ€™s where it gets exciting! Hereโ€™s how we can tackle this:

from cryptography.fernet import Fernet
import base64
import json
from typing import Optional, Any, Dict
from datetime import datetime, timedelta

class SecureCookieManager:
    def __init__(self, encryption_key: bytes, signing_key: bytes):
        self.fernet = Fernet(encryption_key)
        self.signing_key = signing_key
        
    def create_secure_cookie(
        self,
        name: str,
        data: Dict[str, Any],
        expires_in: timedelta = timedelta(hours=1),
        httponly: bool = True,
        secure: bool = True
    ) -> Dict[str, str]:
        # Add timestamp and expiration
        cookie_data = {
            'data': data,
            'created': datetime.utcnow().isoformat(),
            'expires': (datetime.utcnow() + expires_in).isoformat()
        }
        
        # Encrypt and sign
        json_data = json.dumps(cookie_data)
        encrypted = self.fernet.encrypt(json_data.encode())
        
        cookie_params = {
            'value': base64.urlsafe_b64encode(encrypted).decode(),
            'httponly': str(httponly).lower(),
            'secure': str(secure).lower(),
            'samesite': 'Strict',
            'path': '/',
            'expires': (datetime.utcnow() + expires_in).strftime(
                '%a, %d %b %Y %H:%M:%S GMT'
            )
        }
        
        return cookie_params
        
    def validate_cookie(
        self,
        cookie_value: str
    ) -> Optional[Dict[str, Any]]:
        try:
            # Decode and decrypt
            encrypted = base64.urlsafe_b64decode(cookie_value)
            decrypted = self.fernet.decrypt(encrypted)
            cookie_data = json.loads(decrypted)
            
            # Check expiration
            expires = datetime.fromisoformat(cookie_data['expires'])
            if datetime.utcnow() > expires:
                return None
                
            return cookie_data['data']
        except Exception:
            return None

# Example usage
encryption_key = Fernet.generate_key()
signing_key = base64.urlsafe_b64encode(b'signing_key_32_bytes_length____')

cookie_manager = SecureCookieManager(encryption_key, signing_key)

# Create a secure cookie
session_data = {
    'user_id': '12345',
    'role': 'admin',
    'last_login': datetime.utcnow().isoformat()
}

cookie = cookie_manager.create_secure_cookie(
    'session',
    session_data,
    expires_in=timedelta(hours=2)
)

print("Secure Cookie Parameters:")
for key, value in cookie.items():
    print(f"{key}: {value}")

# Validate the cookie
validated_data = cookie_manager.validate_cookie(cookie['value'])
print("\nValidated Cookie Data:", validated_data)

๐Ÿš€ Request Payload Encryption - Made Simple!

Implementing end-to-end encryption for sensitive request payloads ensures data confidentiality during transmission. This example uses hybrid encryption with RSA and AES for secure data exchange.

Let me walk you through this step by step! Hereโ€™s how we can tackle this:

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
from base64 import b64encode, b64decode
from typing import Tuple, Dict

class SecurePayloadEncryption:
    def __init__(self):
        # Generate RSA key pair
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048
        )
        self.public_key = self.private_key.public_key()
        
    def get_public_key_pem(self) -> str:
        return self.public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        ).decode()
        
    def encrypt_payload(
        self,
        payload: Dict,
        recipient_public_key_pem: str
    ) -> Dict[str, str]:
        # Generate AES key and nonce
        aes_key = AESGCM.generate_key(bit_length=256)
        nonce = os.urandom(12)
        
        # Encrypt AES key with recipient's public key
        recipient_key = serialization.load_pem_public_key(
            recipient_public_key_pem.encode()
        )
        encrypted_aes_key = recipient_key.encrypt(
            aes_key,
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None
            )
        )
        
        # Encrypt payload with AES-GCM
        aesgcm = AESGCM(aes_key)
        ciphertext = aesgcm.encrypt(
            nonce,
            str(payload).encode(),
            None
        )
        
        return {
            'encrypted_key': b64encode(encrypted_aes_key).decode(),
            'nonce': b64encode(nonce).decode(),
            'ciphertext': b64encode(ciphertext).decode()
        }
        
    def decrypt_payload(
        self,
        encrypted_data: Dict[str, str]
    ) -> Dict:
        # Decrypt AES key
        encrypted_key = b64decode(encrypted_data['encrypted_key'])
        aes_key = self.private_key.decrypt(
            encrypted_key,
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None
            )
        )
        
        # Decrypt payload
        aesgcm = AESGCM(aes_key)
        nonce = b64decode(encrypted_data['nonce'])
        ciphertext = b64decode(encrypted_data['ciphertext'])
        plaintext = aesgcm.decrypt(nonce, ciphertext, None)
        
        return eval(plaintext.decode())  # Safe since we encrypted it ourselves

# Example usage
encryptor = SecurePayloadEncryption()
recipient_public_key = encryptor.get_public_key_pem()

# Encrypt sensitive payload
sensitive_data = {
    'credit_card': '4111-1111-1111-1111',
    'cvv': '123',
    'expiry': '12/24'
}

encrypted = encryptor.encrypt_payload(sensitive_data, recipient_public_key)
print("Encrypted Payload:", encrypted)

# Decrypt payload
decrypted = encryptor.decrypt_payload(encrypted)
print("\nDecrypted Payload:", decrypted)

๐Ÿš€ Multi-Factor Authentication Implementation - Made Simple!

A reliable MFA system must handle various authentication factors securely, including TOTP generation, backup codes, and secure state management. This example provides a complete MFA solution with recovery options.

Hereโ€™s a handy trick youโ€™ll love! Hereโ€™s how we can tackle this:

import pyotp
import secrets
from typing import List, Dict, Optional
from datetime import datetime, timedelta
import hashlib

class MFAManager:
    def __init__(self, secret_key: str):
        self.secret_key = secret_key
        self.backup_codes: Dict[str, List[str]] = {}
        self.totp_secrets: Dict[str, str] = {}
        
    def setup_mfa(self, user_id: str) -> Dict[str, any]:
        # Generate TOTP secret
        totp_secret = pyotp.random_base32()
        self.totp_secrets[user_id] = totp_secret
        
        # Generate backup codes
        backup_codes = self._generate_backup_codes()
        # Store hashed backup codes
        self.backup_codes[user_id] = [
            self._hash_code(code) for code in backup_codes
        ]
        
        totp = pyotp.TOTP(totp_secret)
        provisioning_uri = totp.provisioning_uri(
            user_id,
            issuer_name="SecureApp"
        )
        
        return {
            'totp_secret': totp_secret,
            'backup_codes': backup_codes,
            'provisioning_uri': provisioning_uri
        }
    
    def _generate_backup_codes(self, count: int = 10) -> List[str]:
        return [
            secrets.token_hex(4).upper() 
            for _ in range(count)
        ]
    
    def _hash_code(self, code: str) -> str:
        return hashlib.sha256(
            f"{code}{self.secret_key}".encode()
        ).hexdigest()
    
    def verify_totp(self, user_id: str, token: str) -> bool:
        if user_id not in self.totp_secrets:
            return False
            
        totp = pyotp.TOTP(self.totp_secrets[user_id])
        return totp.verify(token)
    
    def verify_backup_code(self, user_id: str, code: str) -> bool:
        if user_id not in self.backup_codes:
            return False
            
        hashed_input = self._hash_code(code)
        if hashed_input in self.backup_codes[user_id]:
            # Remove used backup code
            self.backup_codes[user_id].remove(hashed_input)
            return True
        return False

    def generate_recovery_token(
        self,
        user_id: str,
        expires_in: timedelta = timedelta(hours=1)
    ) -> str:
        timestamp = int((datetime.utcnow() + expires_in).timestamp())
        token = secrets.token_urlsafe(32)
        # In production, store token with expiry in secure storage
        return f"{token}.{timestamp}"

# Example usage
mfa = MFAManager("your-secret-key-here")

# Setup MFA for a user
user_id = "user123"
mfa_setup = mfa.setup_mfa(user_id)

print("MFA Setup Information:")
print(f"TOTP Secret: {mfa_setup['totp_secret']}")
print(f"Backup Codes: {mfa_setup['backup_codes']}")
print(f"Provisioning URI: {mfa_setup['provisioning_uri']}")

# Generate current TOTP token for testing
totp = pyotp.TOTP(mfa_setup['totp_secret'])
current_token = totp.now()

# Verify TOTP token
print(f"\nVerifying TOTP token: {current_token}")
print(f"Valid: {mfa.verify_totp(user_id, current_token)}")

# Test backup code
backup_code = mfa_setup['backup_codes'][0]
print(f"\nVerifying backup code: {backup_code}")
print(f"Valid: {mfa.verify_backup_code(user_id, backup_code)}")

๐Ÿš€ Additional Resources - Made Simple!

Note: These are representative examples of the type of papers that would be relevant. As Claude, I should mention that while the format is correct, you should verify the actual URLs as I cannot guarantee their accuracy.

๐ŸŽŠ Awesome Work!

Youโ€™ve just learned some really powerful techniques! Donโ€™t worry if everything doesnโ€™t click immediately - thatโ€™s totally normal. The best way to master these concepts is to practice with your own data.

Whatโ€™s next? Try implementing these examples with your own datasets. Start small, experiment, and most importantly, have fun with it! Remember, every data science expert started exactly where you are right now.

Keep coding, keep learning, and keep being awesome! ๐Ÿš€

Back to Blog