1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
The ``checksecure`` management command
======================================
The ``checksecure`` management command is a "linter" for simple improvements
you could make to your site's security configuration. It just runs a list of
check functions. Each check function can return a set of warnings, or the
empty set if it finds nothing to warn about.
.. contents:: :local:
When to run it
--------------
You can run it in your local development checkout. Your local dev settings
module may not be configured for SSL, so you may want to point it at a
different settings module, either by setting the ``DJANGO_SETTINGS_MODULE``
environment variable, or by passing the ``--settings`` option::
django-admin.py checksecure --settings=production_settings
Or you could run it directly on a production or staging deployment to verify that the correct settings are in use.
You could even make it part of your integration test suite, if you want. The
:py:func:`djangosecure.check.run_checks` function runs all configured checks
and returns the complete set of warnings; you could write a simple test that
asserts that the returned value is empty.
.. _built-in-checks:
Built-in checks
---------------
The following check functions are built-in to django-secure, and will run by
default:
.. py:currentmodule:: djangosecure.check.djangosecure
.. py:function:: check_security_middleware
Warns if :doc:`middleware` is not in your ``MIDDLEWARE_CLASSES``.
.. py:function:: check_sts
Warns if :ref:`SECURE_HSTS_SECONDS` is not set to a non-zero value.
.. py:function:: check_sts_include_subdomains
Warns if :ref:`SECURE_HSTS_INCLUDE_SUBDOMAINS` is not ``True``.
.. py:function:: check_frame_deny
Warns if :ref:`SECURE_FRAME_DENY` is not ``True``.
.. py:function:: check_content_type_nosniff
Warns if :ref:`SECURE_CONTENT_TYPE_NOSNIFF` is not ``True``.
.. py:function:: check_xss_filter
Warns if :ref:`SECURE_BROWSER_XSS_FILTER` is not ``True``.
.. py:function:: check_ssl_redirect
Warns if :ref:`SECURE_SSL_REDIRECT` is not ``True``.
.. py:function:: check_secret_key
Warns if `SECRET_KEY`_ is empty, missing, or has a very low number of different characters.
.. _SECRET_KEY: http://docs.djangoproject.com/en/stable/ref/settings/#secret-key
.. py:currentmodule:: djangosecure.check.sessions
.. py:function:: check_session_cookie_secure
Warns if you appear to be using Django's `session framework`_ and the
`SESSION_COOKIE_SECURE`_ setting is not ``True``. This setting marks
Django's session cookie as a secure cookie, which instructs browsers not to
send it along with any insecure requests. Since it's trivial for a packet
sniffer (e.g. `Firesheep`_) to hijack a user's session if the session cookie
is sent unencrypted, there's really no good excuse not to have this on. (It
will prevent you from using sessions on insecure requests; that's a good
thing).
.. _Firesheep: http://codebutler.com/firesheep
.. _session framework: https://docs.djangoproject.com/en/stable/topics/http/sessions/
.. _SESSION_COOKIE_SECURE: https://docs.djangoproject.com/en/stable/topics/http/sessions/#session-cookie-secure
.. py:function:: check_session_cookie_httponly
Warns if you appear to be using Django's `session framework`_ and the
`SESSION_COOKIE_HTTPONLY`_ setting is not ``True``. This setting marks
Django's session cookie as "HTTPOnly", meaning (in supporting browsers) its
value can't be accessed from client-side scripts. Turning this on makes it
less trivial for an attacker to escalate a cross-site scripting
vulnerability into full hijacking of a user's session. There's not much
excuse for leaving this off, either: if your code depends on reading session
cookies from Javascript, you're probably doing it wrong.
.. _SESSION_COOKIE_HTTPONLY: https://docs.djangoproject.com/en/stable/topics/http/sessions/#session-cookie-httponly
.. py:currentmodule:: djangosecure.check.csrf
.. py:function:: check_csrf_middleware
Warns if you do not have Django's built-in `CSRF protection`_ enabled
globally via the `CSRF view middleware`_. It's important to CSRF protect any
view that modifies server state; if you choose to do that piecemeal via the
`csrf_protect`_ view decorator instead, just disable this check.
.. _CSRF protection: https://docs.djangoproject.com/en/stable/ref/contrib/csrf/
.. _CSRF view middleware: https://docs.djangoproject.com/en/stable/ref/contrib/csrf/#how-to-use-it
.. _csrf_protect: https://docs.djangoproject.com/en/stable/ref/contrib/csrf/#django.views.decorators.csrf.csrf_protect
Suggestions for additional built-in checks (or better, patches implementing
them) are welcome!
Modifying the list of check functions
-------------------------------------
By default, all of the :ref:`built-in checks <built-in-checks>` are run when
you run ``./manage.py checksecure``. However, some of these checks may not be
appropriate for your particular deployment configuration. For instance, if you
do your HTTP->HTTPS redirection in a loadbalancer, it'd be irritating for
``checksecure`` to constantly warn you about not having enabled
:ref:`SECURE_SSL_REDIRECT`. You can customize the list of checks by setting the
:ref:`SECURE_CHECKS` setting; you can just copy the default value and remove a
check or two; you can also write your own :ref:`custom checks <custom-checks>`.
.. _custom-checks:
Writing custom check functions
------------------------------
A ``checksecure`` check function can be any Python function that takes no
arguments and returns a Python iterable of warnings (an empty iterable if it
finds nothing to warn about).
Optionally, the function can have a ``messages`` attribute, which is a
dictionary mapping short warning codes returned by the function (which will be
displayed by ``checksecure`` if run with ``--verbosity=0``) to longer
explanations which will be displayed by ``checksecure`` when running at its
default verbosity level. For instance::
from django.conf import settings
def check_dont_let_the_bad_guys_in():
if settings.LET_THE_BAD_GUYS_IN:
return ["BAD_GUYS_LET_IN"]
return []
check_dont_let_the_bad_guys_in.messages = {
"BAD_GUYS_LET_IN": (
"Longer explanation of why it's a bad idea to let the bad guys in, "
"and how to correct the situation.")
}
|