19. Security Basics for System Design
Security is a cross-cutting concern that must be considered at every layer of a system. A single vulnerability can compromise an entire architecture.
Security Principles
| Principle | Description |
|---|---|
| Defense in depth | Multiple layers of security; no single point of failure |
| Least privilege | Grant minimum permissions necessary |
| Zero trust | Never trust, always verify — even internal traffic |
| Fail secure | On failure, deny access rather than allow |
| Separation of duties | No single entity has full control |
| Security by design | Build security in from the start, not as an afterthought |
Authentication
Verifying who you are.
Methods
| Method | Description | Use Case |
|---|---|---|
| API Keys | Static secret passed in header/query | Server-to-server, public APIs |
| Username/Password | Basic credentials | User login |
| OAuth 2.0 | Delegated authorization framework | Third-party access, SSO |
| JWT (JSON Web Tokens) | Self-contained signed tokens | Stateless auth, microservices |
| mTLS | Mutual TLS certificate verification | Service-to-service in service mesh |
| SAML | XML-based SSO | Enterprise SSO |
| Multi-factor (MFA) | Password + second factor (OTP, TOTP, hardware key) | High-security accounts |
JWT (JSON Web Token)
Header.Payload.Signature
Header: {"alg": "RS256", "typ": "JWT"}
Payload: {"sub": "user-123", "role": "admin", "exp": 1705312800}
Signature: HMAC-SHA256(base64(header) + "." + base64(payload), secret)
Client → Login (username/password) → Auth Service
Auth Service → Verify credentials → Issue JWT → Client
Client → Request + JWT (Authorization: Bearer <token>) → API Service
API Service → Verify JWT signature → Extract claims → Process request
JWT Pros: Stateless (no session store), self-contained, works across services.
JWT Cons: Can't be revoked before expiration (without a deny-list), token size overhead.
OAuth 2.0 Flows
| Flow | Use Case |
|---|---|
| Authorization Code | Web apps (most secure) |
| Authorization Code + PKCE | Mobile/SPA apps |
| Client Credentials | Server-to-server |
| Device Code | IoT, TV apps |
Authorization Code Flow:
1. Client → Auth Server: "User wants to log in" (redirect)
2. Auth Server → User: "Enter credentials" (login page)
3. User → Auth Server: Credentials
4. Auth Server → Client: Authorization Code (redirect)
5. Client → Auth Server: Exchange code for tokens (server-side)
6. Auth Server → Client: Access Token + Refresh Token
Authorization
Verifying what you can do.
Models
| Model | Description |
|---|---|
| RBAC (Role-Based Access Control) | Permissions assigned to roles; users assigned to roles |
| ABAC (Attribute-Based Access Control) | Permissions based on attributes (user, resource, environment) |
| ACL (Access Control List) | Explicit list of who can access what |
| ReBAC (Relationship-Based Access Control) | Permissions based on relationships (e.g., "owner of document") |
RBAC Example
Roles:
admin → [read, write, delete, manage_users]
editor → [read, write]
viewer → [read]
Users:
Alice → admin
Bob → editor
Carol → viewer
Request: Bob tries to DELETE /resource/123
→ Bob has role "editor" → "editor" doesn't have "delete" → 403 Forbidden
Encryption
At Rest
Data stored on disk is encrypted.
Application → Plaintext → [Encryption (AES-256)] → Ciphertext → Disk
Disk → Ciphertext → [Decryption] → Plaintext → Application
Types:
| Type | Description |
|------|-------------|
| Server-side encryption (SSE) | Cloud provider encrypts/decrypts (S3, RDS) |
| Client-side encryption | Application encrypts before sending to storage |
| Transparent Data Encryption (TDE) | Database handles encryption automatically |
In Transit
Data moving over the network is encrypted.
Client ←─[TLS 1.3]─→ Server
Service A ←─[mTLS]─→ Service B
Always use HTTPS in production. No exceptions.
Key Management
| Service | Provider |
|---|---|
| AWS KMS | AWS |
| Cloud KMS | Google Cloud |
| Azure Key Vault | Azure |
| HashiCorp Vault | Open source / enterprise |
Principles:
- Never hardcode secrets in code.
- Rotate keys regularly.
- Use envelope encryption (data key encrypted by master key).
- Audit key usage.
Common Attack Vectors & Mitigations
SQL Injection
-- Vulnerable:
query = "SELECT * FROM users WHERE id = " + user_input
-- Attacker input: "1; DROP TABLE users;--"
-- Safe: Parameterized queries
query = "SELECT * FROM users WHERE id = $1"
params = [user_input]
Cross-Site Scripting (XSS)
<!-- Vulnerable: -->
<p>Welcome, ${user_input}</p>
<!-- Attacker input: <script>steal_cookies()</script> -->
<!-- Safe: Escape output -->
<p>Welcome, ${escape(user_input)}</p>
Cross-Site Request Forgery (CSRF)
Attacker site → Hidden form → POST to victim.com/transfer?amount=10000
(using victim's authenticated session cookie)
Mitigation: CSRF tokens, SameSite cookies, checking Origin header.
DDoS (Distributed Denial of Service)
Millions of requests → Your server → Overloaded → Legitimate users can't access
Mitigation:
- CDN (Cloudflare, AWS Shield)
- Rate limiting
- Auto-scaling
- WAF (Web Application Firewall)
- Anycast routing (distribute attack traffic)
Man-in-the-Middle (MITM)
Client ←─[unencrypted]─→ Attacker ←─→ Server
Mitigation: TLS everywhere, certificate pinning, HSTS.
Network Security
Firewall / Security Groups
Internet → [WAF] → [Load Balancer] → [Security Group: Allow port 443]
↓
[App Servers]
[SG: Allow port 8080 from LB only]
↓
[Database]
[SG: Allow port 5432 from App only]
Rules:
- Public subnet: Only load balancers and bastion hosts.
- Private subnet: App servers (no direct internet access).
- Data subnet: Databases (only accessible from app servers).
API Security Checklist
| Security Measure | Description |
|---|---|
| HTTPS everywhere | Encrypt all traffic |
| Authentication | Verify identity on every request |
| Authorization | Check permissions for each resource |
| Rate limiting | Prevent abuse and DDoS |
| Input validation | Validate and sanitize all inputs |
| Output encoding | Prevent XSS |
| CORS policy | Restrict cross-origin requests |
| HSTS | Force HTTPS via Strict-Transport-Security header |
| CSP | Content Security Policy to prevent XSS |
| No sensitive data in URLs | Query parameters are logged; use headers/body |
| Audit logging | Log all security-relevant events |
| Dependency scanning | Check for known vulnerabilities in libraries |
Secrets Management
Never store secrets in:
- Source code
- Environment variables (unless injected at runtime)
- Configuration files committed to git
Use instead:
| Tool | Description |
|------|-------------|
| HashiCorp Vault | Centralized secret store with audit, rotation, dynamic secrets |
| AWS Secrets Manager | Managed secret rotation for AWS services |
| AWS Parameter Store | Simple key-value with encryption |
| Kubernetes Secrets | Native K8s secret management (encrypt with external KMS) |
| Doppler, 1Password | Developer-friendly secret management |
Data Privacy
| Principle | Description |
|---|---|
| Data minimization | Collect only what you need |
| Purpose limitation | Use data only for stated purpose |
| Anonymization | Remove identity from data |
| Pseudonymization | Replace identity with tokens |
| Right to erasure | Users can request data deletion (GDPR) |
| Encryption | Protect data at rest and in transit |
Summary
| Concept | Key Point |
|---|---|
| Authentication | JWT for stateless, OAuth 2.0 for delegation |
| Authorization | RBAC for most systems; ABAC for fine-grained |
| Encryption | TLS in transit, AES-256 at rest, KMS for key management |
| API security | HTTPS + auth + rate limiting + input validation |
| Network security | Defense in depth with security groups and private subnets |
| Secrets | Use Vault or managed secret services; never hardcode |
Rule of thumb: Assume every input is malicious. Encrypt everything. Follow the principle of least privilege. Use established libraries and services — never roll your own crypto or auth.