jonaswinkler / paperless-ng

A supercharged version of paperless: scan, index and archive all your physical documents
https://paperless-ng.readthedocs.io/en/latest/
GNU General Public License v3.0
5.37k stars 356 forks source link

[Other] Apache reverse proxy error "403 Forbidden" #1603

Closed egabosh closed 2 years ago

egabosh commented 2 years ago

Moin,

first of all: Thanks for the amazing work! I have some problems with the dockerized setup and Apache reverse proxy (for adding SSL/Letsencrypt). Using this Image: https://hub.docker.com/r/jonaswinkler/paperless-ng

I use Apache as reverse proxy and not Nginx because Nginx can not do LDAP-Auth which I need for some projects. Here my config:

ProxyPass "/" ws://127.0.0.1:8000/
ProxyPassReverse "/" ws://127.0.0.1:8000/
ProxyPass "/" http://127.0.0.1:8000/
ProxyPassReverse "/" http://127.0.0.1:8000/

Login to the WebGUI over the proxy works fine with this config but when I add tags over the WebGUI I'm getting a "403 Forbidden" error:

POST | https:/PAPERLESURL/api/tags/

[[HTTP/1.1 403 Forbidden 126ms]]()

POST
    https://PAPERLESSURL/api/tags/
Status
403
Forbidden
VersionHTTP/1.1
Übertragen512 B (58 B Größe)
Referrer Policysame-origin

Any ideas whats wrong or what additional Apache config I need. Without the proxy accessing directly over port 8000 everything works fine.

Regards olli

cryptoluks commented 2 years ago

Is this your complete Apache config?

I think this is not enough for websockets to work, maybe this is the problem. Have a look at the developer console and Apache logs, maybe this helps.

Did you see https://github.com/jonaswinkler/paperless-ng/discussions/1482?

egabosh commented 2 years ago

Apache log says: paperless 172.23.0.199 - - [11/Feb/2022:12:29:10 +0100] "POST /api/tags/ HTTP/1.1" 403 58 "https://paperless./tags" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36" VLOG=-

Paperless log (docker logs) says: [2022-02-11 12:29:15,283] [WARNING] [django.request] Forbidden: /api/tags/

According to #1482 (thank you for the link) I tried this config:

ProxyPreserveHost on
AllowEncodedSlashes On
ProxyPass "/" http://127.0.0.1:8000/
ProxyPassMatch ^/(ws)$  ws://localhost:8000/$1

Same problem. And no, this is not the complete apache-config. I cut <VirtualHost> and such "generic" things.

cryptoluks commented 2 years ago

Hm what about the csrftoken cookie of the POST request? Is it present and is it part of the POST request? The csrftoken is not required for GET requests but for POST.

You could try to copy the POST request (create tag) as curl command from developer console network tab (Firefox) and run it manually. Maybe you get {"detail":"CSRF Failed: CSRF token missing or incorrect."} or similar..

And maybe compare the POST requests of the Apache and default setup.

egabosh commented 2 years ago

Ah, there seems to be the Problem! Thank you! image Here are coming up an other error NS_ERROR_CONNECTION_REFUSED. They are not showing up wen I access directly without Apache-Proxy/SSL. Hm. No Idea what I can do but maybe you have an idea?

cryptoluks commented 2 years ago

Can you provide a redacted version of all the headers or Kopfzeilen of the POST request?

And just for completeness, did you try if it works in a private tab or different browser before?

egabosh commented 2 years ago

Searched the Internet a bit and with this lines I got rid of the NS_ERROR_CONNECTION_REFUSED:

SetEnvIf Cookie "(^|;\ *)sfcsrftoken=([^;\ ]+)" PAPERLESS_AUTO_LOGIN_USERNAME=$2
RequestHeader set  X-CSRFToken "%{PAPERLESS_AUTO_LOGIN_USERNAME}e"

Hmmm... The 403 with "CSRF Failed: CSRF token missing or incorrect." persists Hope you have any idea.

egabosh commented 2 years ago

Tried it with Firefox and Chromium. Both same behaviour. Direct without Apache it works and with Apache the 403 shows up.

Here the Post Request:

Host: paperless.XXXXXX
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept: application/json; version=2
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Referer: https://paperless.XXXXXXX/tags
Content-Type: application/json
Content-Length: 117
Origin: https://paperless.XXXXXXX
DNT: 1
Connection: keep-alive
Cookie: csrftoken=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX; sessionid=XXXXXXXXXXXXXXXXXXXXXXXX
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

Here the Post Result:

POST
    https://paperless.XXXXXX/api/tags/
Status
403
Forbidden
VersionHTTP/1.1
Übertragen512 B (58 B Größe)
Referrer Policysame-origin

allow
    GET, POST, HEAD, OPTIONS
Connection
    Keep-Alive
content-language
    de-de
content-length
    58
content-type
    application/json
Date
    Fri, 11 Feb 2022 14:25:49 GMT
Keep-Alive
    timeout=5, max=99
referrer-policy
    same-origin
Server
    uvicorn
Strict-Transport-Security
    max-age=15768000; includeSubDomains; preload
vary
    Accept,Accept-Language,Origin,Cookie
x-content-type-options
    nosniff
x-frame-options
    SAMEORIGIN

Accept
    application/json; version=2
Accept-Encoding
    gzip, deflate, br
Accept-Language
    de,en-US;q=0.7,en;q=0.3
Connection
    keep-alive
Content-Length
    117
Content-Type
    application/json
Cookie
    csrftoken=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX; sessionid=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
DNT
    1
Host
    paperless.XXXXX
Origin
    https://paperless.XXXXXXX
Referer
    https://paperless.XXXXXXXXXXX/tags
Sec-Fetch-Dest
    empty
Sec-Fetch-Mode
    cors
Sec-Fetch-Site
    same-origin
User-Agent
    Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0
cryptoluks commented 2 years ago

I think the X-CSRFToken header is missing. This is probably also, what your snippet wants to achieve.

Can you copy a fresh POST request as curl command, copy the csrftoken value, insert it as new X-CSRFToken value, and send the request with curl?

-H 'X-CSRFToken: <csrftoken value here>'

cryptoluks commented 2 years ago

Try to replace the sfcsrftoken with csrftoken, and test if it matches.

SetEnvIf Cookie "(^|;\ *)csrftoken=([^;\ ]+)" PAPERLESS_AUTO_LOGIN_USERNAME=$2
RequestHeader set  X-CSRFToken "%{PAPERLESS_AUTO_LOGIN_USERNAME}e"
egabosh commented 2 years ago

Woh, cool csrftoken worked! Thank you! Here my complete Apache Config:

SetEnvIf Cookie "(^|;\ *)csrftoken=([^;\ ]+)" csrftoken=$2
RequestHeader set  X-CSRFToken "%{csrftoken}e"
ProxyPreserveHost On
AllowEncodedSlashes On
ProxyPass / http://127.0.0.1:8000/
ProxyPassMatch ^/(ws)$  ws://localhost:8000/$1
ProxyPassReverse / http://127.0.0.1:8000/
ProxyRequests off
cryptoluks commented 2 years ago

Great!

Unrelated: Maybe think about putting your Paperless instance behind a VPN like Wireguard or enable at least basic auth in addition. As you are probably storing sensitive information with Paperless, you can't be careful enough. 😄

Have a nice weekend.

egabosh commented 2 years ago

Yap, basic auth over LDAP is one motivation for this Apache-based reverse proxy. Thank you for great support & nice weekend too.