haiwen / seafile-docker

A Docker image for Seafile server
Other
536 stars 180 forks source link

After v11 Update: CSRF Failed: Origin checking failed #347

Closed pr4xx closed 6 months ago

pr4xx commented 9 months ago

I just updated my 10 server to version 11. Now, whenever I use the web interface to do something API related like DELETE https://sub.domain.com/api/v2.1/upload-links/a8b55d9c08dd46cbbe73/, I get a 403 error:

CSRF Failed: Origin checking failed - https://sub.domain.com does not match any trusted origins.

I cannot find a way to configure the trusted origin list.

I use the docker setup with traefik as the primary web server. So no internal HTTPS and LetsEncrypt. This is my docker compose config:

seafile:
    image: seafileltd/seafile-mc:11.0.0
    container_name: seafile
    restart: always
    expose:
      - 80
    volumes:
      - seafile:/shared
    networks:
      - traefik
      - web
    environment:
      - DB_HOST=db
      - DB_ROOT_PASSWD=<password>
      - TIME_ZONE=Europe/Berlin
      - SEAFILE_ADMIN_EMAIL=<email>
      - SEAFILE_ADMIN_PASSWORD=<password>
      - SEAFILE_SERVER_LETSENCRYPT=false
      - SEAFILE_SERVER_HOSTNAME=sub.domain.com
     labels:
      - traefik.enable=true
      - traefik.http.routers.seafile.rule=Host(`sub.domain.com`)
      - traefik.http.routers.seafile.entrypoints=websecure
      - traefik.http.routers.seafile.tls.certresolver=myresolver
      - traefik.docker.network=traefik
MarioLiebisch commented 9 months ago

Edit your seahub_settings.py and add the following line or modify the existing one (it's probably not there):

CSRF_TRUSTED_ORIGINS = ['https://sub.domain.com']

Contrary to other sources I've found, it's not enough to include the domain name, you have to explicitly add the protocol, too. Once edited, restart the server, and it should be working again.

pr4xx commented 9 months ago

@MarioLiebisch Thanks for the reply, that fixes the problem. But I think there should be another solution? Like an environment variable which I can use in my docker compose file. It feels like I should not be the only one having this issue with a setup like this (docker, traefik, subdomain)

MarioLiebisch commented 9 months ago

Yeah, I kind of agree. It's a confusing "out of the box" experience with no clear error message. I could totally imagine Seahub giving a warning, if no trusted domains are set (at least once Debug mode is enabled) or deactivate this while showing a configuration warning.

Btw. this issue doesn't just break the web API, it also prevents you from accessing the admin panel as the password verification will fail, too.

dhlavaty commented 6 months ago

Edit your seahub_settings.py and add the following line or modify the existing one (it's probably not there):

CSRF_TRUSTED_ORIGINS = ['https://sub.domain.com']

This does not help for localhost. Any idea how to fix that ?

MarioLiebisch commented 6 months ago

This should work with any domain, even localhost. If I'm missing something obvious, you could always just add a custom fake domain to your local hosts file and resolve that to 127.0.0.1.

dhlavaty commented 6 months ago

I'm aparently missing something obvious as well. Nor localhost nor a custom fake domain in my local hosts file work. Both return CSRF Failed: Origin checking failed 🤷‍♂️

MarioLiebisch commented 6 months ago

Are you accessing the URL using the very same protocol mentioned in the config file (https vs http)? If so, out of clues right now. Also make sure to include the port, if you're using a specific non-standard port (i.e. neither 80 nor 433).

dhlavaty commented 6 months ago

Everything (you mention) is OK I think. ( I'm using http://localhost:8000/ ) The login page renders perfectly. After I try to actually login, I end on CSRF Failed: page.

PS: And I tried and installed Seafile Client for Mac, and it connects and seems to work ok. So only the web interface is somehow broken.

kirisakow commented 6 months ago

I'm aparently missing something obvious as well. Nor localhost nor a custom fake domain in my local hosts file work. Both return CSRF Failed: Origin checking failed 🤷‍♂️

@dhlavaty Pay attention to the front dot, e.g., ALLOWED_HOSTS = ['.example.com'].

Here's an anonymized excerpt of my own /shared/seafile/conf/seahub_settings.py file — which works well:

# -*- coding: utf-8 -*-
# For security consideration, please set to match the host/domain of your site, 
# e.g., ALLOWED_HOSTS = ['.example.com'].
# Please refer https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts for details.
ALLOWED_HOSTS = ['.localhost', '127.0.0.1', '[::1]']

# Whether to use a secure cookie for the CSRF cookie
# https://docs.djangoproject.com/en/3.2/ref/settings/#csrf-cookie-secure
CSRF_COOKIE_SECURE = True

# The value of the SameSite flag on the CSRF cookie
# https://docs.djangoproject.com/en/3.2/ref/settings/#csrf-cookie-samesite
CSRF_COOKIE_SAMESITE = 'Strict'

CSRF_TRUSTED_ORIGINS = ['https://myseafile.mydomain.com']

(...)

For the changes to take effect, restart Seahub:

/opt/seafile/seafile-server-latest/seahub.sh restart
dhlavaty commented 6 months ago

So after some Django debugging, I found a solution. The whole problem was, that I tried to use the domain names only in CSRF_TRUSTED_ORIGINS, without a protocol and port. 🤦

This is correct:

# seahub_settings.py

CSRF_TRUSTED_ORIGINS = ["http://localhost:8000"]
freeplant commented 6 months ago

For people who are looking for a solution, we have added an FAQ item for this issue: https://cloud.seatable.io/dtable/external-links/7b976c85f504491cbe8e/?tid=0000&vid=0000&row-id=BQhH-2HSQs68Nq2EW91DBA

dhlavaty commented 6 months ago

@freeplant > Why was this closed? Is it consider solved by adding FAQ (in different repo/project)?

Solution mentioned in this issue is editing CSRF_TRUSTED_ORIGINS in seahub_settings.py, but in FAQ it is by editing nginx/conf/seafile.nginx.conf. Both works actually, but neither or those is a proper solution for seafile-docker. I would expect a settings (and documentation of course) that one can set in his docker-compose.yaml file to solve it forever and for everybody.

MarioLiebisch commented 6 months ago

Unless I misinterpreted the suggestion, that's even a potentially dangerous workaround. Overriding the submitted header will just fake the expected header, essentially breaking the whole CSRF concept here. And even then it won't necessarily help in all instances.

imwhatiam commented 6 months ago

Solution mentioned in this issue is editing CSRF_TRUSTED_ORIGINS in seahub_settings.py, but in FAQ it is by editing nginx/conf/seafile.nginx.conf. Both works actually,

Yes, both solutions can solve this problem, but we recommend changing the nginx configuration. Because if users use a custom port, changing the CSRF_TRUSTED_ORIGINS configuration will not pass the custom port to Seahub, which can cause problems with some features, such as CAS.

but neither or those is a proper solution for seafile-docker. I would expect a settings (and documentation of course) that one can set in his docker-compose.yaml file to solve it forever and for everybody.

The Seafile docker deployment method we provide only supports the standard deployment, which uses the default ports 80 or 443. If users have their own custom requirements, they need to make some changes to the Seafile docker themselves.

freeplant commented 6 months ago

After more investigation, we think the correct solution is as following:

If you modify the port mapping to 20080, the origin field received by Django become http{s}://{ip_or_domain}:20080, and the host field received by Django is {ip_or_domain}, without the custom port. This mismatch results in a CSRF error.

However, in the original HTTP request sent by the browser, the origin and host fields are both http{s}://{ip_or_domain}:20080 . The mismatch is caused by the wrong Nginx setting in our Docker image.

You can correct it by changing Nginx config to the following:

 location / {
        ...
        proxy_set_header Host $http_host;
        ....

The old one is proxy_set_header Host $host;, which does not pass the port part to Django.