What You Get, and How It Gets Undone

Four classic vulnerabilities, handled by default.

SQL injection: the ORM parameterises every query.

Cross-site scripting: templates escape values.

Cross-site request forgery: the token on every POST form.

Clickjacking: middleware sends the right header.

You get all four for free. What follows is how each one gets turned off.

The same query, twice

Safe

# safe: parameterised
Post.objects.filter(
    title=user_input
)

# safe: parameters passed
Post.objects.raw(
    "SELECT * FROM p WHERE t = %s",
    [user_input],
)

Injectable

# unsafe: string built by hand
Post.objects.raw(
    "SELECT * FROM p WHERE t = '%s'"
    % user_input
)

# the input can end the quote
# and add its own SQL
Compare → The ORM is safe. raw() with parameters is safe. raw() with string formatting is the one real way to reintroduce SQL injection into a Django project, and it looks almost identical.

The other three, undone.

|safe on user content turns off escaping for exactly the value most likely to be hostile.

@csrf_exempt removes CSRF protection from a view. Almost nobody needs it, and it is usually applied to silence an error rather than to solve one.

mark_safe() on anything a person typed is the same mistake as |safe, in Python.

Mark this lesson complete

Signed in, your progress follows you to every device.

Next: Settings That Matter →
← Back