Reflow proposals 233, 234.
[torspec.git] / proposals / 171-separate-streams.txt
1 Filename: 171-separate-streams.txt
2 Title: Separate streams across circuits by connection metadata
3 Author: Robert Hogan, Jacob Appelbaum, Damon McCoy, Nick Mathewson
4 Created: 21-Oct-2008
5 Modified: 7-Dec-2010
6 Status: Closed
7 Implemented-In: 0.2.3.3-alpha
8
9 Summary:
10
11   We propose a new set of options to isolate unrelated streams from one
12   another, putting them on separate circuits so that semantically
13   unrelated traffic is not inadvertently made linkable.
14
15 Motivation:
16
17   Currently, Tor attaches regular streams (that is, ones not carrying
18   rendezvous or directory traffic) to circuits based only on whether Tor
19   circuit's current exit node supports the destination, and whether the
20   circuit has been dirty (that is, in use) for too long.
21
22   This means that traffic that would otherwise be unrelated sometimes
23   gets sent over the same circuit, allowing the exit node to link such
24   streams with certainty, and allowing other parties to link such
25   streams probabilistically.
26
27   Older versions of onion routing tried to address this problem by
28   sending every stream over a separate circuit; performance issues made
29   this unfeasible. Moreover, in the presence of a localized adversary,
30   separating streams by circuits increases the odds that, for any given
31   linked set of streams, at least one will go over a compromised
32   circuit.
33
34   Therefore we ought to look for ways to allow streams that ought to be
35   linked to travel over a single circuit, while keeping streams that
36   ought not be linked isolated to separate circuits.
37
38 Discussion:
39
40   Let's call a series of inherently-linked streams (like a set of
41   streams downloading objects from the same webpage, or a browsing
42   session where the user requests several related webpages) a "Session".
43
44   "Sessions" are a necessarily a fuzzy concept.  While users typically
45   consider some activities as wholly unrelated to each other ("My IM
46   session has nothing to do with my web browsing!"), the boundaries
47   between activities are sometimes hard to determine.  If I'm reading
48   lolcats in one browser tab and reading about treatments for an
49   embarrassing disease in another, those are probably separate sessions.
50   If I search for a forum, log in, read it for a while, and post a few
51   messages on unrelated topics, that's probably all the same session.
52
53   So with the proviso that no automated process can identify sessions
54   100% accurately, let's see which options we have available.
55
56   Generally, all the streams on a session come from a single
57   application.  Unfortunately, isolating streams by application
58   automatically isn't feasible, given the lack of any nice
59   cross-platform way to tell which local process originated a given
60   connection.  (Yes, lsof works.  But a quick review of the lsof code
61   should be sufficient to scare you away from thinking there is a
62   portable option, much less a portable O(1) option.)  So instead, we'll
63   have to use some other aspect of a Tor request as a proxy for the
64   application.
65
66   Generally, traffic from separate applications is not in the same
67   session.
68
69   With some applications (IRC, for example), each stream is a session.
70
71   Some applications (most notably web browsing) can't be meaningfully
72   split into sessions without inspecting the traffic itself and
73   maintaining a lot of state.
74
75   How well do ports correspond to sessions?  Early versions of this
76   proposal focused on using destination ports as a proxy for
77   application, since a connection to port 22 for SSH is probably not in
78   the same session as one to port 80. This only works with some
79   applications better than others, though: while SSH users typically
80   know when they're on port 22 and when they aren't, a web browser can
81   be coaxed (though img urls or any number of releated tricks) into
82   connecting to any port at all.  Moreover, when Tor gets a DNS lookup
83   request, it doesn't know in advance which port the resulting address
84   will be used to connect to.
85
86   So in summary, each kind of traffic wants to follow different rules,
87   and assuming the existence of a web browser and a hostile web page or
88   exit node, we can't tell one kind of traffic from another by simply
89   looking at the destination:port of the traffic.
90
91   Fortunately, we're not doomed.
92
93 Design:
94
95   When a stream arrives at Tor, we have the following data to examine:
96     1) The destination address
97     2) The destination port (unless this a DNS lookup)
98     3) The protocol used by the application to send the stream to Tor:
99        SOCKS4, SOCKS4A, SOCKS5, or whatever local "transparent proxy"
100        mechanism the kernel gives us.
101     4) The port used by the application to send the stream to Tor --
102        that is, the SOCKSListenAddress or TransListenAddress that the
103        application used, if we have more than one.
104     5) The SOCKS username and password, if any.
105     6) The source address and port for the application.
106
107   We propose to use 3, 4, and 5 as a backchannel for applications to
108   tell Tor about different sessions.  Rather than running only one
109   SOCKSPort, a Tor user who would prefer better session isolation should
110   run multiple SOCKSPorts/TransPorts, and configure different
111   applications to use separate ports. Applications that support SOCKS
112   authentication can further be separated on a single port by their
113   choice of username/password.  Streams sent to separate ports or using
114   different authentication information should never be sent over the
115   same circuit.  We allow each port to have its own settings for
116   isolation based on destination port, destination address, or both.
117
118   Handling DNS can be a challenge.  We can get hostnames by one of three
119   means:
120
121     A) A SOCKS4a request, or a SOCKS5 request with a hostname.  This
122        case is handled trivially using the rules above.
123     B) A RESOLVE request on a SOCKSPort.  This case is handled using the
124        rules above, except that port isolation can't work to isolate
125        RESOLVE requests into a proper session, since we don't know which
126        port will eventually be used when we connect to the returned
127        address.
128     C) A request on a DNSPort.  We have no way of knowing which
129        address/port will be used to connect to the requested address.
130
131   When B or C is required but problematic, we could favor the use of
132   AutomapHostsOnResolve.
133
134 Interface:
135
136   We propose that {SOCKS,Natd,Trans,DNS}ListenAddr be deprecated in
137   favor of an expanded {SOCKS,Natd,Trans,DNS}Port syntax:
138
139   ClientPortLine = OptionName SP (Addr ":")? Port (SP Options?)
140   OptionName = "SOCKSPort" / "NatdPort" / "TransPort" / "DNSPort"
141   Addr = An IPv4 address / an IPv6 address surrounded by brackets.
142          If optional, we default to 127.0.0.1
143   Port = An integer from 1 through 65535 inclusive
144   Options = Option
145   Options = Options SP Option
146   Option = IsolateOption / GroupOption
147   GroupOption = "SessionGroup=" UINT
148   IsolateOption =  OptNo ("IsolateDestPort" / "IsolateDestAddr" /
149          "IsolateSOCKSUser"/ "IsolateClientProtocol" /
150          "IsolateClientAddr") OptPlural
151   OptNo = "No" ?
152   OptPlural = "s" ?
153   SP = " "
154   UINT = An unsigned integer
155
156   All options are case-insensitive.
157
158   The "IsolateSOCKSUser" and "IsolateClientAddr" options are on by
159   default; "NoIsolateSOCKSUser" and "NoIsolateClientAddr" respectively
160   turn them off.  The IsolateDestPort and IsolateDestAddr and
161   IsolateClientProtocol options are off by default.  NoIsolateDestPort and
162   NoIsolateDestAddr and NoIsolateClientProtocol have no effect.
163
164   Given a set of ClientPortLines, streams must NOT be placed on the same
165   circuit if ANY of the following hold:
166
167     * They were sent to two different client ports, unless the two
168       client ports both specify a "SessionGroup" option with the same
169       integer value.
170     * At least one was sent to a client port with the IsolateDestPort
171       active, and they have different destination ports.
172     * At least one was sent to a client port with IsolateDestAddr
173       active, and they have different destination addresses.
174     * At least one was sent to a client port with IsolateClientProtocol
175       active, and they use different protocols (where SOCKS4, SOCKS4a,
176       SOCKS5, TransPort, NatdPort, and DNS are the protocols in question)
177     * At least one was sent to a client port with IsolateSOCKSUser
178       active, and they have different SOCKS username/password values
179       configurations.  (For the purposes of this option, the
180       username/password pair of ""/"" is distinct from SOCKS without
181       authentication, and both are distinct from any non-SOCKS client's
182       non-authentication.)
183     * At least one was sent to a client port with IsolateClientAddr
184       active, and they came from different client addresses.  (For the
185       purpose of this option, any local interface counts as the same
186       address.  So if the host is configured with addresses 10.0.0.1,
187       192.0.32.10, and 127.0.0.1, then traffic from those addresses can
188       leave on the same circuit, but traffic to from 10.0.0.2 (for
189       example) could not share a circuit with any of them.)
190
191   These rules apply regardless of whether the streams are active at the
192   same time.  In other words, if the rules say that streams A and B must
193   not be on the same circuit, and stream A is attached to circuit X,
194   then stream B must never be attached to stream X, even if stream A is
195   closed first.
196
197 Alternative Interface:
198
199   We're cramming a lot onto one line in the design above.  Perhaps
200   instead it would be a better idea to have grouped lines of the form:
201
202     StreamGroup 1
203     SOCKSPort 9050
204     TransPort 9051
205     IsolateDestPort 1
206     IsolateClientProtocol 0
207     EndStreamGroup
208
209     StreamGroup 2
210     SOCKSPort 9052
211     DNSPort 9053
212     IsolateDestAddr 1
213     EndStreamGroup
214
215   This would be equivalent to:
216    SOCKSPort 9050 SessionGroup=1 IsolateDestPort NoIsolateClientProtocol
217    TransPort 9051 SessionGroup=1 IsolateDestPort NoIsolateClientProtocol
218    SOCKSPort 9052 SessionGroup=2 IsolateDestAddr
219    DNSPort   9053 SessionGroup=2 IsolateDestAddr
220
221   But it would let us extend range of allowed options later without
222   having client port lines group without bound.  For example, we might
223   give different circuit building parameters to different session
224   groups.
225
226 Example of use:
227
228   Suppose that we want to use a web browser, an IRC client, and a SSH
229   client all at the same time.  Let's assume that we want web traffic to
230   be isolated from all other traffic, even if the browser makes
231   connections to ports usually used for IRC or SSH.  Let's also assume
232   that IRC and SSH are both used for relatively long-lived connections,
233   and we want to keep all IRC/SSH sessions separate from one another.
234
235   In this case, we could say:
236
237     SOCKSPort 9050
238     SOCKSPort 9051 IsolateDestAddr IsolateDestPort
239
240   We would then configure our browser to use 9050 and our IRC/SSH
241   clients to use 9051.
242
243 Advanced example of use, #2:
244
245   Suppose that we have a bunch of applications, and we launch them all
246   using torsocks, and we want to keep each applications isolated from
247   one another.  We just create a shell script, "torlaunch":
248     #!/bin/bash
249     export TORSOCKS_USERNAME="$1"
250     exec torsocks $@
251   And we configure our SOCKSPort with IsolateSOCKSUser.
252
253   Or if we're on Linux and we want to isolate by application invocation,
254   we would change the TORSOCKS_USERNAME line to:
255
256     export TORSOCKS_USERNAME="`cat /proc/sys/kernel/random/uuid`"
257
258 Advanced example of use, #2:
259
260   Now suppose that we want to achieve the benefits of the first example
261   of use, but we are stuck using transparent proxies.  Let's suppose
262   this is Linux.
263
264     TransPort 9090
265     TransPort 9091 IsolateDestAddr IsolateDestPort
266     DNSPort 5353
267     AutomapHostsOnResolve 1
268
269   Here we use the iptables --cmd-owner filter to distinguish which
270   command is originating the packets, directing traffic from our irc
271   client and our SSH client to port 9091, and directing other traffic to
272   9090.  Using AutomapHostsOnResolve will confuse ssh in its default
273   configuration; we'll need to find a way around that.
274
275 Security Risks:
276
277   Disabling IsolateClientAddr is a pretty bad idea.
278
279   Setting up a set of applications to use this system effectively is a
280   big problem.  It's likely that lots of people who try to do this will
281   mess it up.  We should try to see which setups are sensible, and see
282   if we can provide good feedback to explain which streams are isolated
283   how.
284
285 Performance Risks:
286
287   This proposal will result in clients building many more circuits than
288   they do today.  To avoid accidentally hammering the network, we should
289   have in-process limits on the maximum circuit creation rate and the
290   total maximum client circuits.
291
292 Specification:
293
294   The Tor client circuit selection process is not entirely specified.
295   Any client circuit specification must take these changes into account.
296
297 Implementation notes:
298
299   The more obvious ways to implement the "find a good circuit to attach
300   to" part of this proposal involve doing an O(n_circuits) operation
301   every time we have a stream to attach.  We already do such an
302   operation, so it's not as if we need to hunt for fancy ways to make it
303   O(1).  What will be harder is implementing the "launch circuits as
304   needed" part of the proposal.  Still, it should come down to "a simple
305   matter of programming."
306
307   The SOCKS4 spec has the client provide authentication info when it
308   connects; accepting such info is no problem.  But the SOCKS5 spec has
309   the client send a list of known auth methods, then has the server send
310   back the authentication method it chooses.  We'll need to update the
311   SOCKS5 implementation so it can accept user/password authentication if
312   it's offered.
313
314   If we use the second syntax for describing these options, we'll want
315   to add a new "section-based" entry type for the configuration parser.
316   Not a huge deal; we already have kludged up something similar for
317   hidden service configurations.
318
319   Opening circuits for predicted ports has the potential to get a little
320   more complicated; we can probably get away with the existing
321   algorithm, though, to see where its weak points are and look for
322   better ones.
323
324   Perhaps we can get our next-gen HTTP proxy to communicate browser tab
325   or session into to tor via authentication, or have torbutton do it
326   directly.  More design is needed here, though.
327
328 Alternative designs:
329
330   The implementation of this option may want to consider cases where the
331   same exit node is shared by two or more circuits and
332   IsolateStreamsByPort is in force.  Since one possible use of the option
333   is to reduce the opportunity of Exit Nodes to attack traffic from the
334   same source on multiple ports, the implementation may need to ensure
335   that circuits reserved for the exclusive use of given ports do not
336   share the same exit node.  On the other hand, if our goal is only that
337   streams should be unlinkable, deliberately shunting them to different
338   exit nodes is unnecessary and slightly counterproductive.
339
340   Earlier versions of this design included a mechanism to isolate
341   _particular_ destination ports and addresses, so that traffic sent to,
342   say, port 22 would never share a port with any traffic *not* sent to
343   port 22.  You can achieve this here by having all applications that
344   send traffic to one of these ports use a separate SOCKSPort, and
345   then setting IsolateDestPorts on that SOCKSPort.
346
347 Future work:
348
349   Nikita Borisov suggests that different session profiles -- so long as
350   there aren't too many of them -- could well get different guard node
351   allocations in order to prevent guard profiling.  This can be done
352   orthogonally to the rest of this proposal.
353
354 Lingering questions:
355
356   I suspect there are issues remaining with DNS and TransPort users, and
357   that my "just use AutomapHostsOnResolve" suggestion may be
358   insufficient.