Commit 38979178 authored by Andreas Valder's avatar Andreas Valder

added CSRF protection, closes #75

parent bdfe0846
This diff is collapsed.
...@@ -32,18 +32,3 @@ Optional (wird für einzelne Features benötigt): ...@@ -32,18 +32,3 @@ Optional (wird für einzelne Features benötigt):
* python-ldap (Login mit Fachschaftsaccount) * python-ldap (Login mit Fachschaftsaccount)
* python-icalendar (SoGo-Kalenderimport für Sitzungsankündigungen) * python-icalendar (SoGo-Kalenderimport für Sitzungsankündigungen)
* python-mysql-connector (wenn MySQL als Datenbank verwendet werden soll) * python-mysql-connector (wenn MySQL als Datenbank verwendet werden soll)
# Lizenz
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License Version 2
as published by the Free Software Foundation;
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
...@@ -9,6 +9,7 @@ import hashlib ...@@ -9,6 +9,7 @@ import hashlib
import random import random
import sched import sched
import traceback import traceback
import string
app = Flask(__name__) app = Flask(__name__)
...@@ -70,6 +71,21 @@ def mod_required(func): ...@@ -70,6 +71,21 @@ def mod_required(func):
return func(*args, **kwargs) return func(*args, **kwargs)
return decorator return decorator
def csrf_protect(func):
@wraps(func)
def decorator(*args, **kwargs):
if '_csrf_token' in request.values:
token = request.values['_csrf_token']
elif '_csrf_token' in request.get_json():
token = request.get_json()['_csrf_token']
else:
token = none
if not ('_csrf_token' in session) or (session['_csrf_token'] != token ) or not token:
return 'csrf test failed', 403
else:
return func(*args, **kwargs)
return decorator
def evalperm(perms): def evalperm(perms):
cperms = [] cperms = []
lperms = [] lperms = []
...@@ -379,6 +395,7 @@ def login(): ...@@ -379,6 +395,7 @@ def login():
modify('INSERT INTO users (name, realname, fsacc, level, calendar_key, rfc6238) VALUES (?, ?, ?, 1, "", "")', user, session['user']['givenName'], user) modify('INSERT INTO users (name, realname, fsacc, level, calendar_key, rfc6238) VALUES (?, ?, ?, 1, "", "")', user, session['user']['givenName'], user)
dbuser = query('SELECT * FROM users WHERE name = ?', user) dbuser = query('SELECT * FROM users WHERE name = ?', user)
session['user']['dbid'] = dbuser[0]['id'] session['user']['dbid'] = dbuser[0]['id']
session['_csrf_token'] = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(128))
return redirect(request.values.get('ref', url_for('index'))) return redirect(request.values.get('ref', url_for('index')))
@app.route('/logout', methods=['GET', 'POST']) @app.route('/logout', methods=['GET', 'POST'])
...@@ -412,10 +429,12 @@ tabs = { ...@@ -412,10 +429,12 @@ tabs = {
@app.route('/edit', methods=['GET', 'POST']) @app.route('/edit', methods=['GET', 'POST'])
@mod_required @mod_required
@csrf_protect
def edit(prefix='', ignore=[]): def edit(prefix='', ignore=[]):
# All editable tables are expected to have a 'time_updated' field # All editable tables are expected to have a 'time_updated' field
ignore.append('ref') ignore.append('ref')
ignore.append('prefix') ignore.append('prefix')
ignore.append('_csrf_token')
if not prefix and 'prefix' in request.args: if not prefix and 'prefix' in request.args:
prefix = request.args['prefix'] prefix = request.args['prefix']
modify('BEGIN') modify('BEGIN')
...@@ -439,6 +458,7 @@ def edit(prefix='', ignore=[]): ...@@ -439,6 +458,7 @@ def edit(prefix='', ignore=[]):
@app.route('/new/<table>', methods=['GET', 'POST']) @app.route('/new/<table>', methods=['GET', 'POST'])
@mod_required @mod_required
@csrf_protect
def create(table): def create(table):
assert table in tabs assert table in tabs
defaults = {'created_by': session['user']['dbid'], 'time_created': datetime.now(), 'time_updated': datetime.now()} defaults = {'created_by': session['user']['dbid'], 'time_created': datetime.now(), 'time_updated': datetime.now()}
...@@ -450,9 +470,9 @@ def create(table): ...@@ -450,9 +470,9 @@ def create(table):
values.append(val) values.append(val)
args = request.values args = request.values
if (request.method == 'POST') and (request.get_json()): if (request.method == 'POST') and (request.get_json()):
args = request.get_json() args = request.get_json().items()
for column, val in args.items(): for column, val in args:
if column == 'ref': if (column == 'ref') or (column == '_csrf_token'):
continue continue
assert column in tabs[table][2]+tabs[table][3] assert column in tabs[table][2]+tabs[table][3]
assert column not in defaults assert column not in defaults
......
var moderator = { var moderator = {
api: { api: {
csrf_token: '',
init: function () { init: function () {
}, },
...@@ -9,6 +10,7 @@ var moderator = { ...@@ -9,6 +10,7 @@ var moderator = {
moderator.api.set_multi(req,reload) moderator.api.set_multi(req,reload)
}, },
set_multi: function(dict,reload) { set_multi: function(dict,reload) {
dict['_csrf_token'] = moderator.api.csrf_token;
$.ajax({ $.ajax({
method: "POST", method: "POST",
url: "/edit", url: "/edit",
...@@ -23,6 +25,7 @@ var moderator = { ...@@ -23,6 +25,7 @@ var moderator = {
}); });
}, },
add_new: function(value,type,reload) { add_new: function(value,type,reload) {
value['_csrf_token'] = moderator.api.csrf_token;
$.ajax({ $.ajax({
method: "POST", method: "POST",
url: "/new/"+type, url: "/new/"+type,
...@@ -42,7 +45,11 @@ var moderator = { ...@@ -42,7 +45,11 @@ var moderator = {
url: url, url: url,
dataType: "text", dataType: "text",
}) })
},
setcsrftoken: function (token) {
moderator.api.csrf_token = token;
} }
}, },
editor: { editor: {
init: function() { init: function() {
......
...@@ -147,7 +147,8 @@ ...@@ -147,7 +147,8 @@
{% if ismod() %} {% if ismod() %}
<script> <script>
$( function () { $( function () {
moderator.permissioneditor.setpermissions({{global_permissions|tojson|safe}}); moderator.permissioneditor.setpermissions({{global_permissions|tojson|safe}});
moderator.api.setcsrftoken('{{ session['_csrf_token'] }}');
}); });
</script> </script>
{% endif %} {% endif %}
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% from 'macros.html' import moderator_permissioneditor %} {% from 'macros.html' import moderator_permissioneditor %}
{% extends "base.html" %} {% extends "base.html" %}
{% block title %} - {{course.title}}{% endblock %} {% block title %}- {{course.title}}{% endblock %}
{% block content %} {% block content %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment