Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed #14261 - Added clickjacking protection (X-Frame-Options header)
Many thanks to rniemeyer for the patch! git-svn-id: http://code.djangoproject.com/svn/django/trunk@16298 bcc190cf-cafb-0310-a4f2-bffc1f526a37
- Loading branch information
1 parent
dc4c2f3
commit 524c5fa
Showing
13 changed files
with
453 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
""" | ||
Clickjacking Protection Middleware. | ||
This module provides a middleware that implements protection against a | ||
malicious site loading resources from your site in a hidden frame. | ||
""" | ||
|
||
from django.conf import settings | ||
|
||
class XFrameOptionsMiddleware(object): | ||
""" | ||
Middleware that sets the X-Frame-Options HTTP header in HTTP responses. | ||
Does not set the header if it's already set or if the response contains | ||
a xframe_options_exempt value set to True. | ||
By default, sets the X-Frame-Options header to 'SAMEORIGIN', meaning the | ||
response can only be loaded on a frame within the same site. To prevent the | ||
response from being loaded in a frame in any site, set X_FRAME_OPTIONS in | ||
your project's Django settings to 'DENY'. | ||
Note: older browsers will quietly ignore this header, thus other | ||
clickjacking protection techniques should be used if protection in those | ||
browsers is required. | ||
http://en.wikipedia.org/wiki/Clickjacking#Server_and_client | ||
""" | ||
def process_response(self, request, response): | ||
# Don't set it if it's already in the response | ||
if response.get('X-Frame-Options', None) is not None: | ||
return response | ||
|
||
# Don't set it if they used @xframe_options_exempt | ||
if getattr(response, 'xframe_options_exempt', False): | ||
return response | ||
|
||
response['X-Frame-Options'] = self.get_xframe_options_value(request, | ||
response) | ||
return response | ||
|
||
def get_xframe_options_value(self, request, response): | ||
""" | ||
Gets the value to set for the X_FRAME_OPTIONS header. | ||
By default this uses the value from the X_FRAME_OPTIONS Django | ||
settings. If not found in settings, defaults to 'SAMEORIGIN'. | ||
This method can be overridden if needed, allowing it to vary based on | ||
the request or response. | ||
""" | ||
return getattr(settings, 'X_FRAME_OPTIONS', 'SAMEORIGIN').upper() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
from functools import wraps | ||
|
||
from django.utils.decorators import available_attrs | ||
|
||
|
||
def xframe_options_deny(view_func): | ||
""" | ||
Modifies a view function so its response has the X-Frame-Options HTTP | ||
header set to 'DENY' as long as the response doesn't already have that | ||
header set. | ||
e.g. | ||
@xframe_options_deny | ||
def some_view(request): | ||
... | ||
""" | ||
def wrapped_view(*args, **kwargs): | ||
resp = view_func(*args, **kwargs) | ||
if resp.get('X-Frame-Options', None) is None: | ||
resp['X-Frame-Options'] = 'DENY' | ||
return resp | ||
return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) | ||
|
||
|
||
def xframe_options_sameorigin(view_func): | ||
""" | ||
Modifies a view function so its response has the X-Frame-Options HTTP | ||
header set to 'SAMEORIGIN' as long as the response doesn't already have | ||
that header set. | ||
e.g. | ||
@xframe_options_sameorigin | ||
def some_view(request): | ||
... | ||
""" | ||
def wrapped_view(*args, **kwargs): | ||
resp = view_func(*args, **kwargs) | ||
if resp.get('X-Frame-Options', None) is None: | ||
resp['X-Frame-Options'] = 'SAMEORIGIN' | ||
return resp | ||
return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) | ||
|
||
|
||
def xframe_options_exempt(view_func): | ||
""" | ||
Modifies a view function by setting a response variable that instructs | ||
XFrameOptionsMiddleware to NOT set the X-Frame-Options HTTP header. | ||
e.g. | ||
@xframe_options_exempt | ||
def some_view(request): | ||
... | ||
""" | ||
def wrapped_view(*args, **kwargs): | ||
resp = view_func(*args, **kwargs) | ||
resp.xframe_options_exempt = True | ||
return resp | ||
return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
======================== | ||
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. | ||
|
||
.. versionadded:: 1.4 | ||
The clickjacking middleware and decorators were added. | ||
|
||
.. _clickjacking: http://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 site and clicks "I Like Ponies" he will inadvertently | ||
click on the online store's "Buy Now" button and unknowningly purchase 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. | ||
|
||
.. _X-Frame-Options: https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header | ||
|
||
Django provides a few simple ways to include this header in responses from your | ||
site: | ||
|
||
1. A simple 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. | ||
|
||
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, add | ||
``'django.middleware.clickjacking.XFrameOptionsMiddleware'`` to | ||
:setting:`MIDDLEWARE_CLASSES`:: | ||
|
||
MIDDLEWARE_CLASSES = ( | ||
... | ||
'django.middleware.clickjacking.XFrameOptionsMiddleware', | ||
... | ||
) | ||
|
||
By default, the middleware will set the X-Frame-Options header to SAMEORIGIN for | ||
every outgoing ``HttpResponse``. If you want DENY instead, set the | ||
:setting:`X_FRAME_OPTIONS` setting:: | ||
|
||
X_FRAME_OPTIONS = 'DENY' | ||
|
||
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 to not 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.") | ||
|
||
|
||
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+ | ||
* Firefox 3.6.9+ | ||
* Opera 10.5+ | ||
* Safari 4+ | ||
* Chrome 4.1+ | ||
|
||
See also | ||
~~~~~~~~ | ||
|
||
A `complete list`_ of browsers supporting X-Frame-Options. | ||
|
||
.. _complete list: https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header#Browser_compatibility | ||
.. _other clickjacking prevention techniques: http://en.wikipedia.org/wiki/Clickjacking#Prevention |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ API Reference | |
:maxdepth: 1 | ||
|
||
authbackends | ||
clickjacking | ||
contrib/index | ||
databases | ||
django-admin | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.