Skip to content

Commit

Permalink
Implement security best practices using Flask-Talisman
Browse files Browse the repository at this point in the history
  • Loading branch information
Baptiste Jonglez authored and zorun committed Oct 10, 2021
1 parent 7554842 commit e626a1c
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -9,6 +9,7 @@ This document describes changes between each past release.
Breaking changes
----------------

- Enable session cookie security by default (#845)
- Drop support for Python 2 (#483)
- Drop support for Python 3.5 (#571)
- Drop support for MySQL (#743)
Expand All @@ -25,6 +26,7 @@ Security

- Add CSRF validation on destructive actions (#796)
- Ask for private code to delete project or project history (#796)
- Add headers to mitigate Clickjacking, XSS, and other attacks: `X-Frame-Options`, `X-XSS-Protection`, `X-Content-Type-Options`, `Content-Security-Policy`, `Referrer-Policy` (#845)

Added
-----
Expand Down
1 change: 1 addition & 0 deletions conf/entrypoint.sh
Expand Up @@ -21,6 +21,7 @@ ADMIN_PASSWORD = '$ADMIN_PASSWORD'
ALLOW_PUBLIC_PROJECT_CREATION = $ALLOW_PUBLIC_PROJECT_CREATION
ACTIVATE_ADMIN_DASHBOARD = $ACTIVATE_ADMIN_DASHBOARD
BABEL_DEFAULT_TIMEZONE = "$BABEL_DEFAULT_TIMEZONE"
SESSION_COOKIE_SECURE = $SESSION_COOKIE_SECURE
EOF

# Start gunicorn without forking
Expand Down
15 changes: 15 additions & 0 deletions docs/configuration.rst
Expand Up @@ -64,6 +64,21 @@ of the secret key could easily access any project and bypass the private code ve
- **Production value:** `ihatemoney conf-example ihatemoney.cfg` sets it to
something random, which is good.

`SESSION_COOKIE_SECURE`
-----------------------

A boolean that controls whether the session cookie will be marked "secure".
If this is the case, browsers will refuse to send the session cookie over plain HTTP.

- **Default value:** ``True``
- **Production value:** ``True`` if you run your service over HTTPS, ``False`` if you run
your service over plain HTTP.

Note: this setting is actually interpreted by Flask, see the
`Flask documentation`_ for details.

.. _Flask documentation: https://flask.palletsprojects.com/en/2.0.x/config/#SESSION_COOKIE_SECURE

`MAIL_DEFAULT_SENDER`
---------------------

Expand Down
12 changes: 10 additions & 2 deletions docs/contributing.rst
Expand Up @@ -104,12 +104,20 @@ You can create a ``settings.cfg`` file, with the following content::
DEBUG = True
SQLACHEMY_ECHO = DEBUG

You can also set the `TESTING` flag to `True` so no mails are sent
(and no exception is raised) while you're on development mode.
Then before running the application, declare its path with ::

export IHATEMONEY_SETTINGS_FILE_PATH="$(pwd)/settings.cfg"

You can also set the ``TESTING`` flag to ``True`` so no mails are sent
(and no exception is raised) while you're on development mode.

In some cases, you may need to disable secure cookies by setting
``SESSION_COOKIE_SECURE`` to ``False``. This is needed if you
access your dev server over the network: with the default value
of ``SESSION_COOKIE_SECURE``, the browser will refuse to send
the session cookie over insecure HTTP, so many features of Ihatemoney
won't work (project login, language change, etc).

.. _contributing-developer:

Contributing as a developer
Expand Down
11 changes: 11 additions & 0 deletions docs/upgrade.rst
Expand Up @@ -65,6 +65,17 @@ If so, pick the ``pip`` commands to use in the relevant section(s) of

Then follow :ref:`general-procedure` from step 1. in order to complete the update.

Disable session cookie security if running over plain HTTP
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

.. note:: If you are running Ihatemoney over HTTPS, no special action is required.

Session cookies are now marked "secure" by default to increase security.

If you run Ihatemoney over plain HTTP, you need to explicitly disable this security
feature by setting ``SESSION_COOKIE_SECURE`` to ``False``, see :ref:`configuration`.


Switch to MariaDB >= 10.3.2 instead of MySQL
++++++++++++++++++++++++++++++++++++++++++++

Expand Down
4 changes: 4 additions & 0 deletions ihatemoney/conf-templates/ihatemoney.cfg.j2
Expand Up @@ -38,3 +38,7 @@ ACTIVATE_ADMIN_DASHBOARD = False
# You can change the timezone used to display time. By default it will be
#derived from the server OS.
#BABEL_DEFAULT_TIMEZONE = "Europe/Paris"

# Enable secure cookies. Requires HTTPS. Disable if you run your ihatemoney
# service over plain HTTP.
SESSION_COOKIE_SECURE = True
1 change: 1 addition & 0 deletions ihatemoney/default_settings.py
Expand Up @@ -8,6 +8,7 @@
ADMIN_PASSWORD = ""
ALLOW_PUBLIC_PROJECT_CREATION = True
ACTIVATE_ADMIN_DASHBOARD = False
SESSION_COOKIE_SECURE = True
SUPPORTED_LANGUAGES = [
"de",
"el",
Expand Down
19 changes: 19 additions & 0 deletions ihatemoney/run.py
Expand Up @@ -7,6 +7,7 @@
from flask_babel import Babel, format_currency
from flask_mail import Mail
from flask_migrate import Migrate, stamp, upgrade
from flask_talisman import Talisman
from jinja2 import pass_context
from markupsafe import Markup
import pytz
Expand Down Expand Up @@ -126,6 +127,24 @@ def create_app(
instance_relative_config=instance_relative_config,
)

# If we need to load external JS/CSS/image resources, it needs to be added here, see
# https://github.com/wntrblm/flask-talisman#content-security-policy
csp = {
"default-src": ["'self'"],
# We have several inline javascript scripts :(
"script-src": ["'self'", "'unsafe-inline'"],
"object-src": "'none'",
}

Talisman(
app,
# Forcing HTTPS is the job of a reverse proxy
force_https=False,
# This is handled separately through the SESSION_COOKIE_SECURE Flask setting
session_cookie_secure=False,
content_security_policy=csp,
)

# If a configuration object is passed, use it. Otherwise try to find one.
load_configuration(app, configuration)
app.wsgi_app = PrefixedWSGI(app)
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Expand Up @@ -33,6 +33,7 @@ install_requires =
Flask-Migrate>=2.5.3,<4 # Not following semantic versioning (e.g. https://github.com/miguelgrinberg/flask-migrate/commit/1af28ba273de6c88544623b8dc02dd539340294b)
Flask-RESTful>=0.3.9,<1
Flask-SQLAlchemy>=2.4,<3
Flask-Talisman>=0.8,<1
Flask-WTF>=0.14.3,<1
WTForms>=2.3.1,<2.4
Flask>=2,<3
Expand Down

0 comments on commit e626a1c

Please sign in to comment.