Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing CSRF_TRUSTED_ORIGINS parameter in Django settings.py #1203

Closed
TheFitzZZ opened this issue Dec 13, 2022 · 29 comments
Closed

Missing CSRF_TRUSTED_ORIGINS parameter in Django settings.py #1203

TheFitzZZ opened this issue Dec 13, 2022 · 29 comments

Comments

@TheFitzZZ
Copy link
Contributor

Since Django 4 it is necessary to define trusted origins to prevent 403/CSRF errors.

Steps to repo:

  • Deploy Docker image
  • Access via http://IP:PORT
  • Try to login - POST will fail

Proposed solution:
Add
CSRF_TRUSTED_ORIGINS = ['https://*.mydomain.com','https://*.127.0.0.1'] in settings.py and make it configurable via environment variable.

Tested on my end and works fine.

Source for solution:
https://stackoverflow.com/questions/70285834/forbidden-403-csrf-verification-failed-request-aborted-reason-given-for-fail

@TheFitzZZ
Copy link
Contributor Author

Not sure if I should've opened this issue in the docker repo - touches both worlds imo.

Link to Discord Thread: https://discord.com/channels/754275926921052230/1051985104345497731

@rolandgeider
Copy link
Member

I'm thinking what the default should be, does CSRF_TRUSTED_ORIGINS accept ['*'] ? And also if this can be avoided by passing some headers in the reverse proxy or something similar

@TheFitzZZ
Copy link
Contributor Author

Research tells me * is not valid (also tested this with no luck, same with http*://*.

https://stackoverflow.com/questions/70679571/how-do-i-set-a-wildcard-for-csrf-trusted-origins-in-django

This thread discusses the same issue: maybe adding adding the mentioned lines to both DJANGO and the NGINX part (the one that is included here) might help. This example is for https, would need to understand how to do the same for http.

If I get to it I will update the thread if it works.

That being said: adding the CSRF as a mandatory env variable would be the quickest fix from my pov, at least for the docker case (as I haven't tested native).

@TheFitzZZ
Copy link
Contributor Author

I played around for a bit but was unable to make it work without the CSRF setting. But I must say I am in no way very versed in dealing with NGINX und proxy settings. I can only point at my original proposition.

As a default, it could be commented out so it doesn't interfere with setups that do not require it.

@rolandgeider
Copy link
Member

thanks for looking into this. Having 127.0.0.1 in the default list won't hurt anyway, then users just have to add the domain they are using

@nodecentral
Copy link

Hi @rolandgeider

With my post in mind wger-project/docker#43 in mind, is there anything I can do to help ?

@rolandgeider
Copy link
Member

Once the docker images are built, it will be possible to set the trusted origins with env variables, doing something like CSRF_TRUSTED_ORIGINS=https://my.domain.example.com,https://127.0.0.1 should do the trick

If this works I'll update the defaullt env file in the docker repo

@TheFitzZZ
Copy link
Contributor Author

Validated the change, working flawlessly for me. Thanks a bunch @rolandgeider!

@rolandgeider
Copy link
Member

Great!

I still think this can be solved with some clever headers, will open a new issue for that

@TheFitzZZ
Copy link
Contributor Author

Feel free to hit me up in Discord if you want some testing done with my setup :-)

@nodecentral
Copy link

Hi, thanks all,

As I don’t have a domain name set up/assigned (running local on a QNAP NAS), would it just be the following env variable for me?

CSRF_TRUSTED_ORIGINS=https://127.0.0.1

@TheFitzZZ
Copy link
Contributor Author

Hi, thanks all,

As I don’t have a domain name set up/assigned (running local on a QNAP NAS), would it just be the following env variable for me?

CSRF_TRUSTED_ORIGINS=https://127.0.0.1

Depends on what URL/IP you use to call it. Just try and you'll see :-)

@nodecentral
Copy link

Hi @TheFitzZZ, sorry for perhaps an obvious question, but does that mean all source devices will have to be listed, so if i want to access wger from my phone, pad, pc, all will need a fixed IP and be listed as trusted here ?

@TheFitzZZ
Copy link
Contributor Author

TheFitzZZ commented Dec 18, 2022

@nodecentral nono, it's the address you use to open it from these devices, ergo what you put into your browser. If you use an IP, put the IP. If you have a domain name, put that :-)

@nodecentral
Copy link

nodecentral commented Jan 18, 2023

Hi, picking this issue up again, as I’m still unable to get past the Forbiden - CSRF verification failed. Request aborted. message. I’ve added the following into the environment variables, but sadly it hasn’t worked.

As @TheFitzZZ suggested, I entered the IP address that’s used when I try to connect to Wger via the wger_nginx element , and example of a full address/IP/port etc four that is 192.168.102.134:8008/en/software/features.

This is the address of my QNAP NAS, where docker and the wger container(s) sit..

      - CSRF_TRUSTED_ORIGINS=http://192.168.102.134

Any ideas/suggestions ?

@TheFitzZZ
Copy link
Contributor Author

If I recall correctly, I had to enable Django debug and then look at the log as it states which origin was untrusted, e.g. Origin checking failed - https://bla.bla.co does not match any trusted origins.

@rolandgeider
Copy link
Member

@nodecentral I'm also not sure if this is needed without HTTPS, but setting debug to true and seeing where django complains is a good idea

@nodecentral
Copy link

nodecentral commented Jan 19, 2023

Hi @rolandgeider - is this what you are after..

Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
    Origin checking failed - http://192.168.102.134:8008 does not match any trusted origins.
    
In general, this can occur when there is a genuine Cross Site Request Forgery, or when [Django’s CSRF mechanism](https://docs.djangoproject.com/en/4.0/ref/csrf/) has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function passes a request to the template’s [render](https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render) method.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.
You’re seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
You can customize this page using the CSRF_FAILURE_VIEW setting.

Also not sure if it is related, but I can access Wger via either

192.168.102.134:49160/en/user/login
192.168.102.134:8008/en/user/login

The first url (IP/Port) returns a basic html only version of wger, but I can’t login to that (wger-project/docker#45)
The second url (IP/Port) returns the pretty UI, which I can log into by give me the CSRF error

@rolandgeider
Copy link
Member

so setting CSRF_TRUSTED_ORIGINS=http://192.168.102.134:8008 does not work? While I haven't tested this with a port, it should work as well

@nodecentral
Copy link

nodecentral commented Jan 19, 2023

That did it, seems it needed the port specifically defined..

One observation though, it did not recognise my username/password so I had to re-register…??

QQ: Why are there two ports made available to access Wger, yet only the wger-ngnix container (8008) seems to the one that present the full UI experience, when the other wger-server container (49160) is imageless/basic html..?

@nodecentral
Copy link

nodecentral commented Jan 19, 2023

Oh no, i spoke too soon.

Tried to log in again from a different device, and get the following error..

Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
    CSRF token from POST incorrect.
    
In general, this can occur when there is a genuine Cross Site Request Forgery, or when [Django’s CSRF mechanism](https://docs.djangoproject.com/en/4.0/ref/csrf/) has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function passes a request to the template’s [render](https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render) method.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.
You’re seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.

@nodecentral
Copy link

nodecentral commented Feb 23, 2023

Hi, I can see there’s been a few updates to the wger docker images since my last post (above) .. Are we any closer to the resolving the CSRF issue ? I only ask as I’ve been unable to use Wger for over a month now.. :-(

To confirm, I have the following defined as an environment variable.

- CSRF_TRUSTED_ORIGINS=http://192.168.102.134:8008

Yet upon logging on to Wger, i still get the following 403 errror when accessing 192.168.102.134:8008/en/user/login..

Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
    CSRF token from POST incorrect.
    
In general, this can occur when there is a genuine Cross Site Request Forgery, or when [Django’s CSRF mechanism](https://docs.djangoproject.com/en/4.1/ref/csrf/) has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function passes a request to the template’s [render](https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render) method.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.
You’re seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
You can customize this page using the CSRF_FAILURE_VIEW setting.

@rolandgeider
Copy link
Member

hey! There's been a bit of cleanup and so, but nothing substantial. There is also not much else we can do about the csrf stuff, whitelisting the origins is basically the only thing we can do from django's side. I also can't understand why it's not working for you :((

@nodecentral
Copy link

Thanks @rolandgeider

Picking up on what you said about..

whitelisting the origins is basically the only thing we can do from django's side

How can I be sure I’m not missing anything when it comes to the white listing? Is there anything that I can check, (it would be great to be presented in the error message) that tells me the exact details for me to whitelist?

@rolandgeider
Copy link
Member

I think there is also an error in the logs that show the origin that is making problems.

And just to make sure, you can run this command to check that the correct origins are actually the ones we want:
docker compose exec web python3 manage.py diffsettings | grep CSRF_TRUSTED_ORIGINS

@nodecentral
Copy link

nodecentral commented Feb 28, 2023

Hi @rolandgeider , if i run that command, (result below) other than the addition of the square brackets, it returns the same info as i have in the environment variable.. ? Should I mirror exactly what it returned below in the docker compose ?

[~] # docker exec wger_server python3 manage.py diffsettings | grep CSRF_TRUSTED_ORIGINS
CSRF_TRUSTED_ORIGINS = ['http://192.168.102.134:8008']

@rolandgeider
Copy link
Member

No the brackets are correct (the settings file reads the env variable set by docker and converts the values it to a python list).

Honestly I have no idea what else we could try. In theory this is just a really simple setting that just allows the origin and everything works after that

@nodecentral
Copy link

The only thing left that i can see as potentially related is the nginx.conf, does that relate in any way to the CSRF_TRUSTED_ORIGIN value ? The IP and port used is not reflected here in mine below ?

upstream wger {
    server web:8000;
}

server {
 
    listen 80;

    location / {
        proxy_pass http://wger;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

    location /static/ {
        alias /wger/static/;
    }

    location /media/ {
        alias /wger/media/;
    }

    # Increase max body size to allow for video uploads
    client_max_body_size 100M;

}

@rolandgeider
Copy link
Member

no that config is only used internally, it doesn't care about the external IP or domain

@rolandgeider rolandgeider unpinned this issue Jan 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants