Security Basics
TL;DR (30-second summary)
Authentication: Verify identity (who you are). Authorization: Check permissions (what you can do). OAuth: Let users login with Google/Facebook. JWT: Stateless tokens. Encryption: HTTPS (in transit), AES (at rest).
Golden rule: Never trust user input. Always validate, sanitize, and authenticate.
Why This Matters
In interviews: Security is non-negotiable. Shows you think about real-world threats and compliance (GDPR, PCI-DSS).
At work: Security breaches cost millions and destroy trust.
Core Concepts
1. Authentication vs Authorization
| Concept | Question | Example |
|---|---|---|
| Authentication | Who are you? | Login with username/password |
| Authorization | What can you do? | Admin can delete, user can only read |
2. Authentication Methods
Session-Based (Traditional)
Pros:
- ✅ Can revoke immediately (delete session)
- ✅ Secure (session ID is meaningless)
Cons:
- ❌ Stateful (requires session store)
- ❌ Doesn't scale horizontally (sticky sessions or shared session store)
Token-Based (JWT)
JWT Structure:
Header.Payload.Signature
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMTIzIn0.abc123xyz
Decoded:
// Header
{"alg": "HS256", "typ": "JWT"}
// Payload
{"user_id": "123", "role": "admin", "exp": 1642345600}
// Signature (verifies token hasn't been tampered with)
HMACSHA256(base64(header) + "." + base64(payload), secret)
Pros:
- ✅ Stateless (no session store needed)
- ✅ Scales horizontally
- ✅ Can include user data in payload (avoid DB lookup)
Cons:
- ❌ Can't revoke until expiry (use short TTL: 15-60 min)
- ❌ Payload is visible (base64, not encrypted)
- ❌ Token size larger than session ID (impacts bandwidth)
Never store sensitive data in JWT (e.g., passwords, credit cards). Payload is BASE64-encoded, not encrypted!
Best practice: Use short-lived JWT (15 min) + refresh token (stored securely).
3. OAuth 2.0
Purpose: Let users login with 3rd-party providers (Google, Facebook, GitHub) without sharing passwords.
OAuth Roles:
- Resource Owner: User
- Client: Your app
- Authorization Server: Google/Facebook
- Resource Server: Google's API (user profile)
OAuth Scopes (permissions):
scope=read:user,write:repo
Use cases:
- "Login with Google" (authentication)
- Grant app access to Google Drive (authorization)
4. Authorization Patterns
Role-Based Access Control (RBAC)
{
"user_id": "123",
"roles": ["admin", "editor"]
}
Check:
if "admin" in user.roles:
allow_delete()
Pros: Simple, easy to manage
Cons: Coarse-grained (can't express complex permissions)
Permission-Based (Fine-Grained)
{
"user_id": "123",
"permissions": [
"users:read",
"users:write",
"posts:delete"
]
}
Check:
if "posts:delete" in user.permissions:
delete_post()
Pros: Flexible, fine-grained
Cons: More complex to manage
Attribute-Based Access Control (ABAC)
# Rule: User can edit post if they are the author
if user.id == post.author_id:
allow_edit()
# Rule: User can view document if department matches
if user.department == document.department:
allow_view()
Pros: Very flexible, context-aware
Cons: Complex rules, harder to debug
5. Common Vulnerabilities
SQL Injection
Attack:
# Vulnerable code
query = f"SELECT * FROM users WHERE email = '{email}'"
# Attacker input: email = "' OR '1'='1"
# Resulting query: SELECT * FROM users WHERE email = '' OR '1'='1'
# Returns all users!
Fix (Parameterized queries):
query = "SELECT * FROM users WHERE email = ?"
db.execute(query, [email]) # Safe - input is escaped
Cross-Site Scripting (XSS)
Attack:
<!-- User input: <script>alert('XSS')</script> -->
<div>Comment: <script>alert('XSS')</script></div>
<!-- Script executes in victim's browser -->
Fix (Output encoding):
<div>Comment: <script>alert('XSS')</script></div>
<!-- Displays as text, doesn't execute -->
Cross-Site Request Forgery (CSRF)
Attack:
<!-- Malicious site -->
<img src="https://bank.com/transfer?to=attacker&amount=1000">
<!-- If user is logged into bank.com, request succeeds -->
Fix (CSRF tokens):
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="abc123...">
<input name="to" value="...">
<button>Transfer</button>
</form>
Server validates token before processing request.
6. Encryption
Data in Transit (HTTPS/TLS)
Purpose: Encrypt data traveling over the network.
Without HTTPS: Attacker can see passwords, credit cards (man-in-the-middle attack).
Always use HTTPS for production APIs.
Data at Rest
Purpose: Encrypt data stored in database or disk.
Algorithms:
- AES-256: Symmetric encryption (same key for encrypt/decrypt)
- RSA-2048: Asymmetric encryption (public/private key pair)
Example (Database encryption):
# Encrypt before storing
encrypted_ssn = aes_encrypt(ssn, key)
db.insert(user_id, encrypted_ssn)
# Decrypt when reading
encrypted_ssn = db.get(user_id)
ssn = aes_decrypt(encrypted_ssn, key)
Use cases:
- Credit card numbers
- Social security numbers
- Medical records (HIPAA compliance)
Key management:
- Never hardcode keys in code
- Use secrets management (AWS Secrets Manager, HashiCorp Vault)
- Rotate keys periodically
Hashing (One-Way)
Purpose: Store passwords securely (can't be reversed).
Never store plain-text passwords:
# WRONG
db.insert(user_id, password) # ❌ Plain-text
# RIGHT
hashed = bcrypt.hash(password) # ✅ Hashed
db.insert(user_id, hashed)
Verify login:
stored_hash = db.get(user_id)
if bcrypt.verify(password, stored_hash):
login_success()
Algorithms:
- bcrypt: Recommended for passwords (slow, with salt)
- Argon2: Modern, resistant to GPU attacks
- SHA-256: Fast, but NOT for passwords (too fast = easy to brute-force)
Salt (random data added to password before hashing):
password: "hello123"
salt: "a1b2c3d4"
hash(password + salt) → "xyz789..."
Prevents rainbow table attacks (pre-computed hashes)
7. API Security Best Practices
| Practice | Why |
|---|---|
| HTTPS everywhere | Encrypt data in transit |
| Rate limiting | Prevent brute-force, DDoS |
| Input validation | Prevent SQL injection, XSS |
| Parameterized queries | Prevent SQL injection |
| Output encoding | Prevent XSS |
| CSRF tokens | Prevent CSRF attacks |
| JWT with short expiry | Limit damage if token stolen (15-60 min) |
| Password hashing | bcrypt/Argon2 with salt |
| Secrets management | Never hardcode API keys/passwords |
| CORS headers | Restrict which domains can call API |
| Security headers | X-Frame-Options, Content-Security-Policy |
Security headers:
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self'
Common Interview Questions
Q1: "Explain JWT and its trade-offs."
Answer:
- What: JSON Web Token - self-contained, stateless authentication
- Structure: Header.Payload.Signature (base64 encoded)
- Pros: Stateless (scales horizontally), no session store
- Cons: Can't revoke until expiry, payload visible (not encrypted)
- Best practice: Short TTL (15 min) + refresh token
Q2: "How do you prevent SQL injection?"
Answer:
- Use parameterized queries (prepared statements)
- Never concatenate user input into SQL string
- Example:
# Vulnerable: query = f"SELECT * FROM users WHERE id = {user_id}"
# Safe: db.execute("SELECT * FROM users WHERE id = ?", [user_id])
Q3: "Session-based vs token-based authentication?"
Answer:
| Aspect | Session-Based | Token-Based (JWT) |
|---|---|---|
| State | Stateful (session store) | Stateless |
| Scalability | Harder (sticky sessions) | Easier (any server can validate) |
| Revocation | Immediate (delete session) | Wait for expiry |
| Use case | Monoliths, server-rendered apps | Microservices, SPAs, mobile |
Q4: "How do you securely store passwords?"
Answer:
- Never plain-text - hash with bcrypt/Argon2
- Salt - add random data to prevent rainbow tables
- Slow algorithm - bcrypt is intentionally slow (resist brute-force)
- Example:
hashed = bcrypt.hash(password, salt_rounds=12)
db.insert(user_id, hashed)
Trade-offs
| Decision | Option A | Option B | Consider |
|---|---|---|---|
| Auth | Session-based (stateful) | JWT (stateless) | Scalability vs revocation |
| Password | bcrypt (proven) | Argon2 (modern) | Compatibility vs security |
| Encryption | AES-256 (symmetric) | RSA (asymmetric) | Speed vs key distribution |
| OAuth | Own auth system | 3rd-party (Google) | Control vs convenience |
Real-World Examples
Auth0 (Authentication as a Service)
- Handles: Login, OAuth, MFA, JWT
- Use case: Offload auth complexity
- Result: 2 billion logins/month for 8000+ companies
Stripe (Payment Security)
- PCI-DSS Level 1 compliant (highest security standard)
- Encryption: TLS 1.2+, AES-256 at rest
- Tokenization: Never store raw card numbers
- Result: Process $1 trillion/year securely
GitHub (OAuth Provider)
- OAuth scopes:
repo,user,admin:org - Personal access tokens: Fine-grained permissions
- 2FA: Required for sensitive operations
Quick Reference Card
Authentication:
- Session: Stateful, use for monoliths
- JWT: Stateless, use for microservices/mobile
- OAuth: 3rd-party login (Google, Facebook)
Authorization:
- RBAC: Role-based (simple)
- ABAC: Attribute-based (flexible)
Encryption:
- In transit: HTTPS/TLS (always)
- At rest: AES-256 (sensitive data)
- Passwords: bcrypt/Argon2 (one-way hash)
Common vulnerabilities:
- SQL Injection: Use parameterized queries
- XSS: Encode output
- CSRF: Use CSRF tokens
Security headers:
Strict-Transport-Security: max-age=31536000
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'
Further Reading
- OWASP Top 10 - Most critical security risks
- JWT.io - JWT debugger and docs
- OAuth 2.0 Simplified
- bcrypt vs Argon2
Next: Monitoring & Observability - Logging, metrics, tracing, alerting.