iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Least Privilege

OWASP’s “Top 10” isn’t a checklist — it’s shorthand for security principles that make the bugs less likely in the first place. Internalise these — least privilege, defense in depth, fail securely, defaults that are safe — and most of the Top 10 stop happening on your codebase.

Principles + how they map to code

EXAMPLE
// 1) LEAST PRIVILEGE
// Every actor (user, service, function, DB user) gets exactly the permissions it needs.
//
// Application:
//   • Per-service AWS IAM role, not a god role
//   • Per-service DB user (read-only where possible)
//   • Workload identity (Kubernetes service accounts) instead of shared secrets
//   • Feature-flag dangerous actions behind explicit role checks
//
// People:
//   • Production access via JIT (just-in-time) approvals
//   • Engineers can deploy, not edit prod DB directly
//   • Quarterly access review — remove every role nobody used in 90 days

// 2) DEFENSE IN DEPTH
// A single control will fail one day. Layered controls turn 'one failure' into 'partial failure'.
//
//   client validation → server validation → DB constraints → app-level audit
//   CSP → input sanitisation → output encoding → cookie HttpOnly
//   WAF → rate limiter → auth → authz → query parameterisation → DB user privileges
//
// Each layer accepts that others might fail. The system stays secure if any TWO layers hold.

// 3) FAIL SECURELY
// When a check errors, choose 'deny' over 'allow'.
//
function can(user, action, resource) {
    try {
        return policyEngine.check(user, action, resource);
    } catch (e) {
        log.error('policy check failed', e);
        return false;                          // deny on error, not allow
    }
}

// • try/catch in authz code returns DENIED on any exception
// • Default routes 404 instead of revealing existence
// • Healthchecks that can't reach dependencies report unhealthy, not healthy
// • Configuration that can't be parsed crashes startup, not silently falls back to insecure defaults

// 4) SECURE BY DEFAULT
// New features should be safe even if the engineer added nothing.
//
//   • Cookies default to HttpOnly + Secure + SameSite=Lax
//   • Database client throws on string concatenation; only takes bind parameters
//   • Web framework escapes templates by default; raw-HTML escape hatch is loud
//   • Production env disables debug pages; dev env enables them
//   • API routes require auth; opt-in 'public' decorator for the few that don't
//   • Audit log enabled for every state change
//
// Code-review heuristic: if the safer behaviour requires an extra annotation, the default is wrong.

// 5) MINIMISE ATTACK SURFACE
// Every endpoint, port, page, package, and parameter is a thing an attacker can poke.
//
//   • Remove unused endpoints
//   • Decommission unused services
//   • npm prune dependencies (depcheck, knip)
//   • Block unused HTTP methods (PUT on a GET-only endpoint)
//   • Tight CORS allowlist; no wildcard with credentials
//   • Robots.txt is NOT security — but disabling unused admin paths helps
//   • Run only the ports you need; firewall everything else

// 6) ZERO TRUST
// Don't trust network location; authenticate every request.
//
//   • mTLS or signed requests between internal services
//   • Strong service-to-service auth (SPIFFE / SPIRE)
//   • API gateways that re-authenticate, not just route
//   • Database connections use TLS even inside the VPC
//   • Secrets fetched per-pod from a vault, not baked into images

// 7) SEPARATION OF DUTIES / CONCERNS
//
//   • Different code path for 'create account' vs 'admin impersonate'
//   • Production releases require an approval from someone OTHER than the developer
//   • Audit logs can be read by ops + security, but only admins can DELETE — and there's a chain of custody
//   • Per-service / per-tenant secret rotation; one compromise doesn't unlock everything

// 8) ENCRYPT EVERYWHERE — DATA AT REST + IN TRANSIT
//
//   • TLS 1.2+ between every client and server, including internal
//   • HSTS with includeSubDomains + preload
//   • Database storage encrypted (transparently — managed services usually do this)
//   • Backups encrypted with rotated keys
//   • Per-tenant data encrypted with tenant-specific keys derived from a master
//   • Secrets stored in a vault, never in code or env files committed to git

// 9) IDENTIFY + LOG
// You can't respond to what you don't see.
//
//   • Structured logs (JSON) so you can query: 'who did what, to what, from where, when'
//   • Audit log for every state change (immutable retention)
//   • Alert on auth.failure, csrf.failure, idor.attempt, rate.limit.exceeded
//   • Correlate logs by request id across services
//   • Send security signals to a SIEM; engineering logs and security logs are different problems

// 10) ASSUME BREACH
// Plan as if defenses have already failed.
//
//   • Network segmentation — a popped pod can't reach the prod database
//   • Secrets rotate frequently enough that yesterday's leak is useless
//   • Backups offline / immutable for the ransomware case
//   • Tabletop exercises ('what if /etc/passwd leaked?')
//   • Pre-written runbooks for the top 5 incident scenarios
//   • A clear incident command structure — who decides, who communicates, who fixes

// 11) PRINCIPLE OF NO-DEFAULT-CREDENTIALS
//
//   • Never ship a service with hard-coded admin/admin
//   • Force a strong credential on first run
//   • Make credential rotation a one-line operation; if it's hard, no one will do it
//   • Disable test accounts in prod build steps

// 12) USE WELL-TESTED LIBRARIES, NOT YOUR OWN CRYPTO
//   • Argon2id / scrypt / bcrypt for password hashing
//   • libsodium / NaCl / Web Crypto for primitives
//   • TLS via the platform (let nginx/OpenSSL handle it)
//   • JWTs via vetted libs — and pin the accepted algorithm list
//   • DON'T:  custom hash chains, home-made 'encryption', RSA with PKCS#1 v1.5 padding, MD5 / SHA-1 for new code

// 13) FAIL EXPLICIT, NOT IMPLICIT
//   • Throw on unsupported configuration, don't fall back
//   • Don't 'just continue' when an authz check returns an unexpected shape
//   • Don't decode JWTs with alg=none accepted
//   • Don't accept the input shape 'we'll handle that later' — refuse it now

// 14) ECONOMY OF MECHANISM
//   • Smaller security surface = easier to audit
//   • Centralise authentication in one library / middleware
//   • Centralise authorisation in a policy layer
//   • Centralise audit logging
//   • Avoid clever, opaque tricks — boring, readable code is auditable code

// 15) MAP TO OWASP TOP 10 (2021)
// A01 Broken Access Control          → Least privilege, central policy layer, 404 not 403
// A02 Cryptographic Failures         → Use vetted crypto libraries, modern algorithms, real KMS
// A03 Injection                      → Parameterised queries, schema validation, input shape checks
// A04 Insecure Design                → Threat model BEFORE coding; security in design reviews
// A05 Security Misconfiguration      → Secure-by-default, infra as code, automated config audits
// A06 Vulnerable Components          → SBOM + scanning + patch SLAs (see owasp/a06)
// A07 Identification + Auth Failures → MFA, strong KDF, account-lockout backoff, session invalidation
// A08 Software + Data Integrity      → Signed releases, CSP, SRI, supply chain SLSA
// A09 Logging + Monitoring Failures  → Structured logs, alerts, retention, SIEM
// A10 Server-Side Request Forgery   → Allowlist outbound destinations, block private ranges, validate URLs

// 16) MAKING THESE PRINCIPLES OPERATIONAL
// Translate principles into:
//   • CI checks (linter rules, dependency scans, secret detectors)
//   • Default templates (cookie config, CSP, fetch wrappers)
//   • Code review checklists
//   • Quarterly drills (incident response, key rotation)
//   • Onboarding curricula so every engineer learns them on day one
//
// A principle on a slide deck doesn't protect anything; a principle baked into the build does.

Why it matters

The OWASP Top 10 changes; principles don’t. Least privilege, defense in depth, fail securely, secure-by-default, assume breach — once those are how your codebase is built and operated, the specific bug categories take care of themselves. Translate every principle into a default template, a CI check, or a code-review heuristic so they show up in real engineering work, not slide decks.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Least privilege everywhere: DB users, IAM roles, K8s ServiceAccounts,
// CI/CD tokens, OAuth scopes. Default deny → grant the minimum needed.
Try it Yourself »

Discussion

Loading…