Security Design Patterns
Security design patterns are reusable solutions to common security problems. Using proven patterns reduces the risk of introducing vulnerabilities through custom implementations.
Authentication Patterns
Token-Based Authentication (JWT)
Stateless authentication using signed tokens. Server validates token signature without database lookup.
✓ Scalable • ✓ Stateless • ⚠ Token revocation complexity
- • Use short expiration times (15-60 minutes)
- • Implement refresh token rotation
- • Store tokens securely (HttpOnly cookies preferred)
- • Validate all claims (exp, iat, iss, aud)
Session-Based Authentication
Server maintains session state. Session ID stored in cookie references server-side session data.
✓ Easy revocation • ✓ Server control • ⚠ State management
- • Use cryptographically random session IDs (128+ bits)
- • Regenerate session ID after authentication
- • Set Secure, HttpOnly, SameSite flags on cookies
- • Implement session timeout and absolute timeout
OAuth 2.0 / OpenID Connect
Delegated authentication using identity providers. Separates authentication from authorization.
✓ SSO support • ✓ Third-party IdP • ⚠ Implementation complexity
- • Use Authorization Code flow with PKCE (not Implicit)
- • Validate state parameter to prevent CSRF
- • Verify ID token signature and claims
- • Use allowed redirect URI whitelist
Multi-Factor Authentication (MFA)
Requires multiple authentication factors: something you know, have, or are.
✓ Strong security • ✓ Phishing resistant • ⚠ User friction
- • Prefer hardware keys (FIDO2/WebAuthn) over SMS
- • TOTP apps are better than SMS (SIM swap attacks)
- • Implement backup codes securely
- • Consider risk-based/adaptive MFA
Authorization Models
RBAC (Role-Based Access Control)
Users assigned roles; roles have permissions.
User → Role → Permission Admin → [read, write, delete] Editor → [read, write] Viewer → [read]
Best for: Static permission structures, enterprise apps
ABAC (Attribute-Based Access Control)
Access based on attributes of user, resource, action, environment.
if user.dept == resource.dept AND user.clearance >= resource.level AND time.hour in [9..17] then ALLOW
Best for: Dynamic, context-aware access control
ReBAC (Relationship-Based Access Control)
Access based on relationships between entities in a graph.
User --[owner]--> Document User --[member]--> Team --[owns]--> Folder Check: can User view Document?
Best for: Social apps, file sharing, nested permissions
Policy-Based (OPA/Cedar)
Externalized policy engine makes authorization decisions.
permit( principal in Role::"editor", action == Action::"edit", resource in Folder::"docs" );
Best for: Microservices, consistent cross-service authz
Authorization Best Practices
Input Validation Patterns
Allowlist Validation
Define what IS allowed rather than what is NOT allowed. Reject everything not explicitly permitted.
^[a-zA-Z0-9_-]20$ // Username pattern Schema Validation
Validate structure, types, and constraints using schemas (JSON Schema, Zod, Yup).
{ "type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"age": { "type": "integer", "minimum": 0, "maximum": 150 }
},
"required": ["email"] } Canonicalization
Convert input to standard form before validation to prevent bypass via encoding tricks.
- • Decode URL encoding before validation
- • Normalize Unicode (NFC form)
- • Resolve path traversal (../) before checking
Data Protection Patterns
Encryption at Rest
- • AES-256 for symmetric encryption
- • Use envelope encryption (DEK + KEK)
- • Rotate keys periodically
- • Use HSM or KMS for key storage
Encryption in Transit
- • TLS 1.2+ required (prefer 1.3)
- • Strong cipher suites only
- • Certificate pinning for mobile
- • mTLS for service-to-service
Tokenization
- • Replace sensitive data with tokens
- • Token vault maps tokens to real data
- • Reduces PCI DSS scope
- • Format-preserving for legacy systems
Data Masking
- • Show only last 4 digits of SSN/CC
- • Redact in logs and error messages
- • Dynamic masking based on user role
- • Static masking for non-prod environments
Anti-Patterns to Avoid
❌ Security by Obscurity
Hiding implementation details instead of proper security controls. Secret algorithms get discovered.
❌ Client-Side Security
Relying on JavaScript validation or UI hiding for security. Attackers bypass the client entirely.
❌ Hardcoded Secrets
Embedding API keys, passwords, or tokens in source code. They end up in version control and logs.
❌ Overly Permissive Defaults
Default configurations that allow everything. Production systems inherit insecure dev settings.