Security
OWASP Top 10. SQL injection. Rate limiting. CORS. Secret management.
OWASP Top 10 — The Essentials
The OWASP Top 10 is the definitive list of critical web security risks:
- Broken Access Control — Users doing things they shouldn't (missing authorization checks)
- Cryptographic Failures — Weak encryption, plain-text passwords, exposed secrets
- Injection — SQL injection, command injection, LDAP injection
- Insecure Design — Missing threat modeling, insecure defaults
- Security Misconfiguration — Default passwords, open S3 buckets, verbose errors
- Vulnerable Components — Outdated dependencies with known CVEs
- Authentication Failures — Weak passwords, no MFA, credential stuffing
- Data Integrity Failures — Unsigned JWTs, malicious packages in CI/CD
- Logging/Monitoring Failures — No audit trail, security events not logged
- SSRF — Server-Side Request Forgery (server fetches attacker-controlled URLs)
SQL Injection
SQL injection is when user input is concatenated directly into SQL queries, letting attackers run arbitrary SQL.
NEVER do this:
const query = "SELECT * FROM users WHERE email = '" + email + "'";
// If email = "'; DROP TABLE users;--"
// Query becomes: SELECT * FROM users WHERE email = ''; DROP TABLE users;--'
Always use parameterized queries / prepared statements:
// Node.js (pg)
const result = await db.query(
"SELECT * FROM users WHERE email = $1",
[email] // ← parameter, NOT string concatenation
);
// The driver sends query and data separately.
// No amount of crafted input can escape the parameter.
ORMs help but aren't immune — raw() escape hatches can reintroduce injection. Stay vigilant.
Rate Limiting & Brute Force Protection
Without rate limiting, attackers can:
• Try 1 million password combinations (brute force)
• Scrape your entire database
• DDoS your API
• Enumerate user accounts
Rate limiting strategies:
• Fixed window: 100 requests/minute. Simple. Burst at window boundaries.
• Sliding window: 100 requests in any 60-second window. More accurate.
• Token bucket: tokens refill at a rate. Allows bursts up to bucket size.
• Leaky bucket: requests queue. Smooths traffic to constant rate.
Scope your limits:
• Per IP (blocks bots)
• Per user (prevents API abuse by authenticated users)
• Per endpoint (login: 10/min, GET /users: 1000/min)
Add CAPTCHA or exponential lockout for auth endpoints.
CORS
CORS (Cross-Origin Resource Sharing) prevents malicious websites from making requests to your API using the browser's credentials.
A browser blocks cross-origin requests BY DEFAULT. Your API must explicitly allow origins.
CORS headers:
Access-Control-Allow-Origin: https://myapp.com (or * for public APIs)
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true (if using cookies)
Preflight: Before complex requests (POST with JSON), browsers send OPTIONS first. Your server must respond 200 to OPTIONS or the actual request is blocked.
Never set Access-Control-Allow-Origin: * with Allow-Credentials: true. That's a security hole — any site can make authenticated requests as the user.
Secret Management
Never commit secrets (API keys, DB passwords, JWT secrets) to source code.
Bad: .env file committed to git. Years later, key is rotated but history still shows it.
Good practices:
• Environment variables injected at runtime (not stored in code)
• Secret managers: AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager
• Rotate secrets regularly
• Use different secrets per environment (dev/staging/prod)
• Audit secret access logs
• Least privilege: each service gets only the secrets it needs
In CI/CD: Use GitHub Actions secrets / Vault integration. Never print env vars in logs.
.gitignore: .env, *.pem, *.key — but this is last resort, not primary protection.
The Backend from First Principles series is based on what I learnt from Sriniously's YouTube playlist — a thoughtful, framework-agnostic walk through backend engineering. If this material helped you, please go check the original out: youtube.com/@Sriniously. The notes here are my own restatement for revisiting later.