|
|
|
Security Considerations
|
|
|
|
=======================
|
|
|
|
|
|
|
|
Web applications usually face all kinds of security problems and it's very
|
|
|
|
hard to get everything right. Flask tries to solve a few of these things
|
|
|
|
for you, but there are a couple more you have to take care of yourself.
|
|
|
|
|
|
|
|
.. _xss:
|
|
|
|
|
|
|
|
Cross-Site Scripting (XSS)
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
Cross site scripting is the concept of injecting arbitrary HTML (and with
|
|
|
|
it JavaScript) into the context of a website. To remedy this, developers
|
|
|
|
have to properly escape text so that it cannot include arbitrary HTML
|
|
|
|
tags. For more information on that have a look at the Wikipedia article
|
|
|
|
on `Cross-Site Scripting
|
|
|
|
<https://en.wikipedia.org/wiki/Cross-site_scripting>`_.
|
|
|
|
|
|
|
|
Flask configures Jinja2 to automatically escape all values unless
|
|
|
|
explicitly told otherwise. This should rule out all XSS problems caused
|
|
|
|
in templates, but there are still other places where you have to be
|
|
|
|
careful:
|
|
|
|
|
|
|
|
- generating HTML without the help of Jinja2
|
|
|
|
- calling :class:`~flask.Markup` on data submitted by users
|
|
|
|
- sending out HTML from uploaded files, never do that, use the
|
|
|
|
``Content-Disposition: attachment`` header to prevent that problem.
|
|
|
|
- sending out textfiles from uploaded files. Some browsers are using
|
|
|
|
content-type guessing based on the first few bytes so users could
|
|
|
|
trick a browser to execute HTML.
|
|
|
|
|
|
|
|
Another thing that is very important are unquoted attributes. While
|
|
|
|
Jinja2 can protect you from XSS issues by escaping HTML, there is one
|
|
|
|
thing it cannot protect you from: XSS by attribute injection. To counter
|
|
|
|
this possible attack vector, be sure to always quote your attributes with
|
|
|
|
either double or single quotes when using Jinja expressions in them:
|
|
|
|
|
|
|
|
.. sourcecode:: html+jinja
|
|
|
|
|
|
|
|
<a href="{{ href }}">the text</a>
|
|
|
|
|
|
|
|
Why is this necessary? Because if you would not be doing that, an
|
|
|
|
attacker could easily inject custom JavaScript handlers. For example an
|
|
|
|
attacker could inject this piece of HTML+JavaScript:
|
|
|
|
|
|
|
|
.. sourcecode:: html
|
|
|
|
|
|
|
|
onmouseover=alert(document.cookie)
|
|
|
|
|
|
|
|
When the user would then move with the mouse over the link, the cookie
|
|
|
|
would be presented to the user in an alert window. But instead of showing
|
|
|
|
the cookie to the user, a good attacker might also execute any other
|
|
|
|
JavaScript code. In combination with CSS injections the attacker might
|
|
|
|
even make the element fill out the entire page so that the user would
|
|
|
|
just have to have the mouse anywhere on the page to trigger the attack.
|
|
|
|
|
|
|
|
Cross-Site Request Forgery (CSRF)
|
|
|
|
---------------------------------
|
|
|
|
|
|
|
|
Another big problem is CSRF. This is a very complex topic and I won't
|
|
|
|
outline it here in detail just mention what it is and how to theoretically
|
|
|
|
prevent it.
|
|
|
|
|
|
|
|
If your authentication information is stored in cookies, you have implicit
|
|
|
|
state management. The state of "being logged in" is controlled by a
|
|
|
|
cookie, and that cookie is sent with each request to a page.
|
|
|
|
Unfortunately that includes requests triggered by 3rd party sites. If you
|
|
|
|
don't keep that in mind, some people might be able to trick your
|
|
|
|
application's users with social engineering to do stupid things without
|
|
|
|
them knowing.
|
|
|
|
|
|
|
|
Say you have a specific URL that, when you sent ``POST`` requests to will
|
|
|
|
delete a user's profile (say ``http://example.com/user/delete``). If an
|
|
|
|
attacker now creates a page that sends a post request to that page with
|
|
|
|
some JavaScript they just have to trick some users to load that page and
|
|
|
|
their profiles will end up being deleted.
|
|
|
|
|
|
|
|
Imagine you were to run Facebook with millions of concurrent users and
|
|
|
|
someone would send out links to images of little kittens. When users
|
|
|
|
would go to that page, their profiles would get deleted while they are
|
|
|
|
looking at images of fluffy cats.
|
|
|
|
|
|
|
|
How can you prevent that? Basically for each request that modifies
|
|
|
|
content on the server you would have to either use a one-time token and
|
|
|
|
store that in the cookie **and** also transmit it with the form data.
|
|
|
|
After receiving the data on the server again, you would then have to
|
|
|
|
compare the two tokens and ensure they are equal.
|
|
|
|
|
|
|
|
Why does Flask not do that for you? The ideal place for this to happen is
|
|
|
|
the form validation framework, which does not exist in Flask.
|
|
|
|
|
|
|
|
.. _json-security:
|
|
|
|
|
|
|
|
JSON Security
|
|
|
|
-------------
|
|
|
|
|
|
|
|
In Flask 0.10 and lower, :func:`~flask.jsonify` did not serialize top-level
|
|
|
|
arrays to JSON. This was because of a security vulnerability in ECMAScript 4.
|
|
|
|
|
|
|
|
ECMAScript 5 closed this vulnerability, so only extremely old browsers are
|
|
|
|
still vulnerable. All of these browsers have `other more serious
|
|
|
|
vulnerabilities
|
|
|
|
<https://github.com/pallets/flask/issues/248#issuecomment-59934857>`_, so
|
|
|
|
this behavior was changed and :func:`~flask.jsonify` now supports serializing
|
|
|
|
arrays.
|
|
|
|
|
|
|
|
|
|
|
|
SSL/HTTPS
|
|
|
|
---------
|
|
|
|
|
|
|
|
For implementing HTTPS on your server.
|
|
|
|
|
|
|
|
Below are some packages that implement this protocol:
|
|
|
|
|
|
|
|
* `flask-talisman <https://github.com/GoogleCloudPlatform/flask-talisman>`_
|
|
|
|
* `flask-sslify <https://github.com/kennethreitz/flask-sslify>`_
|
|
|
|
* `flask-secure-headers <https://github.com/twaldear/flask-secure-headers>`_
|
|
|
|
|
|
|
|
Security Headers
|
|
|
|
----------------
|
|
|
|
|
|
|
|
This section contains a list of headers supported by Flask and some packages that implements them.
|
|
|
|
|
|
|
|
`Content Security Policy <https://csp.withgoogle.com/docs/index.html>`_ (CSP)
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Enhance security and prevents common web vulnerabilities such as cross-site scripting and MITM related attacks.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
.. sourcecode:: html
|
|
|
|
|
|
|
|
Content-Security-Policy: default-src https:; script-src 'nonce-{random}'; object-src 'none'
|
|
|
|
|
|
|
|
|
|
|
|
See also `Content Security Policy <https://csp.withgoogle.com/docs/index.html>`_.
|
|
|
|
|
|
|
|
* `flask-talisman <https://github.com/GoogleCloudPlatform/flask-talisman>`_
|
|
|
|
* `flask-csp <https://github.com/twaldear/flask-csp>`_
|
|
|
|
* `flask-secure-headers <https://github.com/twaldear/flask-secure-headers>`_
|
|
|
|
|
|
|
|
`HTTP Strict Transport Security <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security>`_ (HSTS)
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Redirects http requests to https on all urls, preventing MITM attacks.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
.. sourcecode:: html
|
|
|
|
|
|
|
|
Strict-Transport-Security: max-age=<expire-time
|
|
|
|
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
|
|
|
|
Strict-Transport-Security: max-age=<expire-time>; preload
|
|
|
|
|
|
|
|
See also `Strict Transport Security <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security>`_.
|
|
|
|
|
|
|
|
* `flask-talisman <https://github.com/GoogleCloudPlatform/flask-talisman>`_
|
|
|
|
* `flask-sslify <https://github.com/kennethreitz/flask-sslify>`_
|
|
|
|
* `flask-secure-headers <https://github.com/twaldear/flask-secure-headers>`_
|
|
|
|
|
|
|
|
`X-FRAME-OPTIONS <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options>`_ (Clickjacking protection)
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Prevents the client from clicking page elements outside of the website, avoiding hijacking or UI redress attacks.
|
|
|
|
|
|
|
|
.. sourcecode:: html
|
|
|
|
|
|
|
|
X-Frame-Options: DENY
|
|
|
|
X-Frame-Options: SAMEORIGIN
|
|
|
|
X-Frame-Options: ALLOW-FROM https://example.com/
|
|
|
|
|
|
|
|
See also `X-Frame-Options <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options>`_.
|
|
|
|
|
|
|
|
* `flask-talisman <https://github.com/GoogleCloudPlatform/flask-talisman>`_
|
|
|
|
* `flask-secure-headers <https://github.com/twaldear/flask-secure-headers>`_
|
|
|
|
|
|
|
|
`X-Content-Type-Options <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options>`_
|
|
|
|
-------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Prevents XSS by blocking requests on clients and forcing them to read the content type instead of first opening it.
|
|
|
|
|
|
|
|
.. sourcecode:: html
|
|
|
|
|
|
|
|
X-Content-Type-Options: nosniff
|
|
|
|
|
|
|
|
See also `X-Content-Type-Options <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options>`_.
|
|
|
|
|
|
|
|
* `flask-talisman <https://github.com/GoogleCloudPlatform/flask-talisman>`_
|
|
|
|
* `flask-secure-headers <https://github.com/twaldear/flask-secure-headers>`_
|
|
|
|
|
|
|
|
`Cookie options <https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies>`_
|
|
|
|
----------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
For setting cookies on client-side storage.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
.. sourcecode:: html
|
|
|
|
|
|
|
|
Set-Cookie: [cookie-name]=[cookie-value]
|
|
|
|
|
|
|
|
See also `HTTP cookies <https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Secure_and_HttpOnly_cookies>`_ .
|
|
|
|
|
|
|
|
* `flask-talisman <https://github.com/GoogleCloudPlatform/flask-talisman>`_
|
|
|
|
* `flask-secure-headers <https://github.com/twaldear/flask-secure-headers>`_
|
|
|
|
|
|
|
|
`HTTP Public Key Pinning <https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning>`_ (HPKP)
|
|
|
|
-------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
For associating clients with web servers through a certificate key and prevent MITM attacks.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
.. sourcecode:: html
|
|
|
|
|
|
|
|
Public-Key-Pins: pin-sha256="base64=="; max-age=expireTime [; includeSubDomains][; report-uri="reportURI"]
|
|
|
|
|
|
|
|
See also `Public Key Pinning <https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning>`_.
|
|
|
|
|
|
|
|
* `flask-talisman <https://github.com/GoogleCloudPlatform/flask-talisman>`_
|
|
|
|
* `flask-secure-headers <https://github.com/twaldear/flask-secure-headers>`_
|
|
|
|
|
|
|
|
References
|
|
|
|
-----------
|
|
|
|
|
|
|
|
* https://docs.djangoproject.com/en/1.11/topics/security/
|
|
|
|
* https://blog.appcanary.com/2017/http-security-headers.html
|
|
|
|
* https://developer.mozilla.org
|
|
|
|
* https://csp.withgoogle.com/docs/index.html
|