Disallow all unauthenticated web GUI access #3357

Open
jgoerzen opened this Issue Jun 27, 2016 · 44 comments

Projects

None yet

6 participants

@jgoerzen

Hello,

I initially discussed this with security@syncthing.net, and @calmh advised me to submit this here.

Through the "GUI" (web interface), an attacker could easily obtain all of the user's files by authorizing a new device ID into the sync. All an attacker has to do is somehow connect to the port on localhost.

Although syncthing supports setting a username/password for this, it is not done by default.

Unfortunately, connecting to a port on localhost is quite simple in a lot of cases. More and more systems are effectively multiuser today (not just Linux, but also think of Windows machines with multiple family members with accounts), and there are other ways to proxy a connection to localhost.

The simple solution to this would be to require (or at least very strongly encourage) the user to set a username/password if either the username or password are blank.

Furthermore, if syncthing wanted to let the user bypass this prompt when the web GUI is started from the CLI or syncthing-gtk, it could pass along an auth token in the initial URL (git-annex does this). I do not see this as all that critical, thoough.

@calmh advised me that the API is already secured and that Syncthing does have protections for XSS in the web GUI, which narrows but does not eliminate the attack surface.

Current behavior as of 0.13.9.

@Ferroin
Ferroin commented Jun 27, 2016

In general, I can see stuff like this falling into three categories:

  1. Multiple mutually trusted users on a single system.
  2. Multiple mutually untrusted users on a single system.
  3. Remote attackers.

In situation one, people are already pretty much agreeing to not mess with each other's stuff, and therefore it's not really relevant to this issue (except for mentioning it for completeness). This is likely the most common situation for traditional 'home computer' users.

I would not personally consider situation three particularly relevant, because if a remote attacker can connect to arbitrary ports on your loopback interface, you've got bigger issues to deal with because they've either already hit you with an ACE exploit, or they've tricked you into letting them access your system, or they already have a trojan or other malicious software on your system. In any of those situations, they can almost certainly get your files more easily and less noticeably via other means.

This leaves situation two, which can be primarily solved as suggested. There are a few things to keep in mind though:

  1. Unless I'm seriously mistaken and am completely misreading HTTP code, Syncthing uses HTTP-Basic authentication. This provides absolutely zero actual security if your not also using HTTPS (without TLS, anyone who can capture traffic can get the usernames and passwords without almost any effort). To further complicate things, most browsers will block bad SSL certificates like the self-signed ones used by default by Syncthing for HTTPS (and on at least Chrome, there's no way short of installing the (bogus) CA certificate to persistently allow that certificate).
  2. There needs to be a way to turn this warning off. The warning should be on by default, but there are people like me who just use Syncthing on single user systems, and pestering us about securing the web interface against a non-existent threat is not a good thing.
@jgoerzen

Agreed on scenario 2. On scenario 3, there are a number of ways that an attacker can obtain network traffic to a port on localhost without having more seriously compromised the system (Javascript and Java are two examples). As @calmh advised, Syncthing does have some protections against remote Javascript, but there are still possible issues here.

@calmh
Member
calmh commented Jun 27, 2016 edited

I'd like to see a plausible scenario for your remote attacker accessing the interface on 127.0.0.1. If there is one, I'll reconsider that aspect.

My position is otherwise that the vast majority of installs are on single user systems or the mutually-trusted-users setup. For setups with untrusted users on the same hardware the issue is plain and I'd hope that such users are aware of it - it's a fairly niche setup after all, in my opinion.

Of course, using authentication is more secure than not, but there is also a convenience aspect. As it is we throw up large red alerts when bound to something other than localhost without authentication.

@Ferroin
Ferroin commented Jun 27, 2016

@calmh Any web based scripting language (Javascript, Silverlight, whatever else someone might use), as well as Adobe Flash, and Java can do it with almost no user intervention, and it's not always guaranteed that these will be properly sand-boxed, and more importantly, are not always traceable as illegitimate connections.

There's all kinds of other potential vectors, but they require much more effort from the attacker, and almost always result in either the system being more severely compromised (SSH can port forward, but for an attacker to use this they need an existing login or to compromise an existing login), or the user helping them out.

@calmh
Member
calmh commented Jun 27, 2016 edited

Any web based scripting language (Javascript, Silverlight, whatever else someone might use), as well as Adobe Flash, and Java can do it with almost no user intervention

No? I don't think they can, unless the script host is already compromised or the application in question is signed and accepted by the user (for Java). Can you point to any case or documentation where this is the case?

SSH and so on of course yes, but then you're in the case where the user has actively given someone access. I'm talking about something initiated remotely, or something like a malicious webpage running in an otherwise uncompromised browser.

@Ferroin
Ferroin commented Jun 27, 2016

Flash itself can, it's a pretty much complete (albeit isolated) programming environment, though most browsers these days that support it though have it properly sandboxed. Silverlight I can't give any background on because I have zero experience dealing with it aside from uninstalling it on every system I manage because of Microsoft's lack of support, it runs any .NET language though, so it should be trivial to do there. Javascript in a browser probably can't go cross-site anymore (it's been years since I've dealt with it so I don't know for certain), but I do know that it has the ability to open regular socket connections, and I do know there were browsers when I was dealing with it that didn't sandbox it well enough. As far as the Java prompt, that can be turned off (and I know quite a few people back when Java was the web app language who did), and things like that are not really all that much of a security item,, because a majority of users will just blindly accept it after the first time (It happened with Java prompts, it's pretty much happened with UAC and downloaded file protection on Windows, and it continues to happen in similar situations).

There's all kinds of other methods of course, but most of them are still on the level of regular malware vectors or require significant user assistance. Using a virus vector to do this would be stupid though, almost all of them end up eventually being an ACE exploit, and if you've got such an exploit, you can do pretty much whatever the hell you want with the system, and therefore don't need to loop through user visible software to steal data.

@calmh
Member
calmh commented Jun 27, 2016 edited

All the things you mention should have proper cross domain access restrictions. If your point is that they can compromise this via various exploits to get access anyway then you are correct, but the point is meaningless because then they might as well access the local filesystem directly.

@Ferroin
Ferroin commented Jun 27, 2016

Should is not the same as must. You can't assume your users are using up-to-date software, or even well written software. I'm not saying you need to account for this, just that you need to consider it.

@jgoerzen
@canton7
Member
canton7 commented Jun 27, 2016

I would consider Java apps a viable attack vector.

If they are running an application on their PC which they trust, that application can already access all of their files. Syncthing is completely irrelevant. This is the classic "It rather involved being on the other side of this airtight hatchway",

Multiple user accounts

Bear in mind that Syncthing is supposed to be run on login as the login user, so we're only worried about multiple currently-logged-in user accounts, which helps a bit.

@calmh
Member
calmh commented Jun 27, 2016

I think that for the Windows and Mac setups we recommend, this (multiple logged in users, that don't trust each others) is very unusual setup.

the untrusted account is more common than you might think

I'll change my mind on that when there is data to back it up. :)

On Linux I'm sure it's legitimately much more common to have remote users logged in. I'm hoping that those users are a technically savvy niche that do appreciate the concerns. Basically, securing a multi user system is tricky.

It's possible we could improve things though. I think one good way to do that would be to ship a good GUI app by default, with this GUI app being able to get access to Synchting by virtue of launching it itself - we can then enforce authentication as much as we like, without the user having to be confronted with it in in the normal case.

@Ferroin
Ferroin commented Jun 27, 2016

It's fully possible to have multiple user logins on a single seat on both Linux and Windows (not sure about OS X). User switching has been around since at least XP on WIndows, and for at least since I started using Linux half a decade ago on Linux. Only one user is active at a time, but the other user's applications do keep running in the background. Under such a situation, it's fully possible to use the 'start at login, persist for session duration' approach used by Syncthing now and still have multiple instance s running at the same time on a given system.

I do like the idea of adding a basic GUI that doesn't need a web browser, with two specific caveat's:

  1. It needs to be optional at build time. One of the nice features of Syncthing over many alternatives I've seen is that it doesn't depend on a desktop environment at all. This means you can install it on a headless server without having to install a full desktop (or in the Linux case, without needing X libraries).
  2. The authentication needs to be on by default, but should have an option to opt-out (preferably by editing the config file). This falls into the same logic as above, with the addition that some desktop users might prefer to use the WebUI instead.
@xduugu
Contributor
xduugu commented Jun 27, 2016

I don't think this issue should be solved in syncthing, since I don't see syncthing (the core application) targeting users without any knowledge of networks. In my opinion, it fits better in the wrapper applications like Syncthing-Gtk or SyncTrazor, which could set a randomly generated username and a password via environment variables (setting the login parameters via environment variables needs to be implemented in syncthing).

But what really could improve the security, would be splitting the core application with the REST interface and the GUI into two separate binaries. The REST interface will be only accessible via API key and the GUI just connects to it, just like the wrapper applications do now.

@calmh
Member
calmh commented Jun 27, 2016

User switching has been around since

Again, I'm not arguing it can't be done, I'm arguing that it's a small minority case. We should be safe for the default 99% deployments, and I expect we are.

I don't see syncthing (the core application) targeting users without any knowledge of networks

No, I think we do, I just don't think those users also have remote untrusted users on their computer. :)

splitting the core application with the REST interface and the GUI into two separate binaries

Sort of, yes, with the main point is that the thing that launches Syncthing can specify an API key and use it to access the web UI.

@canton7
Member
canton7 commented Jun 27, 2016 edited

Maybe there should be a mode where Syncthing forces the user to specify a username and password before allowing them to do anything else (provided an API key isn't given)?

Although this has its own issues: if a user uses a wrapper to set up Syncthing, someone else on the system could then do the first-time setup of the user and pass...

@xduugu
Contributor
xduugu commented Jun 27, 2016 edited

No, I think we do, I just don't think those users also have remote untrusted users on their computer. :)

What I meant with "core application" is the syncthing binary itself. I currently wouldn't recommend a windows desktop user to download the syncthing binary and use it without a wrapper application. For linux and osx, syncthing is actually usable on its own, but most non-technical people will probably still prefer a desktop application that wraps the syncthing binary. My guess is that there is only a small percentage of users that is using the plain syncthing binary that don't have at least basic knowledge of networks and web technologies.

For all the others, the wrapper could start syncthing in a secure "single-user" mode, by setting a set of environment variables.

Sort of, yes, with the main point is that the thing that launches Syncthing can specify an API key and use it to access the web UI.

Yes. With the current GUI, which is provided by a http server, I thought of something like:

  1. start syncthing -api-key="xyz" (provides only the core and the REST API)
  2. When the GUI is requested:
    • start syncthing-gui -api-key="xyz"
    • use API key to connect to optionally specified REST API location
    • choose random port
    • set random username and password for syncthing-gui http service
    • open browser at http://:@127.0.0.1:

@canton7

Maybe there should be a mode where Syncthing forces the user to specify a username and password before allowing them to do anything else? This mode could even be disabled by default, but enabled by a flag / env var, so that wrapper applications can set it.

Wouldn't it be possible for the wrapper application to just set the username and password to something random and only use it internally? Is it really required that the user even knows of these login data?

@canton7
Member
canton7 commented Jun 27, 2016

I think you're confused as to how the GUI works.

The GUI is just a set of javascript and html files. The GUI uses the REST API in order to fetch the data to display. Given this, I really don't understand what your syncthing-gui is supposed to do. Preventing someone from fetching some html and javascript files doesn't help secure anything.

Wouldn't it be possible for the wrapper application to just set the username and password to something random and only use it internally? Is it really required that the user even knows of these login data?

I still offer users the ability to open Syncthing using a normal web browser, as sometimes there are display issues with my embedded browser.

@xduugu
Contributor
xduugu commented Jun 27, 2016

I may be wrong, but from my understanding, the basic authentication does not apply to the REST API, only to the GUI Web interface. It least that's how the REST APIs I've seen used to work.

I still offer users the ability to open Syncthing using a normal web browser, as sometimes there are display issues with my embedded browser.

You just have to include the username and the password you generated in the URL you send to the browser.


If the REST API and the GUI is split in two binaries, there need to be two http servers running at different ports, at least in the first iteration, because that's how it currently works.

First binary: syncthing-core and http server that provides the REST API. Secured by required API key in HTTP header

Second binary: a second http server that just serves the HTML and JS files. This one should be secured by basic auth.
The GUI could also be provided as browser webapp, in which case the issue discussed here would not exist, but a second web server should be the easiest and fastest option from the current code base. Also, I don't know if SyncTrayzor could access the GUI if it is only available as webapp.

For wrappers like Syncthing-Gtk, the syncthing-gui binary is not required, since it directly talks to the REST API. SyncTrayzor would have to start the GUI binary when the user opens the embedded browser window and can stop it when the window is closed.

@canton7
Member
canton7 commented Jun 27, 2016 edited

I may be wrong, but from my understanding, the basic authentication does not apply to the REST API, only to the GUI Web interface. It least that's how the REST APIs I've seen used to work.

Nope.

Second binary: a second http server that just serves the HTML and JS files. This one should be secured by basic auth.

Again, securing this gives you nothing. Someone could download the html/js files off github, and point them at the REST API. No different.

@xduugu
Contributor
xduugu commented Jun 27, 2016

The difference is that a running syncthing-gui process knows the API-Key. If you have access to the GUI, you can access the REST API without knowing the key. That's the point of the basic authentication in it's current form as well.

@canton7
Member
canton7 commented Jun 27, 2016 edited

So the browser talks to syncthing-gui, which just adds a header and forwards the request to syncthing-core? That seems overly complicated and silly.

If you're going down that route, why not just start a single syncthing binary with a flag saying whether it allows requests without an API key header?

@xduugu
Contributor
xduugu commented Jun 27, 2016

No, syncthing-gui would contain the complete GUI, HTML, JS, CSS files, images etc. The REST requests are performed in the same way it is currently done, via AJAX calls.

@canton7
Member
canton7 commented Jun 27, 2016

In that case I still don't understand what you're trying to achieve.

In case this is what's confusing you, I'll say it again: the GUI is just static html and javascript files. That javascript makes requests to the REST API, just like any wrapper. There is no difference between the GUI and a wrapper, as far as the REST API is concerned.

@xduugu
Contributor
xduugu commented Jun 27, 2016

Exactly, the current GUI would be just like a wrapper. You could then run syncthing without a GUI which is obviously more secure. If you require a GUI, you can start syncthing-gui or any sort of syncthing-wrapper and kill the process when you're done.

@canton7
Member
canton7 commented Jun 27, 2016

You're still not telling me what security the syncthing-gui binary gives you. Why does it exist?

@xduugu
Contributor
xduugu commented Jun 27, 2016

syncthing-gui wouldn't be more secure, but the syncthing-core binary would. And the syncthing-gui binary can be started and stopped independently of syncthing-core and doesn't need to run all the time.

@Ferroin
Ferroin commented Jun 27, 2016

@xduugu That still provides only marginally better security. The REST API is the security issue here, not the GUI itself. Anybody with a decent understanding of the API can talk directly too it. Having an API key will not necessarily help, because you can almost certainly retrieve the API key thorough any number of other methods (if it's a CLI argument, then you just need to know the core process' PID, if it's a config item, you just read the file, etc).

@canton7 The point is an attempt at a separation of privileges, what @xduugu is talking about is proxying REST API calls through the component serving the UI pages, then having that add a API key or in some other way handshaking/authenticating with the REST API itself.

@canton7
Member
canton7 commented Jun 27, 2016

what @xduugu is talking about is proxying REST API calls through the component serving the UI pages,

No he isn't. I specifically asked that:

No, syncthing-gui would contain the complete GUI, HTML, JS, CSS files, images etc. The REST requests are performed in the same way it is currently done, via AJAX calls.

@Ferroin
Ferroin commented Jun 27, 2016

Also, just having the REST API does not make it more secure. I talk directly to it with wget on multiple systems I run syncthing on. Relying on the assumption that people won't know how to get to it without a GUI is security by obscurity, which is a method that's been proven regularly to be useless.

@Ferroin
Ferroin commented Jun 27, 2016

@canton7 Then at least one of us is confused, because what I'm reading out of this except for one specific comment about using the 'same AJAX calls' is that he's talking about serving the UI from a separate program which would proxy the API calls and add an API key.

@canton7
Member
canton7 commented Jun 27, 2016

Yeah, it keeps going round and round. I thought he was talking about proxying calls as well, but when I asked

So the browser talks to syncthing-gui, which just adds a header and forwards the request to syncthing-core?

He said

No, syncthing-gui would contain the complete GUI, HTML, JS, CSS files, images etc. The REST requests are performed in the same way it is currently done, via AJAX calls.

@xduugu
Contributor
xduugu commented Jun 27, 2016 edited

@Ferroin
I don't see your point. Of course you can talk directly to the API, but that requires the API key. If you can read the files of the user running the syncthing REST API or the content of the environment variables, I don't see a possibility to hide this key.

@canton7
If you say, the current GUI is just a proxy for the REST interface, then syncthing-gui would be a proxy as well. But it does more than receiving a HTTP request, adding a header field and passing the request to the REST API.

@canton7
Member
canton7 commented Jun 27, 2016

If you say, the current GUI is just a proxy for the REST interface, then syncthing-gui would be a proxy as well.

No, the current GUI is not a proxy for the REST interface...

@Ferroin
Ferroin commented Jun 27, 2016

@xduugu OK, since multiple people seem confused here, which of these is closest to what you're trying to explain?

  1. GUI is served from a separate binary, which then proxies the calls back to the actual syncthing process in some way.
  2. GUI is served from a separate binary, the GUI makes calls directly against the REST API.
  3. The GUI can just be completely disabled.
  4. Something completely different.
@Ferroin
Ferroin commented Jun 27, 2016

OK, ignore the comment I just posted, I missed the other two comments.

@xduugu You have to assume if your trying to protect against access from other users on the same machine that environment variables can be read and files can be seen, and /proc is not properly protected.

@canton7 Strictly speaking, the current GUI is a proxy for the REST API that also preforms a translation of the data to a more human friendly format.

@canton7
Member
canton7 commented Jun 27, 2016 edited

@canton7 Strictly speaking, the current GUI is a proxy for the REST API that also preforms a translation of the data to a more human friendly format.

Let's not confuse things further, please 😄. We're using "proxy" in the technical sense, meaning to accept http requests and forward them to another server

@calmh
Member
calmh commented Jun 27, 2016 edited

I'll clarify just is one item because it stands out, and then let you guys continue duking it out for a while before we reach some sort of conclusion...

Having an API key will not necessarily help, because you can almost certainly retrieve the API key thorough any number of other methods (if it's a CLI argument, then you just need to know the core process' PID, if it's a config item, you just read the file, etc).

If you can access private process data and files readable only by the owning user, we've already lost. So stop talking about this threat model. It's not relevant to this issue.

@xduugu
Contributor
xduugu commented Jun 27, 2016

@Ferroin
It's not my intention to protect the REST API against a local root user. I was under the assumption that other users can read commandline parameters but not environment variables.

@Ferroin
Ferroin commented Jun 27, 2016

@calmh @xduugu On almost all the major non-commercial Linux distributions in existence right now, there is no such thing as 'private process data' outside of anonymous mappings made by that process (and even that's not entirely private because of ptrace() and friends). Environment variables (/proc/$PID/environ), command-line (/proc/$PID/cmdline), open file descriptors (/proc/$PID/{fd,fdinfo}), etc are all readable by anyone, not just root, from /proc unless the administrator configures things differently. Windows and OS X are at least marginally better about this (I don't know enough to comment beyond that on them), but Syncthing is cross-platform, therefore it needs to consider all platforms it runs on. This is the primary threat model on a majority of Linux systems that would be running Syncthing, simply because there is no inherent protection of /proc, and that is what I'm trying to get across in even discussing it at all.

@calmh
Member
calmh commented Jun 27, 2016 edited

Environment variables (/proc/$PID/environ), ..., etc are all readable by anyone, not just root

Can you point to a case where that file is not 0400, where the fd dirs are not correspondingly 0500, or how it's configurable? I've certainly never seen any and would be astonished to see anyone ship that today.

@xduugu
Contributor
xduugu commented Jun 27, 2016

On my (non-commercial) linux distribution, /proc/*/environ is only readable by the owner of the process. That's using the default configuration.

$ ls -l /proc/4526/environ                                                                                                                                                                                        
-r-------- 1 syncthing syncthing 0 Jun 27 19:32 /proc/4526/environ

Commandline on the other hand:

ls -l /proc/4526/cmdline 
-r--r--r-- 1 syncthing syncthing 0 Jun 26 14:27 /proc/4526/cmdline

But if the OS is not configured correctly, I don't see a possibility to hide sensitive data. You can only obfuscate it, but if you know what you are looking for, that doesn't help much.

@Ferroin
Ferroin commented Jun 27, 2016

Apologies, I hadn't realized that environ and fd were readonly outside of the owning user, most of the time when I'm debugging things directly there, I'm running as root, so I don't typically see the permissions themselves.

@calmh
Member
calmh commented Jun 27, 2016 edited

So, bringing this back on track:

Syncthing can have the REST interface (and GUI) protected by auth (hashed in config file) and/or API key (unencrypted in the config file or environment variable), both of which is mostly secure against other non-adminstrator users.

To provide a secure and easy to use GUI we could restrict it so that the GUI is not accessible without auth. The GUI wrapper would start Syncthing with a random API key in the environment and thus be able to provide a view of it without requiring the user to authenticate.

SyncTrayzor, Syncthing-GTK etc could mostly do this today, if we provided a way to say "don't serve the UI without authentication". The user could set up authentication in this GUI and then be able to use from anywhere.

This is a middle ground that I would consider valid. The next step would then be to ship Syncthing with such a GUI wrapper by default, leaving the current command line installation for servers only.

I'm quite certain that I want the initial user experience after downloading and double clicking something to be that the user gets a usable GUI in front of them - not a requirement to set up a password.

@lkwg82
Member
lkwg82 commented Jun 27, 2016

The next step would then be to ship Syncthing with such a GUI wrapper by default, leaving the current command line installation for servers only.

Yes!

@calmh calmh changed the title from Insecure authentication for web GUI by default to Disallow all unauthenticated web GUI access Jun 29, 2016
@calmh calmh added the enhancement label Jun 29, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment