Clickjacking Protection

The clickjacking middleware and decorators provide easy-to-use protection against clickjacking. This type of attack occurs when a malicious site tricks a user into clicking on a concealed element of another site which they have loaded in a hidden frame or iframe.

An example of clickjacking

Suppose an online store has a page where a logged in user can click « Buy Now » to purchase an item. A user has chosen to stay logged into the store all the time for convenience. An attacker site might create an « I Like Ponies » button on one of their own pages, and load the store’s page in a transparent iframe such that the « Buy Now » button is invisibly overlaid on the « I Like Ponies » button. If the user visits the attacker’s site, clicking « I Like Ponies » will cause an inadvertent click on the « Buy Now » button and an unknowing purchase of the item.

Preventing clickjacking

Modern browsers honor the X-Frame-Options HTTP header that indicates whether or not a resource is allowed to load within a frame or iframe. If the response contains the header with a value of SAMEORIGIN then the browser will only load the resource in a frame if the request originated from the same site. If the header is set to DENY then the browser will block the resource from loading in a frame no matter which site made the request.

Django provides a few ways to include this header in responses from your site:

  1. A middleware that sets the header in all responses.
  2. A set of view decorators that can be used to override the middleware or to only set the header for certain views.

The X-Frame-Options HTTP header will only be set by the middleware or view decorators if it is not already present in the response.

How to use it

Setting X-Frame-Options for all responses

To set the same X-Frame-Options value for all responses in your site, put 'django.middleware.clickjacking.XFrameOptionsMiddleware' to MIDDLEWARE:

MIDDLEWARE = [
    ...,
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    ...,
]

This middleware is enabled in the settings file generated by startproject.

By default, the middleware will set the X-Frame-Options header to DENY for every outgoing HttpResponse. If you want any other value for this header instead, set the X_FRAME_OPTIONS setting:

X_FRAME_OPTIONS = "SAMEORIGIN"

When using the middleware there may be some views where you do not want the X-Frame-Options header set. For those cases, you can use a view decorator that tells the middleware not to set the header:

from django.http import HttpResponse
from django.views.decorators.clickjacking import xframe_options_exempt


@xframe_options_exempt
def ok_to_load_in_a_frame(request):
    return HttpResponse("This page is safe to load in a frame on any site.")

Note

If you want to submit a form or access a session cookie within a frame or iframe, you may need to modify the CSRF_COOKIE_SAMESITE or SESSION_COOKIE_SAMESITE settings.

Setting X-Frame-Options per view

To set the X-Frame-Options header on a per view basis, Django provides these decorators:

from django.http import HttpResponse
from django.views.decorators.clickjacking import xframe_options_deny
from django.views.decorators.clickjacking import xframe_options_sameorigin


@xframe_options_deny
def view_one(request):
    return HttpResponse("I won't display in any frame!")


@xframe_options_sameorigin
def view_two(request):
    return HttpResponse("Display in a frame if it's from the same origin as me.")

Note that you can use the decorators in conjunction with the middleware. Use of a decorator overrides the middleware.

Limitations

The X-Frame-Options header will only protect against clickjacking in a modern browser. Older browsers will quietly ignore the header and need other clickjacking prevention techniques.

Browsers that support X-Frame-Options

  • Internet Explorer 8+
  • Edge
  • Firefox 3.6.9+
  • Opera 10.5+
  • Safari 4+
  • Chrome 4.1+

See also

A complete list of browsers supporting X-Frame-Options.