EXERCISE 2 — Threat-modeling a "redeem discount code" feature ============================================================== Using the four questions (Shostack). Goal: surface DESIGN-level abuse cases and the control each needs designed in (not coded as an afterthought). Q1 — WHAT ARE WE BUILDING? - A feature where a user submits a discount code at checkout; the server validates it and reduces the order total. Data: codes (value, type, validity window, usage limits), the user, the cart/total. Trust boundary: the code + cart come from the CLIENT (untrusted) and must be validated server-side against the catalogue/code store (trusted). Q2 — WHAT CAN GO WRONG? (brainstorm abuse cases; STRIDE helps) Design-level threats: 1. CODE REUSE / NO PER-USER CAP: a single-use or per-customer code is used many times (same user repeatedly, or shared publicly and farmed). (Tampering/abuse of legitimate feature.) 2. STACKING: applying multiple codes, or the same code multiple times in one order, to drive the price below intended (or to zero/negative). 3. BRUTE-FORCING CODES: guessing valid codes by trying many (if codes are short/sequential and there's no rate limit). (Spoofing/DoS of the promotion.) 4. CLIENT-TRUSTED DISCOUNT: the client sends the discounted price or the discount amount, and the server trusts it. (Tampering — links to the checkout design flaw.) 5. EXPIRED/INELIGIBLE USE: using a code past its validity, on ineligible items, or below a minimum spend that isn't enforced. 6. NEGATIVE/UNDERFLOW: a code or quantity that makes the total negative -> a "refund" via checkout. (Business-logic flaw.) 7. RACE CONDITION: redeeming a limited code many times concurrently before the usage counter updates (TOCTOU). Q3 — WHAT ARE WE GOING TO DO ABOUT IT? (controls to DESIGN IN) - PER-USER / GLOBAL USAGE LIMITS enforced server-side, atomically (addresses 1): track redemptions per code and per user; reject over limit. - DISALLOW STACKING / one code per order, validated server-side (2). - RATE LIMIT + anti-automation (CAPTCHA on repeated failures) on code submission, and use long, random, non-sequential codes (3). - SERVER COMPUTES THE TOTAL: price and discount are derived server-side from the catalogue/code store; the client only sends the CODE and item IDs, never amounts (4) — the same principle as the checkout-price flaw. - ENFORCE VALIDITY: expiry, eligibility, minimum spend checked server-side at redemption (5). - CLAMP RESULTS: total can never go below zero; quantities must be positive integers (6). - ATOMIC / TRANSACTIONAL redemption with a DB-level constraint or lock so concurrent redeems can't exceed the limit (7). - LOG redemptions and alert on anomalies (mass redemption) — ties to A09. Q4 — DID WE DO A GOOD JOB? - Review the design against each threat in Q2: is every abuse case covered by a control in Q3? Walk the data flow and confirm NO trusted decision (price, eligibility, usage count) depends on client input. Add abuse-case TEST CASES (reuse, stacking, negative, race) to the test suite, not just happy-path tests. Re-threat-model if the feature changes. KEY POINT: None of these controls is something you'd reliably "discover" while writing the code or in a late pen-test — they have to be DECIDED AT DESIGN TIME by asking "how could this be abused?" That is exactly what A04 / threat modeling is for: build the security controls into the feature's design, cheaply, up front.