added url check

This commit is contained in:
2026-02-20 03:27:42 +01:00
parent e7bff6983f
commit e111a876f7
2 changed files with 20 additions and 0 deletions

View File

@@ -41,6 +41,7 @@ from .utils import (
get_course, get_course,
token_required, token_required,
get_cached_deck_info, get_cached_deck_info,
is_safe_url
) )
@@ -131,6 +132,10 @@ def set_cookie(token):
current_app.logger.debug("next_url not present redirecting to index") current_app.logger.debug("next_url not present redirecting to index")
next_url = url_for("main.index") next_url = url_for("main.index")
if not is_safe_url(next_url):
current_app.logger.warning(f"Blocked unsafe redirect attempt to: {next_url}")
return abort(400)
resp = make_response(redirect(next_url)) resp = make_response(redirect(next_url))
resp.set_cookie( resp.set_cookie(
"access_token", serialize_token(token), httponly=True, samesite="Lax", path="/" "access_token", serialize_token(token), httponly=True, samesite="Lax", path="/"
@@ -260,6 +265,10 @@ def admin_login():
next_page = request.args.get("next") next_page = request.args.get("next")
if next_page and not is_safe_url(next_page):
current_app.logger.warning(f"Blocked unsafe redirect attempt to: {next_page}")
return abort(400)
if next_page: if next_page:
session["next_url"] = next_page session["next_url"] = next_page

View File

@@ -6,6 +6,7 @@ from typing import cast
from itsdangerous import BadSignature, URLSafeSerializer from itsdangerous import BadSignature, URLSafeSerializer
from xkcdpass import xkcd_password from xkcdpass import xkcd_password
from functools import wraps, lru_cache from functools import wraps, lru_cache
from urllib.parse import urlparse, urljoin
from .models import Deck, InfoBanner, Token, db, Course from .models import Deck, InfoBanner, Token, db, Course
@@ -209,3 +210,13 @@ def get_cached_deck_info(token_id, course_folder, deck_slug):
"deck_name": deck_obj.name, "deck_name": deck_obj.name,
"index_file": deck_obj.index_file "index_file": deck_obj.index_file
} }
def is_safe_url(target):
"""
Ensures that a redirect target will lead to the same server.
Handles both relative paths ('/admin') and absolute URLs ('https://yourdomain.com/admin').
"""
ref_url = urlparse(request.host_url)
test_url = urlparse(urljoin(request.host_url, target))
return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc