7 min read
ā¢Question 41 of 41hardPython Security Best Practices
Writing secure Python code.
Security Best Practices
Input Validation
code.pyPython
import re
from typing import Optional
def validate_email(email: str) -> bool:
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
def validate_integer(value: str, min_val: int, max_val: int) -> Optional[int]:
try:
num = int(value)
if min_val <= num <= max_val:
return num
except ValueError:
pass
return None
# Never use eval with user input!
# BAD: eval(user_input)
# GOOD: Use ast.literal_eval for safe parsing
import ast
data = ast.literal_eval("{'key': 'value'}")SQL Injection Prevention
code.pyPython
import sqlite3
# BAD - SQL injection vulnerable
def get_user_bad(user_id):
query = f"SELECT * FROM users WHERE id = {user_id}"
cursor.execute(query)
# GOOD - Parameterized query
def get_user_good(user_id):
query = "SELECT * FROM users WHERE id = ?"
cursor.execute(query, (user_id,))Password Handling
code.pyPython
import bcrypt
import secrets
# Hashing passwords
def hash_password(password: str) -> bytes:
salt = bcrypt.gensalt()
return bcrypt.hashpw(password.encode(), salt)
def verify_password(password: str, hashed: bytes) -> bool:
return bcrypt.checkpw(password.encode(), hashed)
# Generating secure tokens
token = secrets.token_urlsafe(32)
api_key = secrets.token_hex(16)File Operations
code.pyPython
import os
# Prevent path traversal
def safe_join(base_dir: str, user_path: str) -> str:
# Resolve to absolute path
base = os.path.abspath(base_dir)
path = os.path.abspath(os.path.join(base, user_path))
# Ensure path is within base directory
if not path.startswith(base):
raise ValueError("Path traversal attempt detected")
return path
# Safe file reading
def read_user_file(filename: str):
safe_path = safe_join("/app/uploads", filename)
with open(safe_path, "r") as f:
return f.read()Environment Variables
code.pyPython
import os
# Never hardcode secrets
# BAD
api_key = "sk_live_xxx"
# GOOD
api_key = os.environ.get("API_KEY")
if not api_key:
raise ValueError("API_KEY not set")