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.
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.
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:
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.
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.
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.
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.
X-Frame-Options
¶A complete list of browsers supporting X-Frame-Options
.
déc. 04, 2023