EXERCISE 3 — Debunking "stored procedures prevent SQLi" and "our WAF protects us" ================================================================================ MYTH 1: "STORED PROCEDURES PREVENT SQLi." THE TRUTH: protection comes from USING PARAMETERS AS BOUND VALUES, not from the code being a stored procedure. A procedure is just SQL that lives in the database; it can be written safely or unsafely. WHERE IT FAILS — a procedure that builds dynamic SQL by concatenation: CREATE PROCEDURE getUser(IN uname VARCHAR(50)) BEGIN SET @sql = CONCAT('SELECT * FROM users WHERE username = ''', uname, ''''); PREPARE st FROM @sql; EXECUTE st; -- concatenated -> INJECTABLE END Here uname is concatenated into a dynamic SQL string and EXECUTEd. Passing uname = admin'-- injects exactly as it would in application code — the vulnerability just moved INTO the database. Calling this proc with user input is no safer than app-side concatenation. THE SAFE FORM — parameter used as a bound value: CREATE PROCEDURE getUser(IN uname VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = uname; -- bound, not concatenated END Now uname is a parameter the query treats as data; admin'-- is a literal username that matches nothing. CORRECT ROLE: stored procedures CAN be a useful layer — they enable privilege separation (grant EXECUTE on the proc, not direct table access) and centralize query logic. But that's defence in depth; the actual SQLi protection is the same as always: PARAMETERS USED AS DATA, never concatenated — inside the proc AND when the app calls it. "We use stored procs" is not a substitute for that discipline. MYTH 2: "OUR WAF PROTECTS US." THE TRUTH: a Web Application Firewall blocks requests matching known SQLi PATTERNS. It's pattern-matching at the perimeter — a blocklist — and shares the blocklist-loses problem from the XSS course. WHERE IT FAILS: - BYPASSES: attackers evade signatures with encoding (URL/hex/unicode), inline comments (UN/**/ION SE/**/LECT), case variation, whitespace tricks, alternative syntax, and novel payloads the rules don't match. WAF bypass is a routine part of real testing. - SECOND-ORDER BLINDNESS: in second-order SQLi (Chapter 6) the malicious value enters as INNOCUOUS data (e.g. a plausible username) and only becomes dangerous later when re-used in a query. The WAF inspecting the inbound request sees nothing to block — the payload isn't an attack pattern at entry. The WAF cannot see this class at all. - THE BUG REMAINS: even when the WAF blocks a probe, the injectable query is still in the code. Any bypass = full exploitation. CORRECT ROLE: a WAF is a valuable BACKSTOP / defence in depth at the perimeter — it stops opportunistic mass-scanning and automated tools, reduces noise, and buys time during a zero-day/patch window. Use it as an outer layer. But NEVER as the SQLi defence: it's bypassable, blind to second-order, and leaves the vulnerability in place. THE UNIFYING POINT: Both myths share the same error: mistaking a HELPFUL LAYER for THE FIX. Stored procedures and WAFs reduce risk and add depth, but the load-bearing defence is PARAMETERIZED QUERIES (Chapter 7), which actually removes the vulnerability. Layer the others on top to catch slips and contain damage; rely on parameterization underneath.