lgallard / qBittorrent-Controller

qBittorrent Controller - An Android app for controlling qBittorrent servers
MIT License
286 stars 58 forks source link

HTTPS with with trusted certificate not working #150

Closed JamiePhonic closed 7 years ago

JamiePhonic commented 7 years ago

Hi there,

So im running my QBT WebUI over SSL using an Nginx reverse proxy as per your wiki thread here, but all im getting is "Network Connection Failed"

If i use standard HTTP, (through the same reverse proxy) then everything works as expected and HTTPS works fine in both chrome and firefox, so im not sure where to go from here. The only difference between the Wiki page and my config, is that im using a "lets enrypt" certificate, but i haven't had issues with it anywhere else thus far.

Im running nginx V1.11.12 with the vhost config provided on the wiki page on ubuntu server 16.0.4 and QBT V3.3.15 on windows server 2016.

lgallard commented 7 years ago

@JamiePhonic

Last release set the Hostname header to fix CSRF compliance https://github.com/lgallard/qBittorrent-Controller/blob/a2616268f70ce075b07ebe186af4b7e8cdf1c79c/app/src/main/java/com/lgallardo/qbittorrentclient/JSONParser.java#L177

Are you using the subfolder in Settings?

More info here: https://github.com/qbittorrent/qBittorrent/issues/6882

JamiePhonic commented 7 years ago

No, it's not in a subfolder. should it be?

lgallard commented 7 years ago

Try setting the subfolder to "/"

If not, you will need to set the Host header in nginx to match your hostname.

JamiePhonic commented 7 years ago

Ok, doing that causes the app to now report "Unauthorized access. Check account settings to avoid bans!" Which hostname should i be setting it to? the external domain, or the interal one?

(Current Nginx vHost config below if it helps)

#HTTP#
######

server {
  listen 80;
  server_name   torrent.notmydomain.tk;

  # Allows letsencrypt-auto to verify domain ownership
  location ^~ /.well-known/acme-challenge/ {
    default_type "text/plain";
    allow all;
    root /var/www/letsencrypt-auto;
  }

  #Redirects all other requests to HTTPS
  location / {
    return  301 https://$server_name$request_uri;
  }
}

#######
#HTTPS#
#######

server {
  listen 443 ssl;
  server_name   torrent.notmydomain.tk;

  # certificates from letsencrypt

  ssl_certificate      /etc/letsencrypt/live/notmydomain.tk/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/notmydomain.tk/privkey.pem;
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  ssl_session_tickets off;

  # Diffie-Hellman parameter for DHE ciphersuites
  ssl_dhparam /etc/nginx/dhparam.pem;

  # modern configuration
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

  ssl_prefer_server_ciphers on;

  # HSTS (ngx_http_headers required) - 6 months
  # add_header Strict-Transport-Security max-age=15768000;

  # OCSP stapling
  ssl_stapling on;
  ssl_stapling_verify on;

  # verify chain of trust of OCSP response
  ssl_trusted_certificate /etc/letsencrypt/live/notmydomain.tk/chain.pem;

  proxy_ignore_headers "Cache-Control" "Expires";
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Host $host;
  proxy_set_header X-Forwarded-Server $host;
  proxy_set_header X-Forwarded-Proto $scheme;
  client_max_body_size 100m;
  proxy_pass_header Set-Cookie;

  location / {
    proxy_pass http://win-server.notmydomain.loc:880;
  }

  access_log /var/log/nginx/torrent-access.log;
  error_log /var/log/nginx/torrent-error.log error;
}
lgallard commented 7 years ago

The host from where the request is been made, the nginx proxy.

JamiePhonic commented 7 years ago

ive done that by changing proxy_set_header Host $host; to proxy_set_header Host nginx-server.notmydomain.loc; and also by just removing all the proxy header options completly, but after running a wireshark capture on it, i can see QBT is returning a 401 Unauthorized to the nginx server (my logon credentials are definetly correct)

Update:

The 401 appears to be because the app is requesting https://torrent.notmydomain.tk:443///version/api with a referer of https://torrent.notmydomain.tk:443// (this is with subfolder set to /) with subfolder empty, the app fails because DNS Lookup for https://https://torrent.notmydomain.tk:443/version/api failed, and referer = https://torrent.notmydomain.tk:443

When i drop back to HTTP, i just get a 401 both times

(this information was gathered by configuring my phone to point to a fiddler proxy running on my PC)

JamiePhonic commented 7 years ago

Ok, i've managed to make some progress:

I can get it working over HTTP by stripping out the Referer headder with proxy_set_header Referer ""; (i know this bypasses the CSRF check, but browsers dont appear to send it anyway), however i still cant get it working over HTTPS becuase the app appears to be doubling the protocol in the URL (see above).

Unforunatly, i'm not a programmer (I'm a network admin :)), so i can't figure out where the issue is in the code (or verify if there even is one)

Update:

Success! So it appears that someone else actually had this issue before and reported it to QBT themselfs here and managed to work out the solution. They were also kind enough to update the QBT wiki with the fixes for both NginX and for IIS ARR After Modifying my Nginx config accordingly, the only thing i had to do is set subfolder in the app to / as @lgallard originally suggested. A generalized copy of my working nginx config is shown below:

#HTTP#
######

server {
  listen 80;
  server_name   torrent.yourdomain.tld;

  # Allows letsencrypt-auto to verify domain ownership 
  # Delete if not using HTTPS with LetsEncrypt
  location ^~ /.well-known/acme-challenge/ {
    default_type "text/plain";
    allow all;
    root /var/www/letsencrypt-auto;
  }

  #Redirects all other requests to HTTPS 
  # Delete if not using HTTPS
  location / {
    return  301 https://$server_name$request_uri;
  }

  # If you ARE using HTTPS, then remove this block, or remove the one above
  # if you want to enable both HTTP and HTTPS
  location / {
    client_max_body_size 100m;
    proxy_ignore_headers                  "Cache-Control" "Expires";
    proxy_set_header  Host                $host;
    proxy_set_header  X-Real-IP           $remote_addr;
    proxy_set_header  X-Forwarded-For     $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Host    $host:<QBT WebUI Port>;
    proxy_set_header  X-Forwarded-Server  $host;
    proxy_set_header  X-Forwarded-Proto   $scheme;

    proxy_hide_header   Referer;
    proxy_hide_header   Origin;
    proxy_set_header    Referer           ''; 
    proxy_set_header    Origin            ''; 

    proxy_cache_valid any 0;
    proxy_pass_header Set-Cookie;
    proxy_pass http://qbtwebui-address:port;
  }

  access_log /var/log/nginx/torrent-access.log;
  error_log /var/log/nginx/torrent-error.log error;
}

#######
#HTTPS# (Delete this whole section if you're not using HTTPS)
#######

server {
  listen 443 ssl;
  server_name   torrent.yourdomain.tld;

  # certificates from letsencrypt

  ssl_certificate      /etc/letsencrypt/live/yourdomain.tld/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/yourdomain.tld/privkey.pem;
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  ssl_session_tickets off;

  # Diffie-Hellman parameter for DHE ciphersuites
  ssl_dhparam /etc/nginx/dhparam.pem;

  # modern configuration
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

  ssl_prefer_server_ciphers on;

  # HSTS (ngx_http_headers required) - 6 months
  # add_header Strict-Transport-Security max-age=15768000;

  # OCSP stapling
  ssl_stapling on;
  ssl_stapling_verify on;

  # verify chain of trust of OCSP response
  ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.tld/chain.pem;

  # Set the proxy cache key
  set $cache_key $scheme$host$uri$is_args$args;

  location / {
    client_max_body_size 100m;
    proxy_ignore_headers                  "Cache-Control" "Expires";
    proxy_set_header  Host                $host;
    proxy_set_header  X-Real-IP           $remote_addr;
    proxy_set_header  X-Forwarded-For     $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Host    $host:<QBT WebUI Port>;
    proxy_set_header  X-Forwarded-Server  $host;
    proxy_set_header  X-Forwarded-Proto   $scheme;

    proxy_hide_header   Referer;
    proxy_hide_header   Origin;
    proxy_set_header    Referer           ''; 
    proxy_set_header    Origin            ''; 

    proxy_cache_valid any 0;
    proxy_pass_header Set-Cookie;
    proxy_pass http://qbtwebui-address:port;
  }

  access_log /var/log/nginx/torrent-access.log;
  error_log /var/log/nginx/torrent-error.log error;
}
Rouzax commented 7 years ago

I'm also still having this issue with the latest version 3.3.16 and that is the reason I'm stuck on 3.3.12 In my case it is a Windows IIS ARR Reverse Proxy with a Lets Encrypt SSL certificate.

JamiePhonic commented 7 years ago

@Rouzax There is also a config for this on the wiki: https://github.com/qbittorrent/qBittorrent/wiki/IIS-ARR-Reverse-Proxy Should work with the latest 3.3.16 (updated my post above for future reference)

Rouzax commented 7 years ago

Unfortunately that results in a weird looking logon screen image When I try to logon I just get an empty screen that has my usename and password in the URL bar. image

My web.config has the following line:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Lets Encrypt" stopProcessing="true">
                    <match url=".well-known/acme-challenge/.*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="None" />
                </rule>
                <rule name="HTTP Redirect to HTTPS" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
                    <match url="*" ignoreCase="true" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" appendQueryString="true" redirectType="Found" />
                </rule>
                <rule name="Torrent Reverse Proxy" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
                    <match url="*" />
                    <action type="Rewrite" url="http://download:8080/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_X-Forwarded-Host" value="{HTTP_HOST}:{SERVER_PORT}" />
                    </serverVariables>
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

Also tried with the temporary 3.3.15 fix that is in the wiki.

JamiePhonic commented 7 years ago

try changing <set name="HTTP_X-Forwarded-Host" value="{HTTP_HOST}:{SERVER_PORT}" /> to <set name="HTTP_X-Forwarded-Host" value="{HTTP_HOST}:8080" /> that's what works with me through nginx: proxy_set_header X-Forwarded-Host $host:8080;

Rouzax commented 7 years ago

Same result. 😢 Opened a new issue https://github.com/qbittorrent/qBittorrent/issues/7577

JamiePhonic commented 7 years ago

This should work:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Lets Encrypt" stopProcessing="true">
                    <match url=".well-known/acme-challenge/.*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="None" />
                </rule>
                <rule name="HTTP Redirect to HTTPS" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
                    <match url="*" ignoreCase="true" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" appendQueryString="true" redirectType="Found" />
                </rule>
                <rule name="Torrent Reverse Proxy" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
                    <match url="*" />
                    <action type="Rewrite" url="http://download:8080/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_X-Forwarded-Host" value="{HTTP_HOST}:{SERVER_PORT}" />
                        <set name="HTTP_REFERER" value="" />
                    </serverVariables>
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

(You'll probably need to add HTTP_REFERER as a variable in the URL rewrite module)

Rouzax commented 7 years ago

@JamiePhonic Thanks that bring me a bit further. My logon screen now look okay but when I try to logon I get the message: Unable to log in, qBittorrent is probably unreachable. image

This is my IIS log, that shows the 401's on the logon.

#Software: Microsoft Internet Information Services 10.0
#Version: 1.0
#Date: 2017-10-13 15:30:56
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2017-10-13 15:30:56 192.168.2.12 GET / X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=ad36f450-afe0-4259-8379-dc08f600a9e2&SERVER-STATUS=200 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 200 0 0 182
2017-10-13 15:30:56 192.168.2.12 GET /css/style.css X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=75569718-5d1b-438a-b374-02d69d911adf&SERVER-STATUS=200 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 200 0 0 0
2017-10-13 15:30:56 192.168.2.12 GET /scripts/mootools-1.2-core-yc.js X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=48c0742a-737e-432c-8015-b23998345a7e&SERVER-STATUS=200 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 200 0 0 0
2017-10-13 15:30:56 192.168.2.12 GET /images/qbittorrent.png X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=6ebb37a9-26ae-4032-840b-57f0edc680d7&SERVER-STATUS=200 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 200 0 0 13
2017-10-13 15:30:56 192.168.2.12 GET /favicon.ico X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=36202bab-536d-4887-8636-781d6be5689c&SERVER-STATUS=200 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 200 0 0 46
2017-10-13 15:30:58 192.168.2.12 POST /login X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=9d2cf821-0681-4f5b-b852-f09ab3f96e04&SERVER-STATUS=401 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 401 0 0 0
2017-10-13 15:31:01 192.168.2.12 POST /login X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=cedcbf00-bc8d-4166-aed8-54e86569d07f&SERVER-STATUS=401 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 401 0 0 15
2017-10-13 15:31:03 192.168.2.12 POST /login X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=7cd46af6-8a38-4b28-840b-9a85b6820a66&SERVER-STATUS=401 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 401 0 0 0
2017-10-13 15:31:05 192.168.2.12 POST /login X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=5d4cecb8-76b8-4d96-b0c2-d46f11ff4144&SERVER-STATUS=401 443 - 192.168.2.254 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/61.0.3163.100+Safari/537.36 - 401 0 0 15
JamiePhonic commented 7 years ago

Here is a copy of my web.confg file that's working with QBT 3.3.16 (Pastebined for neatness)

https://pastebin.com/TSJEsLnq

Rouzax commented 7 years ago

Thanks will give that a try. I see that you also have outbound rewrite rules which I don't have.

JamiePhonic commented 7 years ago

Solution to @Rouzax issue has been found Here The Wiki Page has also been updated, so both Nginx and IIS configs should now work with qBittorrent V3.3.13 and above.

crabvk commented 6 years ago

@JamiePhonic thank you for sharing your config.

Had the same "Unauthorized access." In my case it was

proxy_set_header Host $http_host;

vs.

proxy_set_header Host $host;

because qBController doesn't event make requests if "Connection Port" is empty (but showing loading progress as if it does). And if I specify port number, variable $http_host contains it (which cause Unauthorized access)