Lesson 7 of 7
Lesson 7 — Security, Performance and Real-World Practice
Injection, least privilege, indexes, query plans, backups — the things that keep a live database safe and fast.
Learn it
SQL injection happens when user input becomes part of the query. Parameterised queries fix it.
Least privilege: the app's account should only be able to do what the app needs — no DROP TABLE rights.
Row level security and views let different users see different rows of the same table.
Slow queries usually mean a missing index or a query that scans the whole table. EXPLAIN shows you which.
Key terms
- SQL injection
- Attack where user input is executed as part of a query.
- Least privilege
- Give each account only the permissions it truly needs.
- Row level security
- Policies limiting which rows a user can see or change.
- Query plan
- The steps the database will take; inspected with EXPLAIN.
- Point-in-time recovery
- Restoring a database to any moment before an incident.
Harden a live database
- 1Parameterise: Replace every string-built query with placeholders.
- 2Trim privileges: App user gets SELECT/INSERT/UPDATE on its tables only.
- 3Add policies: Row level security so a student reads only their own progress.
- 4Index the hot paths: EXPLAIN the three slowest queries and index the filtered columns.
- 5Prove the backup: Restore last night's backup into a scratch database and query it.
Injection, fixed
python# VULNERABLE — the input becomes code
name = request.form["name"]
cur.execute(f"SELECT * FROM student WHERE name = '{name}'")
# name = "' OR '1'='1" -> returns every student
# SAFE — the input stays data
cur.execute("SELECT * FROM student WHERE name = %s", (name,))
# And in the database itself:
# CREATE POLICY own_rows ON progress
# FOR SELECT TO app_user USING (user_id = current_setting('app.user_id')::uuid);The parameterised version sends the query and the value separately, so the database never parses user input as SQL.
Try it
Safe practice or serious risk? Decide for each.
Building a WHERE clause by concatenating a search box value.
The web app connects as a user with only SELECT/INSERT/UPDATE on its own tables.
Storing passwords as bcrypt hashes with a per-user salt.
Taking backups nightly but never testing a restore.
Adding an index on every column just in case.
Challenge
A school portal query `SELECT * FROM grades WHERE student_id = ` + input takes 9 seconds and lets any logged-in student read anyone's grades. Write an incident plan: fix the injection, fix the access control, and fix the performance.
Pick whichever way suits you — every mode earns the same bonus XP.
Write at least 40 more characters to submit.
Mark your own work
Guided walkthrough — 0/3 clues revealed
- Clue 1 locked — reveal it only if you get stuck.
- Clue 2 locked — reveal it only if you get stuck.
- Clue 3 locked — reveal it only if you get stuck.
Each clue costs 5 XP (never below 25 XP). You'd earn 50 XP right now.
Extension: Add a composite index on (student_id, term) and explain why column order matters.