From 5483f5d694ffc0c480245a54bb7c688fa6748428 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Mon, 21 Mar 2022 22:54:27 +0100 Subject: [PATCH] Security update - Use CSRF token protection for forms, make "remove password" use HTTP Post (#484) --- changedetectionio/__init__.py | 11 +++-- changedetectionio/forms.py | 2 + changedetectionio/templates/edit.html | 1 + changedetectionio/templates/import.html | 1 + changedetectionio/templates/login.html | 1 + changedetectionio/templates/scrub.html | 1 + changedetectionio/templates/settings.html | 14 +++--- .../templates/watch-overview.html | 1 + changedetectionio/tests/conftest.py | 3 ++ .../tests/test_access_control.py | 44 ++++++++++++------- changedetectionio/tests/test_backend.py | 1 + requirements.txt | 2 +- 12 files changed, 54 insertions(+), 28 deletions(-) diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index 3ea9020c..f887c05c 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -35,6 +35,7 @@ from flask import ( url_for, ) from flask_login import login_required +from flask_wtf import CSRFProtect from changedetectionio import html_tools @@ -72,6 +73,9 @@ app.config['LOGIN_DISABLED'] = False # Disables caching of the templates app.config['TEMPLATES_AUTO_RELOAD'] = True +csrf = CSRFProtect() +csrf.init_app(app) + notification_debug_log=[] def init_app_secret(datastore_path): @@ -610,16 +614,15 @@ def changedetection_app(config=None, datastore_o=None): form.notification_format.data = datastore.data['settings']['application']['notification_format'] form.base_url.data = datastore.data['settings']['application']['base_url'] - # Password unset is a GET, but we can lock the session to always need the password - if not os.getenv("SALTED_PASS", False) and request.values.get('removepassword') == 'yes': - from pathlib import Path + if request.method == 'POST' and form.data.get('removepassword_button') == True: + # Password unset is a GET, but we can lock the session to a salted env password to always need the password + if not os.getenv("SALTED_PASS", False): datastore.data['settings']['application']['password'] = False flash("Password protection removed.", 'notice') flask_login.logout_user() return redirect(url_for('settings_page')) if request.method == 'POST' and form.validate(): - datastore.data['settings']['application']['notification_urls'] = form.notification_urls.data datastore.data['settings']['requests']['minutes_between_check'] = form.minutes_between_check.data datastore.data['settings']['application']['extract_title_as_title'] = form.extract_title_as_title.data diff --git a/changedetectionio/forms.py b/changedetectionio/forms.py index df5d6336..b3ffc547 100644 --- a/changedetectionio/forms.py +++ b/changedetectionio/forms.py @@ -353,3 +353,5 @@ class globalSettingsForm(commonSettingsForm): global_subtractive_selectors = StringListField('Remove elements', [ValidateCSSJSONXPATHInput(allow_xpath=False, allow_json=False)]) global_ignore_text = StringListField('Ignore Text', [ValidateListRegex()]) ignore_whitespace = BooleanField('Ignore whitespace') + save_button = SubmitField('Save', render_kw={"class": "pure-button pure-button-primary"}) + removepassword_button = SubmitField('Remove password', render_kw={"class": "pure-button pure-button-primary"}) \ No newline at end of file diff --git a/changedetectionio/templates/edit.html b/changedetectionio/templates/edit.html index 0f10c8fa..74d41725 100644 --- a/changedetectionio/templates/edit.html +++ b/changedetectionio/templates/edit.html @@ -19,6 +19,7 @@
+
diff --git a/changedetectionio/templates/import.html b/changedetectionio/templates/import.html index 943e580d..e9376fc4 100644 --- a/changedetectionio/templates/import.html +++ b/changedetectionio/templates/import.html @@ -4,6 +4,7 @@
+
Enter one URL per line, and optionally add tags for each URL after a space, delineated by comma (,): diff --git a/changedetectionio/templates/login.html b/changedetectionio/templates/login.html index 32259930..2e24ddb4 100644 --- a/changedetectionio/templates/login.html +++ b/changedetectionio/templates/login.html @@ -4,6 +4,7 @@