Bypass csrf plugins (#597)

* Add bypass_csrf_protection decorator
* Add beta notice
* Add test_bypass_csrf_protection
selenium-screenshot-testing
Kevin Chung 2018-03-24 22:54:12 -04:00 committed by GitHub
parent c0e418d900
commit aedd753f4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 1 deletions

View File

@ -125,6 +125,19 @@ def get_user_page_menu_bar():
return db_pages() + USER_PAGE_MENU_BAR return db_pages() + USER_PAGE_MENU_BAR
def bypass_csrf_protection(f):
"""
Decorator that allows a route to bypass the need for a CSRF nonce on POST requests.
This should be considered beta and may change in future versions.
:param f: A function that needs to bypass CSRF protection
:return: Returns a function with the _bypass_csrf attribute set which tells CTFd to not require CSRF protection.
"""
f._bypass_csrf = True
return f
def init_plugins(app): def init_plugins(app):
""" """
Searches for the load function in modules in the CTFd/plugins folder. This function is called with the current CTFd Searches for the load function in modules in the CTFd/plugins folder. This function is called with the current CTFd

View File

@ -190,6 +190,9 @@ def init_utils(app):
@app.before_request @app.before_request
def csrf(): def csrf():
func = app.view_functions[request.endpoint]
if hasattr(func, '_bypass_csrf'):
return
if not session.get('nonce'): if not session.get('nonce'):
session['nonce'] = sha512(os.urandom(10)) session['nonce'] = sha512(os.urandom(10))
if request.method == "POST": if request.method == "POST":

View File

@ -12,7 +12,8 @@ from CTFd.plugins import (
register_admin_plugin_menu_bar, register_admin_plugin_menu_bar,
get_admin_plugin_menu_bar, get_admin_plugin_menu_bar,
register_user_page_menu_bar, register_user_page_menu_bar,
get_user_page_menu_bar get_user_page_menu_bar,
bypass_csrf_protection
) )
from freezegun import freeze_time from freezegun import freeze_time
from mock import patch from mock import patch
@ -145,3 +146,29 @@ def test_register_user_page_menu_bar():
assert menu_item.title == 'test_user_menu_link' assert menu_item.title == 'test_user_menu_link'
assert menu_item.route == '/test_user_href' assert menu_item.route == '/test_user_href'
destroy_ctfd(app) destroy_ctfd(app)
def test_bypass_csrf_protection():
"""
Test that the bypass_csrf_protection decorator functions properly
"""
app = create_ctfd()
with app.app_context():
with app.test_client() as client:
r = client.post('/login')
output = r.get_data(as_text=True)
assert r.status_code == 403
def bypass_csrf_protection_test_route():
return "Success", 200
# Hijack an existing route to avoid any kind of hacks to create a test route
app.view_functions['auth.login'] = bypass_csrf_protection(bypass_csrf_protection_test_route)
with app.test_client() as client:
r = client.post('/login')
output = r.get_data(as_text=True)
assert r.status_code == 200
assert output == "Success"
destroy_ctfd(app)