-
Notifications
You must be signed in to change notification settings - Fork 704
Description
Background
SecureDrop currently uses the "standard" configuration of "expose service on localhost, then connect that to a hidden service via torrc" (see install_files/ansible-base/roles/tor-hidden-services/templates/torrc).
This configuration is problematic, because applications sometimes (fairly) assume that localhost has a different threat model than an externally exposed service. Most recently, this common configuration lead to some hidden services exposing sensitive information through the Apache mod_status module (link). SecureDrop was never vulnerable to this particular issue because we have been aware of it for years and accordingly disable mod_status as well as the rest of the default Apache site configuration.
Nonetheless, I think this is a generally problematic configuration due to the mismatch in the intended use of localhost vs. its common (but frankly, inappropriate) use for externally exposed Tor Hidden Services. I am concerned that other, similar issues may be lurking.
Alternatives to localhost
Riseup has a nice page on deploying hidden services (down right now, here's a cached copy) that discusses this issue in depth. Here are their proposed alternatives to localhost:
Be careful of localhost bypasses!
You should take very careful care to not accidentally expose things on your server that are restricted to the local machine. For example, if you provide /server-status in apache (from mod_status) to monitor the health of your apache webserver, that will typically be restricted to only allow access from 127.0.0.1, or you may have .htaccess rules that only allow localhost, etc.
There are a few ways you can solve this problem:
different machine: consider running the onion service on a different machine (real or virtual) than the actual service. This has the advantage that you can isolate the service from the onion service (a compromise of one doesn’t compromise the other) and helps with isolating potential information leaks
isolation: similarly to the above, you can also isolate tor and the service so it will run on a different network namespace than the service.
public ip: configure the onion service to connect to the public IP address of the service instead of localhost/127.0.0.1, this should make tor not pick 127.0.0.1 as the source address and avoid most misconfigurations. For example like this:
bc. HiddenServiceDir /var/lib/tor/hidden/ftp/
HiddenServicePort 80 192.168.1.1:81
unix socket: consider using unix socket support instead of a TCP socket (requires 0.26 or later tor) – if you do this, then the onion service will be running on the same server as the service itself. With a socket approach, you should be able to run with privatenetwork=yes in systemd unit which gets you some really great isolation, for example:
bc. HiddenServicePort 80 unix:/etc/lighttpd/unix.sock
but then the service itself needs to support unix sockets, otherwise you have to setup some socat redirection from tcp <→ unix (nginx, twisted, lighttpd all support this)
audit carefully: carefully audit, and regularly re-audit your system for configurations that allow localhost/127.0.0.1, but prohibit everywhere else and configure those to work around the problem (for example make /server-status operate on a different IP; make the webserver listen on a different port for /server-status; make it password protected, etc.)
Unix Domain Sockets
Of the options above, I am most interested in Unix domain sockets because they can provide an additional layer of isolation protection through privatenetwork=yes.
I initially thought this would provide a layer of defense in depth for attackers attempting to exfiltrate sensitive data (since they would no longer be able to make arbitrary outgoing Tor connections), but I think they could still use the web application itself as a mechanism to exfiltrate, so this might not be as helpful as I thought it was when I started writing this. This warrants further research.