mirror of https://github.com/JohnHammond/CTFd.git
Bypass csrf plugins (#597)
* Add bypass_csrf_protection decorator * Add beta notice * Add test_bypass_csrf_protectionselenium-screenshot-testing
parent
c0e418d900
commit
aedd753f4e
|
@ -125,6 +125,19 @@ def get_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):
|
||||
"""
|
||||
Searches for the load function in modules in the CTFd/plugins folder. This function is called with the current CTFd
|
||||
|
|
|
@ -190,6 +190,9 @@ def init_utils(app):
|
|||
|
||||
@app.before_request
|
||||
def csrf():
|
||||
func = app.view_functions[request.endpoint]
|
||||
if hasattr(func, '_bypass_csrf'):
|
||||
return
|
||||
if not session.get('nonce'):
|
||||
session['nonce'] = sha512(os.urandom(10))
|
||||
if request.method == "POST":
|
||||
|
|
|
@ -12,7 +12,8 @@ from CTFd.plugins import (
|
|||
register_admin_plugin_menu_bar,
|
||||
get_admin_plugin_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 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.route == '/test_user_href'
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue