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

[WebUI] All alternatives WebUI clients are being broken with 3.3.13 except official one #6882

Closed
naikel opened this issue Jun 2, 2017 · 27 comments

Comments

@naikel
Copy link
Contributor

naikel commented Jun 2, 2017

The 3.3.13 update has included an enforcement to check a 'referer' header that has to be present and also has to be the same than the 'Host' header.

That means only the official WebUI client is allowed now.

A simple python client like this, similar to thousands of scripts being used worldwide for several things, doesn't work now. The example below is used to ask an Amazon Echo what is the current global download limit:

import requests

username='admin'
password='admin'

session = requests.session()

session.post('http://htpc:8080/login', { 'username': username, 'password': password }) 
response = session.get('http://htpc:8080/command/getGlobalDlLimit')
if not response.ok:
    response.raise_for_status()
print response.content

Also alternative WebUI clients hosted in some other place don't work, since the referer has to be the same than the Host server. That means the only way for it to work is that the qBittorrent itself is hosting it. Example of an alternative WebUI request:

Hypertext Transfer Protocol
    POST /login HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): POST /login HTTP/1.1\r\n]
            [POST /login HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: POST
        Request URI: /login
        Request Version: HTTP/1.1
    Host: htpc:8080\r\n
    Accept-Encoding: deflate, gzip\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0\r\n
    Accept: application/json, text/plain, */*\r\n
    Accept-Language: en-US,en;q=0.5\r\n
    Referer: http://htpc/client/bootstrap/\r\n
    Content-Type: application/x-www-form-urlencoded\r\n
    Cookie: SID=OumVzEVQAKJG6txdDec43x5u5uHGsq5R\r\n
        Cookie pair: SID=OumVzEVQAKJG6txdDec43x5u5uHGsq5R
    Connection: keep-alive\r\n
    Cache-Control: max-age=0\r\n
    Content-Length: 31\r\n
        [Content length: 31]
    \r\n
    [Full request URI: http://htpc:8080/login]
    [HTTP request 1/1]
HTML Form URL Encoded: application/x-www-form-urlencoded
    Form item: "username" = "admin"
        Key: username
        Value: admin
    Form item: "password" = "admin"
        Key: password
        Value: admin

This is also denied since the referer will never be equal to the host unless it is the official WebUI client.

@naikel naikel changed the title [WebUI] All alternatives WebUI clients are being broken with 3.3.12 except official one [WebUI] All alternatives WebUI clients are being broken with 3.3.13 except official one Jun 2, 2017
@Guyver
Copy link

Guyver commented Jun 2, 2017

CSRF...it's unusable with sonarr on the same box

@naikel
Copy link
Contributor Author

naikel commented Jun 2, 2017

@Guyver I'm afraid this breaks everything. In my opinion, a REST API service can't have that kind of checks, since you're providing a service that must be accessed from anywhere not inside your own box, don't you think? Also it doesn't even work inside your own box unless it is the same port!

@Guyver
Copy link

Guyver commented Jun 2, 2017

@naikel Yeah, it needs to be revised. I rolled back to the previous version once I noticed the code. Solely checking the referrer isn't the way to go! Info

@Chocobo1
Copy link
Member

Chocobo1 commented Jun 2, 2017

@naikel
I'm thinking of adding a switch/option for CSRF check, maybe titled: Enable alternative WebUI clients.
The default value of the switch will be on for qbt-nox and off for GUI qbt.
Does it make sense?

@naikel
Copy link
Contributor Author

naikel commented Jun 2, 2017

@Chocobo1 I guess that will work.

@lgallard
Copy link

lgallard commented Jun 2, 2017

Confirmed, it breaks the authentication in apps like qBittorrent Controller (Android App)

@Chocobo1
Copy link
Member

Chocobo1 commented Jun 2, 2017

Sorry, more questions:

  1. The first example is a minimal script, but you can make it work with qbt by trivially adding the Origin or Referer header, python lib allows it, no?

  2. The second example is exactly what CSRF defends for, what is the usage story of it? may I ask.

  3. For other 3rd-party apps/controllers, simply add a Origin or Referer header isn't that impossible!?
    Sonarr can do it: qBitTorrent 3.3.14 broken due to changed api Sonarr/Sonarr#1956, qbittorrent: add Origin header for webui CSRF Sonarr/Sonarr#1957

@naikel
Copy link
Contributor Author

naikel commented Jun 2, 2017

@Chocobo1

1.- Yes, but that means all the people in the world would have to do that. As impressive as it sounds, the WebUI REST API is used way more often than the WebUI itself, and that would mean everybody would have to change their clients to spoof a referer, since there will be no real referer.

2.- I have my own WebUI written in Angular + Bootstrap that runs in a different server and it uses the REST API to communicate to qBittorrent. As you can see the qBittorrent is in http://htpc:8080 and my own client runs in the Apache server at http://htpc/bootstrap/client. This should be allowed if I can authenticate.

3.- The referer means they are coming from another request, but that isn't true. All applications authenticate, get a Cookie, and then do standalone requests to qBittorrent. Adding a referer would be spoofing in my opinion. Applications go directly to the /login page, without a referer. After getting the cookie, they start doing requests even from different servers, in case of clusters and things like that.

I don't think defending against CSRF for RESTful services is a good idea.

@naikel
Copy link
Contributor Author

naikel commented Jun 2, 2017

Well, I guess we could all add an Origin: header in our apps. What was the idea of this? People clicking links in the "Comment" section of a torrent and getting their qBittorrent hijacked? I don't really see how can somebody attack via CSRF a poor victim using the qBittorrent WebUI.

@Chocobo1
Copy link
Member

Chocobo1 commented Jun 2, 2017

I don't really see how can somebody attack via CSRF a poor victim using the qBittorrent WebUI.

Framing someone by CSRF uploading torrent with illegal content (the one that FBI bust into your house)?

@Matth7878
Copy link

Matth7878 commented Jun 2, 2017

Can confirm, Transdrone app for android not working anymore with latest version. :-/
Rolling back to previous version.

Edit : after rolling back still broken for me. I can only use webui client. :-( :-( :-(

@Taloth
Copy link

Taloth commented Jun 2, 2017

I checked those CSRF guidelines linked in the commit. (Source: owasp.org)

What to do when Both Origin and Referer Headers Aren't Present
If neither of these headers is present, which should be VERY rare, you can either accept or block the request. We recommend blocking, particularly if you aren't using a random CSRF token as your second check. You might want to log when this happens for a while and if you basically never see it, start blocking such requests.

As mentioned, CSRF attacks from the browser are rather unlikely to have both headers missing, since a browser will include them automatically. So it might be safe to permit the api call if no such headers are present at all. That would 'fix' external non-browser clients. External browser clients, such as browser extensions would still suffer problems since they have a Referer header.

For external browser clients, a better solution might be to offer an alternative to Cookie authentication. For example, allow the token to be submitted as Authentication: Bearer <token>. This requires a code change in those clients, but that's inevitable since they actually ARE performing cross-site calls.

I'm fine with changing Sonarr to include the Origin or Referer header, but to me that feels a bit like spoofing them, coz the api call wasn't referred by or originated from qbit. Semantics, I know... but I don't like spoofing.
Yet I think the above might offer an acceptable compromise.

@naikel
Copy link
Contributor Author

naikel commented Jun 2, 2017

Definitely @Taloth has a point and the best solution, in my opinion, is this:

  • If the request doesn't have either a referer or an origin header, do not block it. It's a legitimate REST API call and should be allowed.

  • If a legitimate third party application is doing a cross-site (totally fine), it can choose to either remove the referer header or to add an origin one, or use the X-Forwarded-Host (capitalization has to be fixed in qBittorrent for this header).

  • If a request comes from a browser it will always have either a referer header or an origin one, or both.

Since most applications do directs REST API calls, not blocking them if they don't have either header will be the most compatible option, and applications that do cross-site must code a simple fix (adding/removing a header).

What do you guys think?

@demize
Copy link

demize commented Jun 2, 2017

I don't agree that it's an issue of semantics. This change would make sense if the API was being discontinued, as it restricts API requests to the official client; of course, this means that anything you do to attempt to legitimately access the API will mimic what an illegitimate application would do to try to access a private API.

When you have an API in place, particularly a RESTful API, its entire purpose is to allow cross-site requests. Implementing this change to block cross-site requests then breaks the API in a way that legitimate applications should not be trying to fix. A public-facing API should verify the authenticity of requests some other way (i.e. through the use of API keys) that doesn't depend on the origin of the request (or using malicious tactics to defeat overzealous protection tactics in the API).

@naikel
Copy link
Contributor Author

naikel commented Jun 2, 2017

@demize totally agree with you, but I also understand the devs concern. With that in mind and knowing that all browsers include a Referer and/or an Origin header every single time, the CSRF defense should only be applied when one of those headers appear, and not block everything else that don't include those, like the REST API calls. CSRF only applies to browsers, if a browser is not involved in the call then it shouldn't be applied to it.

@lgallard
Copy link

lgallard commented Jun 2, 2017

I've used several public APIs and I've never seen a CSRF validation per requests. Instead they use other mechanisms to validate them (username/password, tokens, cookies, oauth, etc).

@naikel
Copy link
Contributor Author

naikel commented Jun 2, 2017

@lgallard that's the thing: CSRF only applies to browsers, nothing else. With the cookie auth for our REST API calls is more than enough.

@Chocobo1
Copy link
Member

Chocobo1 commented Jun 2, 2017

#6882 (comment)

I agree with it and thank you.

Also thanks to @naikel for summarizing: #6882 (comment)

In response, I've opened PR #6887 which relax the CSRF defense.

@Misiek304
Copy link

Wait a second.
qBittorrent has another WebUI interfaces?

Please share a link.

@naikel
Copy link
Contributor Author

naikel commented Jun 4, 2017

@Misiek304 well I do have alternative WebUIs, but they are not ready for the public. Basically two sites: a desktop site, that allows RSS and Search through the WebUI, and a mobile site. Both written in Angular + Bootstrap.

I wrote them because the extreme limitations of the very obsolete (but very pretty) MochaUI framework that the official WebUI uses. Since MochaUI only allows one desktop, you can't make an "RSS" tab, or a "Search" tab. and that's a show-stopper for me, since I want every single functionality the GUI has on the web.

@Rouzax
Copy link

Rouzax commented Jun 10, 2017

Is this also the reason that my Reverse Proxy with Microsoft ARR is breaking the Web GUI?

sledgehammer999 added a commit that referenced this issue Jun 13, 2017
[WebUI] relax CSRF defense. Closes #6882.
sledgehammer999 pushed a commit that referenced this issue Jul 3, 2017
Allow HTTP request which has neither Origin nor Referer header included
@WolfganP
Copy link

2.- I have my own WebUI written in Angular + Bootstrap that runs in a different server and it uses the REST API to communicate to qBittorrent. As you can see the qBittorrent is in http://htpc:8080 and my own client runs in the Apache server at http://htpc/bootstrap/client. This should be allowed if I can authenticate.

@naikel Would you mind to share your alternate WebUI (I assume it may work better on mobile displays), or point me to your custom fork/branch where it's implemented if public? Thx in advance.

@naikel
Copy link
Contributor Author

naikel commented Jul 25, 2017

@WolfganP it's still in development it doesn't even have a login page yet (you have to log in manually). It should look better in mobile phones, though I haven't tested it yet there.

The idea is to implement everything the GUI has and using new technologies like ReactJS that should work on every device. Current WebUI uses MochaUI that has been abandoned since 2009. Also, it looks better since it uses Bootstrap themes, so it looks refreshed and modern. All tables are column resizable, column sortable, etc. And it has Search and RSS tabs (though they don't work yet).

It's a fun personal project I have.

@abarash
Copy link

abarash commented Jul 25, 2017

@naikel that sounds awesome! As @WolfganP suggested, if you open-source it, I'm sure there are plenty of folks who would love to help out (if you want the help). :-)

@WolfganP
Copy link

WolfganP commented Jul 26, 2017

I remember when I was using uTorrent, that pluglable alternate WebUI were possible by dumping a zip file with the html, css & js in the config folder (ref: https://forum.utorrent.com/topic/40221-%C2%B5torrent-miniui/#comment-250917), that's why webui development and customization were really easy to implement as it didn't require a program rebuild.
Maybe the same concept can be applied to qBitTorrent? (ie official default webui always present, alternative webui accessed via http://htpc:8080/altui)

@naikel
Copy link
Contributor Author

naikel commented Jul 26, 2017

@WolfganP that would be great, wouldn't be? I think it's a nice idea and it's fairly easy to implement so you just put a zip file with all your alternative WebUI in the user's qBittorrent config folder and qBittorrent would serve those files via HTTP.

So far my WebUI is external. You run it in your own Apache server, and in the login page (that doesn't exist so far) you type username, password, and the qBittorrent WebUI URL. This is not ideal for general use of course, but it's the fastest way to develop it without modifying qBittorrent. It's just a "development environment" the final product will be either inside of a qBittorrent executable or using that alternative you just mentioned.

@tastyratz
Copy link

I see a ton of associated reports closed as duplicate, but I don't actually see in this one a specific address of the actual issue unless maybe I'm missing something. The UI is planned to be replaced in the future which sounds fantastic, but what about bypassing protection/referrer check/etc. now?

I'm trying to run the webUI behind Organizr (similar to muximux or other dashboards). I'm getting a white screen. This is on the latest version 4.1.0.
I feel like spoofing referrer, installing additional programs to do it, and trying to make it all work that way are a lot less clean vs an advanced option to disable referrer check?

@qbittorrent qbittorrent locked and limited conversation to collaborators Feb 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests