I work on a webpage where language and darkmode are set by a POST form. I just realized that the csrf_token gets leaked in the browser headers for the POST request:
Cookie
csrftoken=…; sessionid=
Each of them goes to a subdomain (/i18n/ and /darkmode/). Trying to find out why they leak I checked the docu: Is a subdomain considered an external URL? If yes: What would I do in that case? Without the token I get a 403 because the CSRF token is missing. If no: Could it be that the token gets leaked because I don’t use render or RequestContext in the views?
Here is one of the template-parts where I perform the post-request:
<form class= "language_dropdown" action="{% url "set_language" %}" method="post" id="language_selector_form">
{% csrf_token %}
....
</form>
Here is the corresponding view I inherited from my collegue:
def set_language(request):
"""
Redirect to a given URL while setting the chosen language in the session
(if enabled) and in a cookie. The URL and the language code need to be
specified in the request parameters.
Since this view changes how the user will see the rest of the site, it must
only be accessed as a POST request. If called as a GET request, it will
redirect to the page in the request (the 'next' parameter) without changing
any state.
"""
next_url = request.POST.get('next', request.GET.get('next'))
if (
(next_url or request.accepts('text/html')) and
not url_has_allowed_host_and_scheme(
url=next_url,
allowed_hosts={request.get_host()},
require_https=request.is_secure(),
)
):
next_url = request.META.get('HTTP_REFERER')
if not url_has_allowed_host_and_scheme(
url=next_url,
allowed_hosts={request.get_host()},
require_https=request.is_secure(),
):
next_url = '/'
response = http.HttpResponseRedirect(next_url) if next_url else HttpResponse(status=204)
lang_code = None
if request.method == 'POST':
lang_code = request.POST.get(LANGUAGE_QUERY_PARAMETER)
if request.method == 'GET':
lang_code = request.GET.get(LANGUAGE_QUERY_PARAMETER)
if lang_code and check_for_language(lang_code):
if next_url:
next_trans = translate_url(next_url, lang_code)
if next_trans != next_url:
response = http.HttpResponseRedirect(next_trans)
if hasattr(request, 'session'):
# Storing the language in the session is deprecated.
# (RemovedInDjango40Warning)
request.session[LANGUAGE_SESSION_KEY] = lang_code
response.set_cookie(
settings.LANGUAGE_COOKIE_NAME, lang_code,
max_age=settings.LANGUAGE_COOKIE_AGE,
path=settings.LANGUAGE_COOKIE_PATH,
domain=settings.LANGUAGE_COOKIE_DOMAIN,
secure=settings.LANGUAGE_COOKIE_SECURE,
httponly=settings.LANGUAGE_COOKIE_HTTPONLY,
samesite=settings.LANGUAGE_COOKIE_SAMESITE,
)
return response