Security¶
Build secure applications with defense in depth.
Security Mindset¶
Assume Breach¶
Design systems assuming attackers will get in:
- Minimize blast radius — Limit what compromised components can access
- Defense in depth — Multiple layers of protection
- Least privilege — Only grant necessary permissions
- Zero trust — Verify everything, trust nothing
Threat Modeling¶
Before building, ask:
- What are we building? — Data flows, trust boundaries
- What can go wrong? — STRIDE analysis
- What are we doing about it? — Mitigations
- Did we do a good job? — Validation
STRIDE:
├── Spoofing → Authentication
├── Tampering → Integrity checks
├── Repudiation → Audit logging
├── Info Disclosure → Encryption, access control
├── Denial of Service → Rate limiting, quotas
└── Elevation of Privilege → Authorization
Section Contents¶
| Topic | Description |
|---|---|
| Secrets Management | Environment variables, vaults, rotation |
| Input Validation | Pydantic, Zod, sanitization |
| Authentication | JWT, sessions, MFA |
| Authorization | RBAC, ABAC, permissions |
| OWASP Top 10 | Common vulnerabilities and prevention |
| Security Checklist | Pre-deploy verification |
Quick Wins¶
1. Never Trust User Input¶
# Bad: Direct use
@app.get("/users/{user_id}")
async def get_user(user_id: str):
return await db.execute(f"SELECT * FROM users WHERE id = '{user_id}'")
# Good: Parameterized query with validation
@app.get("/users/{user_id}")
async def get_user(user_id: int): # Type validation
return await db.execute(
select(User).where(User.id == user_id) # ORM parameterizes
)
2. Use Security Headers¶
from fastapi import FastAPI
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware
app = FastAPI()
@app.middleware("http")
async def security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
response.headers["Content-Security-Policy"] = "default-src 'self'"
return response
3. Hash Passwords Properly¶
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
4. Validate Everything¶
from pydantic import BaseModel, EmailStr, Field, field_validator
import re
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(..., min_length=12)
username: str = Field(..., min_length=3, max_length=30)
@field_validator("username")
@classmethod
def username_alphanumeric(cls, v):
if not re.match(r"^[a-zA-Z0-9_]+$", v):
raise ValueError("Username must be alphanumeric")
return v
@field_validator("password")
@classmethod
def password_strength(cls, v):
if not re.search(r"[A-Z]", v):
raise ValueError("Password must contain uppercase")
if not re.search(r"[a-z]", v):
raise ValueError("Password must contain lowercase")
if not re.search(r"\d", v):
raise ValueError("Password must contain digit")
return v
Security Layers¶
┌─────────────────────────────────────────┐
│ Network Security │
│ (Firewall, WAF, DDoS protection) │
├─────────────────────────────────────────┤
│ Transport Security │
│ (TLS, HTTPS, HSTS) │
├─────────────────────────────────────────┤
│ Application Security │
│ (Auth, input validation, rate limits) │
├─────────────────────────────────────────┤
│ Data Security │
│ (Encryption at rest, access control) │
├─────────────────────────────────────────┤
│ Monitoring & Response │
│ (Logging, alerting, incident mgmt) │
└─────────────────────────────────────────┘
Common Mistakes¶
| Mistake | Impact | Fix |
|---|---|---|
| Secrets in code | Credential leak | Environment variables, vaults |
| SQL string concat | SQL injection | Parameterized queries |
| No rate limiting | DoS, brute force | Rate limit all endpoints |
| Verbose errors | Info disclosure | Generic error messages |
| Missing auth checks | Unauthorized access | Auth on every endpoint |
| Client-side validation only | Bypassed easily | Always validate server-side |
Related Documentation¶
- Backend Security — FastAPI security patterns
- OWASP Top 10 — Common web vulnerabilities and prevention strategies