Last active
August 15, 2025 06:12
-
-
Save 0xdade/36de213e01bdbc6a71aa64cebce683e5 to your computer and use it in GitHub Desktop.
I was reading Filippo's words on the new golang CrossOriginProtection middleware, and I really like that we have the opportunity to move beyond the weird csrf_token pattern that we've become so accustomed to. So I started drafting a python implementation of the CrossOriginProtection middleware that recently merged into go's net/http module.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # DO NOT USE. Implementation is untested proof of concept. | |
| # Django CSRF Middleware based on https://words.filippo.io/csrf/ | |
| from functools import wraps | |
| from django.conf import settings | |
| from django.http import HttpRequest, HttpResponse | |
| from asgiref.sync import iscoroutinefunction | |
| SAFE_METHODS = ["GET", "HEAD", "OPTIONS"] | |
| def csrf_exempt(view_func): | |
| """Mark a view function as being exempt from the CSRF view protection.""" | |
| if iscoroutinefunction(view_func): | |
| async def _view_wrapper(request, *args, **kwargs): | |
| request._dangerously_bypass_csrf_protection = True | |
| return await view_func(request, *args, **kwargs) | |
| else: | |
| def _view_wrapper(request, *args, **kwargs): | |
| request._dangerously_bypass_csrf_protection = True | |
| return view_func(request, *args, **kwargs) | |
| return wraps(view_func)(_view_wrapper) | |
| class CrossOriginProtectionMiddleware: | |
| def process_request(self, request: HttpRequest): | |
| raise AssertionError("Removing this line acknowledges that this code has not been tested") | |
| if request.method in SAFE_METHODS: | |
| # Allow GET, HEAD, and OPTIONS requests without any checks | |
| return None | |
| if hasattr(request, "_dangerously_bypass_csrf_protection") and request._dangerously_bypass_csrf_protection: | |
| # Allow requests that explicitly bypass CSRF protection | |
| return None | |
| origin = request.headers.get("Origin") | |
| sec_fetch_site = request.headers.get("Sec-Fetch-Site") | |
| host = request.headers.get("Host") | |
| if origin and origin not in settings.CSRF_TRUSTED_ORIGINS: | |
| # Reject requests with an origin not in the allowed list | |
| return HttpResponse( | |
| "Forbidden: Cross-origin request not allowed.", | |
| status=403, | |
| ) | |
| if sec_fetch_site is not None: | |
| if sec_fetch_site in ["same-origin", "none"]: | |
| # Allow same-origin and no-origin requests | |
| return None | |
| else: | |
| # Reject requests with other Sec-Fetch-Site values | |
| return HttpResponse( | |
| "Forbidden: Cross-origin request not allowed.", | |
| status=403, | |
| ) | |
| if origin is None and sec_fetch_site is None: | |
| # If no origin and Sec-Fetch-Site, allow the request | |
| return None | |
| if origin and host and origin.partition("://")[2] == host: | |
| # Allow requests where the origin matches the host | |
| return None |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment