EXERCISE 3 — "Can't fix insecure design with perfect implementation" ==================================================================== THE PRINCIPLE: If a feature is DESIGNED without a needed security control (or built on an unsafe mechanism), then implementing that design perfectly just produces a flawlessly-built INSECURE feature. The vulnerability lives in WHAT was decided to build, not in HOW the code turned out — so code quality can't remove it. WORKED EXAMPLE: Feature: "reset your password by answering security questions" (mother's maiden name, first pet). - Implement it impeccably: parameterized DB queries, no XSS, constant-time comparisons, great error handling, rate limiting on the form, HTTPS. - It is STILL insecure: the answers are PUBLIC/GUESSABLE (social media, public records, a handful of common pet names). An attacker who looks up or guesses the answer resets the account — and the code did everything "right." - No implementation improvement fixes this, because the WEAKNESS IS THE MECHANISM. The fix is to REDESIGN the recovery flow (emailed single-use expiring token / stronger verification), i.e. change what is built. - Contrast: a forgotten-to-parameterize query is an IMPLEMENTATION bug — fix the line and it's secure. The security-question flow is a DESIGN bug — no line is wrong. WHY PEN-TESTING LATE DOESN'T CATCH DESIGN FLAWS: - Pen-testing and code review look for IMPLEMENTATION defects: an injectable parameter, a missing cookie flag, an unescaped output. They test whether the code correctly does what it was meant to do. - A flawed DESIGN often has CLEAN code: a tester sees well-written code that faithfully implements a bad idea (trusting client prices, weak recovery, missing rate limits) and nothing looks "buggy." The flaw is in the intended behaviour, which isn't a code defect to find. - Late testing is also EXPENSIVE to act on: discovering at pen-test (or after a breach) that the whole feature needs redesigning is far costlier than catching it at the whiteboard. Hence "shift left": threat-model and write security requirements BEFORE coding. Pen-testing is a valuable backstop for implementation bugs, not a substitute for secure design. FOUR SECURE-BY-DESIGN PRINCIPLES + how each prevents an earlier vulnerability: 1. LEAST PRIVILEGE. - Earlier vuln: SQL injection escalating to dropping tables / OS commands (SQLi course). A least-privilege DB account (read-only, no FILE/ xp_cmdshell) designed in LIMITS the blast radius so an injection can't wipe the DB or run commands — damage contained by design. 2. FAIL SECURELY / DENY BY DEFAULT. - Earlier vuln: broken access control where a forgotten endpoint is publicly reachable (A01). Designing the system to DENY by default means a new/forgotten route is protected automatically — mistakes fail closed, not open. 3. DEFENCE IN DEPTH. - Earlier vuln: session theft (XSS/CSRF/Auth). Layering controls by design — HttpOnly + Secure + SameSite + tokens + short timeouts — means one failing control (e.g. a missed SameSite) doesn't equal account takeover. 4. SECURE DEFAULTS / MINIMIZE ATTACK SURFACE. - Earlier vuln: security misconfiguration / over-exposure (A05/A02). Designing the default configuration to be the safe one (no default creds, errors generic, only needed features/data exposed) prevents the "shipped-with-debug-on" class before it exists. ONE-LINE TAKEAWAY: Some vulnerabilities are decided at design time; perfect code can't undo a bad design, and late pen-testing rarely catches it — so threat-model and apply secure-by-design principles (least privilege, fail securely, defence in depth, secure defaults) UP FRONT.