From 1d65c1bca06c0c0cbaae004fd18e2e361713dcd6 Mon Sep 17 00:00:00 2001 From: Lukas Braun <lukas.braun@fau.de> Date: Wed, 25 Jul 2018 19:01:54 +0200 Subject: [PATCH] Check Origin header before accept/edit/delete For some protection against CSRF attacks, check if the Origin header is the weburl we are listening on before handling POSTs to moderation/{edit,accept}/<doc>. If the request does not contain an Origin header (which should never be the case for POST requests in modern browsers), a warning is printed and the request handled anyway. It is probably a good idea to implement some CSRF token mechanism to authenticate requests as well, I'm not sure how robust this Origin checking stuff really is. --- util/web.py | 11 ++++++++++- web/views.py | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/util/web.py b/util/web.py index db5fbac..b051c9a 100644 --- a/util/web.py +++ b/util/web.py @@ -6,8 +6,9 @@ from jinja2.exceptions import TemplateNotFound from werkzeug import Local, LocalManager, Response from werkzeug.routing import Map, Rule -from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import BadRequest, Forbidden +import sys import os import netaddr @@ -117,6 +118,14 @@ def remote_is_internal_network(request): return False +def same_origin_only(request): + try: + if request.headers['Origin'] != config.weburl: + raise Forbidden(description="Same-Origin check failed") + except KeyError: + sys.stderr.write("WARNING: No Origin header in request for protected endpoint!\n"); + + available_themes = set([it[1] for it in config.themes_by_url]) available_themes.add(config.default_theme) jinja_env = Environment(loader=ThemeSupportTemplateLoader(available_themes), cache_size=0) diff --git a/web/views.py b/web/views.py index 3743283..35c2b05 100644 --- a/web/views.py +++ b/web/views.py @@ -23,7 +23,7 @@ import datetime from util.web import expose, render_template, profify, completion_hints, \ update_meta_from_request, theme_for_url, local, \ - remote_is_internal_network + remote_is_internal_network, same_origin_only from util.readMetaData import readMeta from util.general import canonicalize_title, trim_pdf, empty_metadata from util.univis import get_univis_metadata @@ -243,6 +243,8 @@ def upload(request): def edit_submit(request, document): failed = False if request.method == 'POST': + same_origin_only(request) + if document in public_pdf_db: entry = public_pdf_db[document] @@ -310,6 +312,8 @@ def moderate(request, failed=None): @expose('/moderation/accept/<document>/') def edit_article(request, document): if request.method == 'POST': + same_origin_only(request) + if document in moderation_queue_db: entry = moderation_queue_db[document] result = update_meta_from_request(entry, request.form) -- GitLab