From 34e97658f53334a009d42bb0e08f7cc691f4458b Mon Sep 17 00:00:00 2001 From: nd <git@notandy.de> Date: Tue, 14 Jul 2020 23:04:18 +0200 Subject: [PATCH] fixed csrf protection --- uffd/csrf/csrf.py | 38 +++++++++++++++++++++++--------------- uffd/selfservice/views.py | 2 +- uffd/session/views.py | 3 +++ uffd/user/views.py | 3 ++- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/uffd/csrf/csrf.py b/uffd/csrf/csrf.py index e00e59a3..f63df933 100644 --- a/uffd/csrf/csrf.py +++ b/uffd/csrf/csrf.py @@ -8,23 +8,31 @@ bp = Blueprint("csrf", __name__) csrfEndpoints = [] # pylint: enable=invalid-name -def csrf_protect(func): - csrfEndpoints.append(func.__name__) - @wraps(func) - def decorator(*args, **kwargs): - if '_csrf_token' in request.values: - token = request.values['_csrf_token'] - elif request.get_json() and ('_csrf_token' in request.get_json()): - token = request.get_json()['_csrf_token'] - else: - token = None - if ('_csrf_token' not in session) or (session['_csrf_token'] != token) or not token: - return 'csrf test failed', 403 - return func(*args, **kwargs) - return decorator +def csrf_protect(blueprint=None, endpoint=None): + def wraper(func): + if not endpoint: + if blueprint: + urlendpoint = "{}.{}".format(blueprint.name, func.__name__) + else: + urlendpoint = func.__name__ + csrfEndpoints.append(urlendpoint) + @wraps(func) + def decorator(*args, **kwargs): + if '_csrf_token' in request.values: + token = request.values['_csrf_token'] + elif request.get_json() and ('_csrf_token' in request.get_json()): + token = request.get_json()['_csrf_token'] + else: + token = None + if ('_csrf_token' not in session) or (session['_csrf_token'] != token) or not token: + return 'csrf test failed', 403 + return func(*args, **kwargs) + return decorator + return wraper -@bp.url_defaults +@bp.app_url_defaults def csrf_inject(endpoint, values): + print(endpoint, csrfEndpoints, endpoint not in csrfEndpoints) if endpoint not in csrfEndpoints or not session.get('_csrf_token'): return values['_csrf_token'] = session['_csrf_token'] diff --git a/uffd/selfservice/views.py b/uffd/selfservice/views.py index 5d18eb6d..d23351bb 100644 --- a/uffd/selfservice/views.py +++ b/uffd/selfservice/views.py @@ -26,7 +26,7 @@ def self_index(): return render_template('self.html', user=get_current_user()) @bp.route("/update", methods=(['POST'])) -@csrf_protect +@csrf_protect(blueprint=bp) def self_update(): pass diff --git a/uffd/session/views.py b/uffd/session/views.py index 8c4ffd28..2590b0b7 100644 --- a/uffd/session/views.py +++ b/uffd/session/views.py @@ -1,4 +1,6 @@ import datetime +import random +import string import functools from flask import Blueprint, render_template, request, url_for, redirect, flash, current_app, session @@ -36,6 +38,7 @@ def login(): return redirect(url_for('.login')) session['user_uid'] = user.uid session['logintime'] = datetime.datetime.now().timestamp() + session['_csrf_token'] = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(64)) return redirect(request.values.get('ref', url_for('index'))) def get_current_user(): diff --git a/uffd/user/views.py b/uffd/user/views.py index 03be06e5..8421e59f 100644 --- a/uffd/user/views.py +++ b/uffd/user/views.py @@ -44,6 +44,7 @@ def user_show(uid=None): @bp_user.route("/<int:uid>/update", methods=['POST']) @bp_user.route("/new", methods=['POST']) +@csrf_protect(blueprint=bp_user) def user_update(uid=False): conn = get_conn() if uid: @@ -70,7 +71,7 @@ def user_update(uid=False): return redirect(url_for('.user_list')) @bp_user.route("/<int:uid>/del") -@csrf_protect +@csrf_protect(blueprint=bp_user) def user_delete(uid): conn = get_conn() conn.search(current_app.config["LDAP_BASE_USER"], '(&(objectclass=person)(uidNumber={}))'.format((escape_filter_chars(uid)))) -- GitLab