Home
Backend from First Principles / Module 16 — Security

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:

  1. Broken Access Control — Users doing things they shouldn't (missing authorization checks)
  2. Cryptographic Failures — Weak encryption, plain-text passwords, exposed secrets
  3. Injection — SQL injection, command injection, LDAP injection
  4. Insecure Design — Missing threat modeling, insecure defaults
  5. Security Misconfiguration — Default passwords, open S3 buckets, verbose errors
  6. Vulnerable Components — Outdated dependencies with known CVEs
  7. Authentication Failures — Weak passwords, no MFA, credential stuffing
  8. Data Integrity Failures — Unsigned JWTs, malicious packages in CI/CD
  9. Logging/Monitoring Failures — No audit trail, security events not logged
  10. 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:

JavaScript
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:

JavaScript
// 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.

Snippet
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.


Source & Credit

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.

⁂ Back to all modules