From 2116b2943a1e8fee096257f3802e555f48b83a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Horvat?= Date: Thu, 13 Oct 2016 21:11:25 +0200 Subject: [PATCH] Fix bug 1308645: Improve frontend security (#477) * Stop using JS in href attributes (Persona sign in blocked by CSP) * Fix CSP-related homepage framing issues on a local setup using HTTP --- pontoon/base/static/js/main.js | 8 ++++ pontoon/base/templates/django/base.html | 2 +- .../socialaccount/authentication_error.html | 2 +- pontoon/base/templates/landing.html | 2 +- pontoon/base/templates/translate.html | 4 +- pontoon/settings/base.py | 46 +++++++++++++++++-- requirements.txt | 2 + 7 files changed, 58 insertions(+), 8 deletions(-) diff --git a/pontoon/base/static/js/main.js b/pontoon/base/static/js/main.js index 3e2d743df..5fb1d39f4 100755 --- a/pontoon/base/static/js/main.js +++ b/pontoon/base/static/js/main.js @@ -422,6 +422,14 @@ var Pontoon = (function (my) { /* Main code */ $(function() { + // Sign in with Persona + $('#persona-sign-in').click(function(e) { + e.preventDefault(); + + var type = $(this).data('type') || 'login'; + allauth.persona.login('', type); + }); + // Show/hide menu on click $('.selector').click(function (e) { if (!$(this).siblings('.menu').is(':visible')) { diff --git a/pontoon/base/templates/django/base.html b/pontoon/base/templates/django/base.html index ed70d2a64..9ebf31050 100644 --- a/pontoon/base/templates/django/base.html +++ b/pontoon/base/templates/django/base.html @@ -45,7 +45,7 @@
  • Help
  • {% if not user.is_authenticated %} -
  • Sign in: Firefox Accounts · Persona
  • +
  • Sign in: Firefox Accounts · Persona
  • {% else %}
  • Sign out
  • {% endif %} diff --git a/pontoon/base/templates/django/socialaccount/authentication_error.html b/pontoon/base/templates/django/socialaccount/authentication_error.html index bf155e7cc..de420f27d 100644 --- a/pontoon/base/templates/django/socialaccount/authentication_error.html +++ b/pontoon/base/templates/django/socialaccount/authentication_error.html @@ -5,5 +5,5 @@ {% block content %}

    Sign In Failure

    An error occurred while attempting to sign in.

    -

    Try again with Firefox Accounts or Persona

    +

    Try again with Firefox Accounts or Persona

    {% endblock %} diff --git a/pontoon/base/templates/landing.html b/pontoon/base/templates/landing.html index 9e2cf29d0..4bc16ab09 100644 --- a/pontoon/base/templates/landing.html +++ b/pontoon/base/templates/landing.html @@ -16,7 +16,7 @@
  • Help
  • {% if not user.is_authenticated() %} -
  • Sign in: Firefox Accounts · Persona
  • +
  • Sign in: Firefox Accounts · Persona
  • {% else %}
  • Sign out
  • {% endif %} diff --git a/pontoon/base/templates/translate.html b/pontoon/base/templates/translate.html index 96f823d09..31bc697a9 100755 --- a/pontoon/base/templates/translate.html +++ b/pontoon/base/templates/translate.html @@ -126,12 +126,12 @@

    Project info

    {% if user.is_authenticated() %} {% if user.logged_via('fxa') and not user.logged_via('persona') %} -
  • Connect with Persona account
  • +
  • Connect with Persona account
  • {% endif %}
  • Sign Out
  • {% else %}
  • Sign in: Firefox Accounts
  • -
  • Sign in: Persona
  • +
  • Sign in: Persona
  • {% endif %} diff --git a/pontoon/settings/base.py b/pontoon/settings/base.py index e83372301..c83cbcc0d 100644 --- a/pontoon/settings/base.py +++ b/pontoon/settings/base.py @@ -136,6 +136,8 @@ def path(*args): 'session_csrf.CsrfMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.security.SecurityMiddleware', + 'csp.middleware.CSPMiddleware', ) CONTEXT_PROCESSORS = ( @@ -471,9 +473,6 @@ def _allowed_hosts(): if not os.environ.get('CI', False): NOSE_ARGS.append('--with-progressive') -# Set X-Frame-Options to DENY by default on all responses. -X_FRAME_OPTIONS = 'DENY' - # General auth settings LOGIN_URL = '/' LOGIN_REDIRECT_URL = '/' @@ -487,9 +486,50 @@ def _allowed_hosts(): # Always generate a CSRF token for anonymous users. ANON_ALWAYS = True +# Set X-Frame-Options to DENY by default on all responses. +X_FRAME_OPTIONS = 'DENY' + # Use correct header for detecting HTTPS on Heroku. SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') +# Strict-Transport-Security: max-age=63072000 +# Ensures users only visit the site over HTTPS +SECURE_HSTS_SECONDS = 63072000 + +# X-Content-Type-Options: nosniff +# Disables browser MIME type sniffing +SECURE_CONTENT_TYPE_NOSNIFF = True + +# x-xss-protection: 1; mode=block +# Activates the browser's XSS filtering and helps prevent XSS attacks +SECURE_BROWSER_XSS_FILTER = True + +# Content-Security-Policy headers +CSP_DEFAULT_SRC = ("'none'",) +CSP_CHILD_SRC = ("https:",) +CSP_FRAME_SRC = ("https:",) # Older browsers +CSP_CONNECT_SRC = ("'self'",) +CSP_FONT_SRC = ("'self'",) +CSP_IMG_SRC = ( + "'self'", + "https://*.wp.com/pontoon.mozilla.org/", + "https://ssl.google-analytics.com", + "https://www.gravatar.com/avatar/", +) +CSP_SCRIPT_SRC = ( + "'self'", + "https://login.persona.org", + "'sha256-x3niK4UU+vG6EGT2NK2rwi2j/etQodJd840oRpEnqd4='", + "'sha256-fDsgbzHC0sNuBdM4W91nXVccgFLwIDkl197QEca/Cl4='", + "https://ssl.google-analytics.com/ga.js", +) +CSP_STYLE_SRC = ("'self'", "'unsafe-inline'",) + +# Needed if site not hosted on HTTPS domains (like local setup) +if not SITE_URL.startswith('https'): + CSP_IMG_SRC = CSP_IMG_SRC + ("http://www.gravatar.com/avatar/",) + CSP_CHILD_SRC = CSP_FRAME_SRC = CSP_FRAME_SRC + ("http:",) + # For absolute urls try: DOMAIN = socket.gethostname() diff --git a/requirements.txt b/requirements.txt index 547de4d3a..03ef50115 100644 --- a/requirements.txt +++ b/requirements.txt @@ -145,3 +145,5 @@ python-openid==2.2.5 \ requests-oauthlib==0.6.1 \ --hash=sha256:905306080ec0cc6b3c65c8101f471fccfdb9994c16dd116524fd3fc0790d46d7 \ --hash=sha256:7c708e8e2a4aa6a905cf91f28420d75db37270e0ec8fc951915c098dd8bde53e +django-csp==3.1 \ + --hash=sha256:9208219c341ddbe371b5fd217ced0c916a5e2f7184bc603415074afcace6b51c