qbittorrent / qBittorrent

qBittorrent BitTorrent client
https://www.qbittorrent.org
Other
27.39k stars 3.9k forks source link

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

Closed naikel closed 7 years ago

naikel commented 7 years ago

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.

Guyver commented 7 years ago

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

naikel commented 7 years ago

@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 commented 7 years ago

@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 commented 7 years ago

@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 commented 7 years ago

@Chocobo1 I guess that will work.

lgallard commented 7 years ago

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

Chocobo1 commented 7 years ago

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: https://github.com/Sonarr/Sonarr/issues/1956, https://github.com/Sonarr/Sonarr/pull/1957

naikel commented 7 years ago

@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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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

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 commented 7 years ago

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 commented 7 years ago

@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 commented 7 years ago

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 commented 7 years ago

@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 commented 7 years ago

https://github.com/qbittorrent/qBittorrent/issues/6882#issuecomment-305731949

I agree with it and thank you.

Also thanks to @naikel for summarizing: https://github.com/qbittorrent/qBittorrent/issues/6882#issuecomment-305764198

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

Misiek304 commented 7 years ago

Wait a second. qBittorrent has another WebUI interfaces?

Please share a link.

naikel commented 7 years ago

@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 commented 7 years ago

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

WolfganP commented 7 years ago

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 commented 7 years ago

@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 commented 7 years ago

@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 commented 7 years ago

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 commented 7 years ago

@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 commented 6 years ago

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?