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

Quiz

Six SQL injection questions that show up in code review. Pick the right defence and explain.

Six SQLi design questions

EXAMPLE
# ============================================================
# Q1) Why is parameterised SQL safe even when input is malicious?
# ============================================================
# ANSWER: the driver sends the query template and the parameter values
# SEPARATELY to the database. The DB parses the query once with placeholders,
# then binds values. The values cannot become SQL syntax — they are data.
# String concatenation, by contrast, lets the input become part of the query.

# ============================================================
# Q2) When can identifiers (table, column names) NOT be parameterised?
# ============================================================
# ANSWER: they cannot — placeholders are for VALUES, not identifiers.
# Solution: whitelist. Map untrusted input through a fixed dictionary:
# const SORTS = { newest: 'created_at DESC', price: 'price_cents ASC' };
# const order = SORTS[req.query.sort] ?? SORTS.newest;
# Then construct the SQL with the WHITELISTED string.

# ============================================================
# Q3) Are stored procedures inherently safe from SQLi?
# ============================================================
# ANSWER: NO. A stored procedure that builds dynamic SQL with concatenation
# is exactly as vulnerable as the equivalent inline query. Parameterise
# INSIDE the procedure (EXECUTE ... USING / sp_executesql).

# ============================================================
# Q4) Your ORM is safe by default. Where does SQLi come back?
# ============================================================
# ANSWER: the escape hatches.
# - Eloquent: whereRaw, selectRaw, DB::statement, DB::select with strings
# - Sequelize: sequelize.query
# - Prisma: $queryRawUnsafe (vs the safe $queryRaw tagged template)
# - EF Core: FromSqlInterpolated (safe) vs FromSqlRaw with concatenation (unsafe)
# Code review: grep for the unsafe variants.

# ============================================================
# Q5) Your search is parameterised but LIKE patterns still cause weird matches.
# ============================================================
# ANSWER: % and _ are LIKE wildcards. Escape them in user input before
# substituting:
# const safe = input.replace(/[%_]/g, c => '\\\\' + c);
# Then bind '%' + safe + '%' as the parameter.

# ============================================================
# Q6) A test SQLi payload returns nothing — is the bug fixed?
# ============================================================
# ANSWER: maybe. Negative result is weak evidence.
# Verify the actual code path:
# - Read the query (log it locally)
# - Confirm placeholders are used and values are arrays/structures
# - Try blind-SQLi payloads: ' OR pg_sleep(2)--   /  ' OR sleep(2)#
# - Try error-based: WHERE id = 1 AND 1=convert(int, 'abc')
# Pen test before signing off.

# ============================================================
# Bonus — what makes least-privileged DB roles a defence-in-depth?
# ============================================================
# ANSWER: even if a SQLi slips through, the role cannot DROP, ALTER, COPY,
# read other schemas, or access pg_catalog / mysql.user. The attacker is
# bounded by what the app already does. Pair this with WAF rules and you
# have a meaningful safety net.

# ============================================================
# Scoring
# ============================================================
# 6 / 6 -> ready to review SQLi PRs
# 4 / 6 -> revisit sqli/cheatsheet
# < 4   -> read OWASP SQLi Prevention Cheat Sheet

Why it matters

Parameterise every query AND ship a least-privileged DB role. The combination — primary defence + safety net — means a single missed query that slips through code review cannot drain the database. The role boundary turns "we shipped a SQLi bug" from an extinction event into "we have a bug to fix in the next release".

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

Example

Example
-- 3 questions per lesson.
Try it Yourself »

Discussion

Loading…