Nick Mathewson:
Hi!
As you may know, the Tor control port assumes that if you can authenticate to it, you are completely trusted with respect to the Tor instance you have authenticated to. But there are a few programs and tools that filter access to the Tor control port, in an attempt to provide more restricted access.
When I've been asked to think about including such a feature in Tor in the past, I've pointed out that while filtering commands is fairly easy, defining a safe subset of the Tor control protocol is not. The problem is that many subsets of the control port protocol are sufficient for a hostile application to deanonymize users in surprising ways.
But I could be wrong! Maybe there are subsets that are safer than others.
Let me try to illustrate. I'll be looking at a few filter sets for example.
[...]
Filters from https://git-tails.immerda.ch/tails/tree/config/chroot_local-includes/etc/tor...
Small note: we've renamed tor-controlport-filter to onion-grater, to not infringe on the Tor trademark. :)
- onioncircuits.yml
See onioncircuits.json above; it allows the same GETINFO stuff.
The whole point of onioncircuits is to present all Tor circuit/stream state to the users since they (IIRC) feel that Tor is too opaque without this (and I'm sure the Tor Browser added its per-tab circuit view for similar reasons). In other words, the point of onioncircuits *is* to expose this information. Hence I guess this all boils down balancing the security consequences of this (e.g. user compromise => full Tor state leak) vs the desired transparency.
As for Tails, my impression of our current threat model here is that we don't protect against the main user being compromised, so we certainly won't sacrifice the transparency desired by our users to block this leak -- there are probably equally bad leaks around already so that sacrifice would be pointless. But we are incrementally working towards this by limiting information leaks (e.g. control port filtering) and sandboxing applications to protect full user compromise so we *do* care about these things. At the point where we feel we can start caring about this for real we'll have to revisit this point.
- onionshare.yml
As above, appears to allow HS_DESC events.
Explanation: modern (ADD_ONION instead of SETCONF HiddenService{Dir,Port}) onionshare uses stem's create_ephemeral_hidden_service() with `await_publication = True`, which means waiting for the corresponding HS_DESC event. I believe the roflcoptor filter was written for the "old" onionshare only.
It allows "GETINFO onions/current", which can expose a list of every onion service locally hosted, even those not launched through onionshare.
I think this can be disallowed; in fact, when looking at the onionshare and stem sources I don't see why this would ever be used by onionshare.
- tor-browser.yml
As "tbb.json" above.
Not quite! As intrigeri pointed out, this filter sets `restrict-stream-events: true` which gives what meejah called a "limited view" of the STREAM events, namely only those "belonging" to the client/controller (implementation: for each event look up which PID that has opened the socket with the event's source address/port, then match PIDs to determine whether it should be suppressed or not).
So, how bad is "GETINFO circuit-status" with only the "limited" STREAM view)? Well, by knowing all circuits' exit nodes an attacker that also observes the traffic of these exit nodes knows a bit more than what we are comfortable with. :/
I guess treating "GETINFO circuit-status" specially with a `restrict-circuit-status` option that, when set, suppresses circuits that doesn't have any stream belonging to the client. But the same goes for CIRC events and "GETINFO stream-status", so, in fact, what about these options:
* restrict-circuit-view: when enabled: - "GETINFO circuit-status" will only show circuits that has some stream attached that belongs to the controller. - CIRC events are dropped unless some stream attached to the circuit in question belongs to the controller. * restrict-stream-view (replacing the current `restrict-stream-events`): - "GETINFO stream-status" will only show streams belonging to the controller. - STREAM events are dropped unless they belong to the controller.
Does this make sense? What other bits of sensitive internal Tor state accessible for controllers have I missed?
BTW, I guess a `restrict-onion-view` would also make sense for HS_DESC events and "GETINFO onions/current", but I see no general way to learn what application an onion "belongs" to. The filter could keep track of it, but such tracking would be lost if restarted (and not tracked at all if the onion was added before the filter started). A general solution would depend on little-t tor tracking this information, e.g. the PID of the controller that asked for an onion to be added. That seems ugly, though.
- tor-launcher.yml
Allows setconf of bridges, which allows the app to pick a hostile bridge on purpose. Similar issues with Socks*Proxy. The app can also use ReachableAddresses to restrict guards on the .
Being able to set these options arbitrarily is Tor Launcher's purpose, so I'm fine with all this. We treat it as a "trusted" application in Tails, and I'm having difficulties imaging how it could be any different.
Allows SAVECONF, which lets the application make the above changes permanent (for as long as the torrc file is persisted)
Indeed! In general, Tails users have control of exactly what should persist, so it depends on their own threat model here. At the moment Tails itself does nothing to support making torrc persistent, but if we could make only the part of torrc that Tor Launcher sets persistent I'm sure we would (preferably on a per-network basis).
So above, I see a few common patterns:
[...]
- Many restrictive filters block SETCONF and SAVECONF. These two
changes together should be enough to make sure that a hostile application can only deanonymize _current_ traffic, not future Tor traffic. Is that the threat model? It's coherent, at least.
FWIW, Tails has this threat model in general.
- The NEWNYM-based side-channel above is a little scary.
Agreed! NEWNYM is too broad when multiple clients use the same tor instance -- right now a compromised Tor Browser would be able to influence all other torified applications. I'd be great if instead of NEWNYM the "New identity" feature would use the same mechanism as for "New Tor Circuit for this Site" for all tabs' domains before clearing the browser session; this way, if any of the domains are revisited, it would be with a new circuit, so it is as if we had issued a NEWNYM scoped only for the Tor Browsers circuits, so other applications are unaffected.
And where do we go forward from here?
The filters above seem to have been created by granting the applications only the commands that they actually need, and by filtering all the other commands. But if we'd like filters that actually provide some security against hostile applications using the control port, we'll need to take a different tactic: we'll need to define the threat models that we're trying to work within, and see what we can safely expose under those models.
Here are a few _possible_ models we could think about, but I'd like to hear from app developers and filter authors and distributors more about what they think:
A. Completely trusted controller. (What we have now)
It can be argued that Tor Launcher (and similar) could be in this category since the capabilities it must have in order to do its job are so severe that preventing other capabilities won't make much difference. OTOH, if there are mechanisms for limiting this, why not use them? And we do need such mechanisms to support the other relevant use cases.
B. Controller is untrusted, but is blocked from exfiltrating information. B.1. Controller can't connect to the network at all. B.2. Controller can't connect to the network except over tor.
In Tails, B.2 is strongly enforced for all network usage, not just controllers, but B.1 less so; for instance, onioncircuits runs as the normal user, but any application under that user is allowed to connect to the Internet through Tor, so if that user is compromised the information onionshare has access to can leak out on the network (but through Tor).
B.1 seems really desirable for Tor state visualisation applications like onioncircuits, but I fear only heavily compartmentalized systems like Qubes and Whonix can go in this direction. B.2 seems like something that only can be achieved in systems where Tor is enforced for all connections on at least the OS-level, like in Tails and Whonix, but that threat model already strictly includes this one, so it seems irrelevant.
D. Controller is trusted wrt a fraction of the requests that the clients are handling. (For example, all requests going over a single SOCKSPort, or all ADD_ONION requests that it makes itself.)
I feel work in this direction is highly necessary for many threat models and applications, not least Tor Browser itself vs. Tor's stream state. As I mentioned above, Tails' control port filter allows a controller to only see its own Tor stream state, and that should be expanded to circuits and onions too. It would be even nicer if tor internally tracked usage of both SocksPort and ControlPort on an application-level, and controller commands would be scoped accordingly: controllers would only be able to see stream/circuit/hidden service/etc state belonging to them. Just to give you an idea, the tracking could be by PID (which is pretty weak).
Imagine that ControlPort can take a "RestrictedView" flag. When set, controllers will get a view of Tor's state (streams, circuits, onions etc) restricted to what "belongs" to them, e.g. it only sees streams for connections itself made via the SocksPort. Tor would then have to internally track who these things belong to, which could be done by PID, which is pretty weak, but I bet there are more convincing ways. A crappy idea would be that the cookie used for authenticating to the ControlPort would be unique for the application and also used for the SocksPort (via SOCKS authentication), so that when the "RestrictedView" flag is set, controllers only see things originating from the ControlPort and SocksPorts that have used the same cookie.
Other interesting ideas?
Cheers!