
Security Best Practices: Hashing, Salts, and Secrets
Protect your data. Learn the essential security patterns for handling passwords, managing secrets, and securing your FastAPI code against common vulnerabilities.
Security Best Practices: Hashing, Salts, and Secrets
Security is not a feature you "Add" at the end; it is a foundation you build upon. A single data breach can destroy a company's reputation and financial stability.
In this lesson, we learn how to protect the most sensitive part of our system: the User's identity and secrets.
1. Password Hashing (Never store raw text!)
You must never store a user's password as plain text in your database. If an attacker gains access to your database, they immediately have every user's credentials.
The Solution: One-way Hashing
We use algorithms like Bcrypt or Argon2.
- Hashing: A function that turns a password into a scrambled string that cannot be reversed.
- Salting: Adding a unique, random string to every password before hashing it. This prevents "Rainbow Table" attacks (where attackers pre-calculate hashes for common passwords).
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def get_password_hash(password):
return pwd_context.hash(password)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
2. Secrets Management
Your API likely needs a SECRET_KEY for JWTs and an API_KEY for services like Stripe.
- Rule #1: Never hard-code secrets in your Python files.
- Rule #2: Never commit secrets to Git.
The Solution: Environment Variables
Use .env files locally and "Secret Managers" (like AWS Secrets Manager or Vault) in production. Pydantic's BaseSettings makes this effortless.
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
secret_key: str
database_url: str
class Config:
env_file = ".env"
settings = Settings()
3. Rate Limiting
Even a secure API can be taken down by a Brute Force attack (trying 1,000 passwords a second).
- Rate Limiting is the process of limiting how many requests a single IP address can make in a certain timeframe.
- Tool:
slowapiis a popular library for adding rate limiting to FastAPI.
4. SQL Injection and XSS
FastAPI protects you from many common web attacks by default:
- SQL Injection: Using SQLModel/SQLAlchemy automatically "Escapes" data so attackers can't run malicious SQL.
- XSS: FastAPI's automatic JSON serialization prevents many types of script injection attacks.
Visualizing Password Verification
graph TD
A["User enters 'mypassword123'"] --> B["API receives plain text"]
B --> C["Fetch Hash from DB: '$2b$12$...'"]
C --> D["Bcrypt: Hash('mypassword123') matches Hash from DB?"]
D -- "Yes" --> E["Login Success"]
D -- "No" --> F["Login Fail (401)"]
Summary
- Bcrypt: Use it for all password storage.
- Environment Variables: The ONLY place for keys and secrets.
- Rate Limiting: Essential to prevent brute-force and DDoS attacks.
- Framework Defaults: FastAPI + Pydantic + SQLModel provides a "Secure by Default" experience.
In the next lesson, we’ll look at Input Sanitization and Resource Protection.
Exercise: The Secret Leak
You accidentally committed your .env file to a public GitHub repository.
- Is it enough to just delete the file from the repo and commit again?
- What are the three steps you must take immediately to secure your system?