#33360: Add missing support for `Origin: null` (`CSRF_TRUSTED_ORIGINS`)
-------------------------------------+-------------------------------------
     Reporter:  Tomasz Wójcik        |                    Owner:  nobody
         Type:  Uncategorized        |                   Status:  new
    Component:  CSRF                 |                  Version:  4.0
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
  origin,CSRF_TRUSTED_ORIGINS,null   |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Description changed by Tomasz Wójcik:

Old description:

> In Django 4, [https://code.djangoproject.com/ticket/16010 #16010] has
> been released. It includes 2 changes that affect my project:
> - origins in `CSRF_TRUSTED_ORIGINS` are required to include an HTTP
> scheme
> - `Origin` header, if present in the request headers, will always be
> checked against `CSRF_TRUSTED_ORIGINS`
>
> The problem is that by default when the project is running on localhost,
> browsers will always send `Origin: null` (correct me if I'm wrong).
>
> [https://github.com/django/django/blob/2f73e5406d54cb8945e187eff302a3a3373350be/django/middleware/csrf.py#L433
> if 'HTTP_ORIGIN' in request.META] will always evaluate to `True` on
> localhost, even if `Origin: null`.
> [https://github.com/django/django/blob/2f73e5406d54cb8945e187eff302a3a3373350be/django/middleware/csrf.py#L281
> if request_origin in self.allowed_origins_exact] will never evaluate to
> `True` on localhost, as `null` will never be a valid origin as it doesn't
> include a scheme.
>
> As a result, it's impossible to POST a form on localhost.
>
> ------------------------
>
> - If it's a regression to 16010, I'd propose changing
>
> [https://github.com/django/django/blob/2f73e5406d54cb8945e187eff302a3a3373350be/django/middleware/csrf.py#L433
> if 'HTTP_ORIGIN' in request.META]
>
> to
>
> `​if request.META.get('HTTP_ORIGIN') is not None`
>
> - If it's a feature, I'd suggest adding the above or a setting
> `CSRF_ALLOW_NULL_ORIGIN = False` but it'd require a change in all
> projects migrating to v 4
>
> - if I am mistaken and the `Origin` header should be automatically
> populated by browsers with a non-null value when POSTing from localhost,
> this ticket can be closed (or maybe docs could be improved?)
>
> -----------------------
>
> Sample code that is failing on 4 and is working fine on 3.x
>

> {{{
> # settings
> from corsheaders.defaults import default_headers
>
> CORS_ALLOWED_ORIGINS = [
>     "http://localhost:8000";,
>     "http://127.0.0.1:8000";,
> ]
> CSRF_TRUSTED_ORIGINS = [
>     "http://localhost:8000";,
>     "http://127.0.0.1:8000";,
>     ]
> }}}
>

>
> {{{
> # template
> <form method="post">
>     {% csrf_token %}
> </form>
> }}}
>
> Error:
> > Origin checking failed - null does not match any trusted origins.
>
> Request headers:
> {{{
> Host: localhost:8000
> Origin: null
> }}}
>
> Even if I'm wrong, it's worth noting that the standard defines `opaque
> origin` when `Origin` will be set to `null` so technically this value
> should be supported anyway but I don't understand its definition.
> Let me know if there's something to do here. If yes, please assign me.

New description:

 In Django 4, [https://code.djangoproject.com/ticket/16010 #16010] has been
 released. It includes 2 changes that affect my project:
 - origins in `CSRF_TRUSTED_ORIGINS` are required to include an HTTP scheme
 - `Origin` header, if present in the request headers, will always be
 checked against `CSRF_TRUSTED_ORIGINS`

 The problem is that by default when the project is running on localhost,
 browsers will always send `Origin: null` (correct me if I'm wrong).

 
[https://github.com/django/django/blob/2f73e5406d54cb8945e187eff302a3a3373350be/django/middleware/csrf.py#L433
 if 'HTTP_ORIGIN' in request.META] will always evaluate to `True` on
 localhost, even if `Origin: null`.
 
[https://github.com/django/django/blob/2f73e5406d54cb8945e187eff302a3a3373350be/django/middleware/csrf.py#L281
 if request_origin in self.allowed_origins_exact] will never evaluate to
 `True` on localhost, as `null` will never be a valid origin as it doesn't
 include a scheme.

 As a result, it's impossible to POST a form on localhost.

 ------------------------

 - If it's a regression to 16010, I'd propose changing

 
[https://github.com/django/django/blob/2f73e5406d54cb8945e187eff302a3a3373350be/django/middleware/csrf.py#L433
 if 'HTTP_ORIGIN' in request.META]

 to

 `​if request.META.get('HTTP_ORIGIN') is not None`

 - If it's a feature, I'd suggest adding the above or a setting
 `CSRF_ALLOW_NULL_ORIGIN = False` but it'd require a change in all projects
 migrating to v 4

 - if I am mistaken and the `Origin` header should be automatically
 populated by browsers with a non-null value when POSTing from localhost,
 this ticket can be closed (or maybe docs could be improved?)

 -----------------------

 Sample code that is failing on 4 and is working fine on 3.x


 {{{
 # settings
 from corsheaders.defaults import default_headers

 CORS_ALLOWED_ORIGINS = [
     "http://localhost:8000";,
     "http://127.0.0.1:8000";,
 ]
 CSRF_TRUSTED_ORIGINS = [
     "http://localhost:8000";,
     "http://127.0.0.1:8000";,
     ]
 }}}



 {{{
 # template
 <form method="post">
     {% csrf_token %}
 </form>
 }}}

 Error:
 > Origin checking failed - null does not match any trusted origins.

 Request headers:
 {{{
 Host: localhost:8000
 Origin: null
 }}}

 Even if I'm wrong, it's worth noting that the standard defines `opaque
 origin` when `Origin` will be set to `null` so technically this value
 should be supported anyway but I don't understand its (`opaque origin`)
 definition.
 Let me know if there's something to do here. If yes, please assign me.

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33360#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.ade3711f01166e82009a1ac7e6de667d%40djangoproject.com.

Reply via email to