Stack: Django/DRF · Project: TicketFlow Status: Published Prerequisite: Lesson 21 — Authorization
Objectives
- Walk through the OWASP Top 10 (2021) with the concrete attack and the concrete defense on your stack.
- Find and close the weaknesses your own project already has (an honest inventory).
- Learn the triage: what you fix today, what the framework watches, what a pentest audits.
1. A01 — Broken Access Control (the real #1)
Lesson 21's hole (IDOR, role escalation, frontend-only rules). Defenses already implemented: filtered queryset, object permissions, rules in the service, escalation regression tests. The check that is ALWAYS missing: reviewing each new endpoint against lesson 21's matrix — OWASP is not "fixed once", it is a per-PR discipline.
2. A02 — Cryptographic Failures
Sensitive data unencrypted or with weak encryption:
- In transit: mandatory TLS (lesson 01's HSTS), nothing sensitive over HTTP.
- At rest: password hashes with argon2 (20); TOTP secrets encrypted at rest (20); reset tokens hashed.
- Field encryption:
django-fernet-fields/a custom field with a settings/KMS key (23) for what the DB must not read (the buyer's ID document, should the business ask for it). - Never: inventing your own "encryption", MD5/SHA1 for anything security, reversible passwords.
3. A03 — Injection (SQL, commands, templates)
- SQLi: the ORM parameterizes ALWAYS. The hole appears with
.raw(),extra()or cursors with f-strings:cursor.execute(f"SELECT... {user_input}")= injection served. Rule:%sparameters always; if dynamic SQL is unavoidable (order by column), a whitelist of identifiers (13). - Commands:
os.system("convert " + filename)— never:subprocess.run([...], shell=False)with a list, or better: libraries instead of the shell. - Template injection: rendering user input with
Template(...)executes code. Django templates auto-escape; the risk is using the input as the template. - XSS (it fits here in DRF): your API returns JSON and the frontend escapes when rendering (React/Vue do it by default) — the hole appears with
dangerouslySetInnerHTML/v-htmlon user data (the event name with<script>: escape or sanitize with DOMPurify if there is legitimate rich HTML).
4. A04 — Insecure Design / A05 — Security Misconfiguration
Design: the DB invariants (00b/10) and the authorization matrix (21) ARE design security: OWASP rewards preventing at the schema over patching at the view. Misconfiguration — Django's checklist:
DEBUG = False # the stacktrace leaks settings and paths
ALLOWED_HOSTS = ["ticketflow.app"] # prevents host header poisoning
SECURE_SSL_REDIRECT, SECURE_HSTS_SECONDS = True, 31536000
SESSION_COOKIE_SECURE, CSRF_COOKIE_SECURE = True, True
SECURE_CONTENT_TYPE_NOSNIFF, SECURE_REFERRER_POLICY = True, "same-origin"
X_FRAME_OPTIONS = "DENY" # clickjackingpython manage.py check --deploy audits it — put it in the pipeline (41). And DRF's defaults: the browseable API off in production (JSON renderer only) so you don't expose test forms.
5. A07 — Identification/Auth failures + A10 SSRF
Auth: credential stuffing (rate limit 20/23), eternal tokens (18), lax resets (20) — all covered. SSRF (Server-Side Request Forgery): your backend fetches user-supplied URLs (e.g. the organizer's "avatar_url") and an attacker asks for http://169.254.169.254/ (cloud metadata = credentials) or http://localhost:6379/ (your Redis). Defense: domain/scheme whitelist, resolve and block private IPs, never blindly fetch user URLs.
The rest (A06 vulnerable components: pip-audit in CI; A08 deployment integrity: image signatures/pinned dependencies; A09 logging/monitoring: 45/46) is covered in their modules — OWASP is a map, not a sprint.
6. TicketFlow's inventory (exercise)
Your project already has: a parameterized ORM, argon2, HMAC on webhooks, rate limiting, layered authorization, constraints as invariants. Its typical pending holes: check --deploy not passing, browseable API on, some user avatar/image URL (latent SSRF), unsanitized payload logs. The exercises turn them into tickets.
11. Beyond the Top 10: the three attacks the ranking doesn't lead with but that do bite
The Top 10 is a ranking of CATEGORIES; the concrete attacks of backend day-to-day: (1) Mass assignment: the client sends is_staff: true in the profile JSON and the serializer assigns it — the cure: explicit serializers (only the contract's fields, 15) never fields = "__all__" (21 completes it with per-field permissions); (2) Timing attacks: comparing secrets with == leaks through time — the cure: hmac.compare_digest ALWAYS (you already used it in 17/27) and reset responses with uniform timing (20); (3) Dependency confusion / typosquatting: the pip install requests of a typo installs the attacker's package — the cure: a lockfile with hashes (40), a private proxy for internal naming, and 41's pip-audit.
12. The response to a vulnerability: the finding's runbook
Finding (or being reported) a vulnerability is the start of the process, not the end: (1) triage in <24 h: exploitable in YOUR context (40's CVE triage), severity, who decides; (2) containment if it is being exploited: 41's flag/rollback, 23's rate limit, secret revocation (27); (3) fix + regression test (33: the test that reproduces the exploit, now green); (4) responsible disclosure: if it affects users (a breach, 56): the 72 h notification runbook; if not: the discreet changelog; (5) the postmortem (47) with the root question: why didn't the review/pipeline catch it? — and the action that will catch it next time.
The rewards program (security.txt + a security mailbox) turns someone else's report into a gift: TicketFlow's /.well-known/security.txt page with contact, disclosure policy and PGP — 20 lines the honest pentester looks for before reporting to a forum.
- Why is OWASP #1 access control and not injection? What discipline sustains it?
- Explain to a junior why
cursor.execute(f"... {email}")is severe andexecute("... %s", [email])is not. - Your SPA shows
event.descriptionthat the organizer writes with HTML: where is the XSS risk and what decision do you make (escape vs sanitize)? - Why does SSRF aim at
169.254.169.254and what does the attacker get if they pull it off? - Which three
check --deploychecks would fail in your project today?
Continue with the exercises. The solutions only after trying it yourself.