Stream isolation and circuit sharing
When two streams share a circuit, a hostile exit node learns that those streams belong to the same user. An observer between the exit and the destination, and the destination itself, can also infer this fact with reasonably high probability. Therefore, it’s important for streams that are logically isolated not to share circuits with one another. For example, streams from two different applications, or streams representing two different accounts within an application, or streams representing two different sessions from an application, should generally not share the same circuit.
Tor clients cannot infer on their own which streams come from the same application, account, or session. Therefore, they need to provide a mechanism for applications to tell the client which streams are related, and which are not.
Every stream has a collection of isolation properties that define its isolation profile. Two streams may share a circuit if (and only if) their isolation profiles are compatible.
Semantically, every isolation property has:
- A key.
- A value.
- An “isolate” flag.
Two isolation properties are incompatible when:
- they have the same key,
- they have different values,
- and at least one of them has the “isolate” flag set to true.
Two isolation profiles are incompatible if they contain a pair of isolation properties that is incompatible.
Implementation note:
When searching for a circuit on which a given stream can be used, it is inefficient to check every stream on that circuit for compatibility with the stream we’re trying to attach. Instead, implementations can merge the current set of isolation properties on all streams currently on a circuit, and only compare the stream’s properties to the circuit’s properties. For a description of this algorithm see the “Implementation Notes” section of proposal 171.
Implementations SHOULD provide at least the following isolation properties; they should by default have their “isolate” flag set to true.
- Application Address. The address (not port) from which the application connected to the Tor client.
- Proxy Address. The specific proxy address and port provided by the Tor client to which the application connected.
- Proxy Protocol. The proxy protocol that the application used when connecting to Tor client. (For example, SOCKS4, SOCKS5, HTTP CONNECT, etc)
- Application-provided Isolation Tokens. A set of values provided by the application, either via a library API, or via the specific proxy protocol. See the set of isolation tokens recommended for SOCKS and the set of and isolation tokens recommended for HTTP CONNECT.
Implementations MAY provide additional isolation properties, such as for destination port, or destination address, or destination domain. These properties SHOULD NOT have their “isolate” flags set by default, since their benefit is limited and their usage can consume excessive resources.
Isolation and circuit rotation
Some strong isolation properties are better than others at ensuring that streams from different accounts, applications, and sessions are placed on different circuits. For example, applications that provide their own application tokens are generally trusted to manage which streams are isolated from one another; whereas the application address generally only distinguishes whether the application is using 127.0.0.1 or ::1.
When no isolation property is strong, it makes sense to rotate circuits after they have been in use for a while. (You can think of this as adding “approximate stream creation time” as an isolation property, but this is not usually the most convenient implementation.) But when a strong isolation property is present, it makes sense to use the same circuit for a long time. See proposal 368 for further discussion.
Some isolation properties are strong, meaning that they are usually effective at isolating streams from different contexts.
Among the properties listed above, only “Application-provided Isolation Tokens” are strong.
When a circuit contains any streams without strong isolation properties, then after it has been in use for streams for a sufficient time, no additional streams SHOULD be attached to it.
In C tor this timeout is
MaxCircuitDirtiness. In arti it iscircuit_timing.max_dirtiness.
If a circuit contains only streams with strong isolation properties, then it can be used indefinitely, and only needs to be closed after it has been unused for a long while.
In C tor this is controlled by
KeepAliveSocksAuth.