mirror of
https://github.com/django/django.git
synced 2024-12-23 17:46:27 +00:00
43aa0c103b
There is no need to list old browser versions or point users to
workarounds.
Backport of f302343380
from main.
133 lines
4.7 KiB
Plaintext
133 lines
4.7 KiB
Plaintext
========================
|
|
Clickjacking Protection
|
|
========================
|
|
|
|
.. module:: django.middleware.clickjacking
|
|
:synopsis: Protects against Clickjacking
|
|
|
|
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.
|
|
|
|
.. _clickjacking: https://en.wikipedia.org/wiki/Clickjacking
|
|
|
|
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.
|
|
|
|
.. _clickjacking-prevention:
|
|
|
|
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.
|
|
|
|
.. _X-Frame-Options: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
|
|
|
|
Django provides a few ways to include this header in responses from your site:
|
|
|
|
#. A middleware that sets the header in all responses.
|
|
|
|
#. 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
|
|
:setting:`MIDDLEWARE`::
|
|
|
|
MIDDLEWARE = [
|
|
...,
|
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
|
...,
|
|
]
|
|
|
|
This middleware is enabled in the settings file generated by
|
|
:djadmin:`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 :setting:`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 :setting:`CSRF_COOKIE_SAMESITE` or
|
|
:setting:`SESSION_COOKIE_SAMESITE` settings.
|
|
|
|
.. versionchanged:: 5.0
|
|
|
|
Support for wrapping asynchronous view functions was added to the
|
|
``@xframe_options_exempt`` decorator.
|
|
|
|
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.
|
|
|
|
.. versionchanged:: 5.0
|
|
|
|
Support for wrapping asynchronous view functions was added to the
|
|
``@xframe_options_deny`` and ``@xframe_options_sameorigin`` decorators.
|
|
|
|
Limitations
|
|
===========
|
|
|
|
The ``X-Frame-Options`` header will only protect against clickjacking in
|
|
`modern browsers`_.
|
|
|
|
.. _modern browsers: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options#browser_compatibility
|