@@ -32,6 +32,9 @@ within strings, so no confusion is possible there. However it does permit newli
3232extraneous whitespace between elements; client and server MUST NOT use newlines in such a
3333way.
3434
35+ Messages SHOULD be :ref: `padded <padding_messages >` to bucketed lengths,
36+ and buffered (to introduce delays) to protect against traffic analysis.
37+
3538If using JSON RPC 2.0's feature of parameter passing by name, the
3639names shown in the description of the method or notification in
3740question MUST be used.
@@ -258,3 +261,117 @@ and confirm the returned roots match.
258261 implementation would require hashing approximately 88MB of data to
259262 provide a single merkle proof. ElectrumX implements an optimization
260263 such that it hashes only approximately 180KB of data per proof.
264+
265+
266+ .. _padding_messages :
267+
268+ Traffic analysis
269+ ----------------
270+
271+ The goal is to defend against a passive network Man-in-the-Middle, such as an ISP
272+ or a Tor exit node, observing the encrypted TLS stream, and making educated guesses
273+ of the message contents based on TCP packet flow: timing, direction, and sizes of TCP packets.
274+
275+ .. note :: When using raw cleartext TCP as transport for the JSON-RPC payloads, without encryption,
276+ a passive network observer can see all the plaintext messages.
277+
278+ As a generic mitigation, implementations (both client and server) SHOULD
279+
280+ - pad messages to bucketed lengths (e.g. powers of 2, with a min size), and
281+
282+ - introduce small timing delays, ideally by buffering messages.
283+
284+ We can fully backwards-compatibly add padding to the JSON-RPC messages by adding extra
285+ whitespaces inside the JSON objects in a way that parsers ignore.
286+ This can be done at any protocol version.
287+
288+ For example, instead of sending::
289+
290+ {"jsonrpc":"2.0","method":"server.version","id":0,"params":["electrum/4.5.8","1.4"]}\n
291+
292+
293+ the client could send::
294+
295+ {"jsonrpc":"2.0","method":"server.version","id":0,"params":["electrum/4.5.8","1.4"] }\n
296+
297+
298+ For better results, both the client and the server SHOULD implement logic to pad the messages
299+ that they send. So that requests and responses (and notifications) SHOULD all be padded.
300+ This does not have to be rolled out simultaneously: it is ok for only a client to pad what
301+ they send and not the server (or the other way around),
302+ that just limits the effectiveness of the defense against traffic analysis.
303+
304+ Note when the JSON-RPC messages are sent in the TLS stream, they are sometimes batched together.
305+ That is, a single TCP packet might contain multiple small JSON-RPC messages,
306+ e.g. if the client tries to send multiple messages in a short burst.
307+ Also, many protocol requests are <100 bytes, so it would be wasteful to pad all to e.g. 1 kbyte.
308+
309+ To save bandwidth, instead of padding individual JSON-RPC messages,
310+ participants (the client and the server) COULD implement an application-level buffer,
311+ write the messages into that buffer, periodically empty the buffer into the TLS stream
312+ and only add the padding into e.g. the last JSON-RPC message when emptying the buffer.
313+
314+ .. note :: Example implementation
315+ in the `Electrum client <https://github.com/spesmilo/electrum/pull/9875 >`_
316+ and in the `electrumx server <https://github.com/spesmilo/electrumx/pull/301 >`_:
317+
318+ Both the client and the server writes raw JSON-RPC protocol messages into a buffer,
319+ which is then occasionally flushed to the wire. When it is flushed, padding is added
320+ to round up the total length to 1 KB, or to the next power of 2.
321+ The buffer is flushed if it reaches 1 KB, plus there is extra logic that periodically polls
322+ if the oldest message in the buffer is older than 1 second, in which case it is also flushed.
323+ The worst-case 1 second delay is a performance hit that might in cases be felt by the user.
324+ This is a tradeoff to make the flow of packets harder to analyse for an observer.
325+
326+ Implementations COULD make the buffer size and the max time delay configurable.
327+
328+ .. note :: Many protocol requests are <100 bytes. Contrast that with broadcasting a transaction,
329+ which could potentially be several megabytes of data.
330+ (max consensus-valid tx is 4 MB, times 2 for hex-encoding)
331+ Hence padding to a constant size is not practical.
332+ Instead it is recommended to pad to bucketed lengths, e.g. to powers of 2.
333+
334+ The specific details of the size of the buffer, how often it is flushed, and how the padding
335+ is done is not specified by the protocol at the moment. Consequently, neither the client nor
336+ the server can enforce the other to pad and much less to delay messages.
337+
338+ .. note :: Some server implementations do not deal with TLS at all,
339+ they only implement the raw cleartext TCP protocol, and just recommend operators
340+ to put a reverse proxy in front that does TLS termination.
341+ Such protocol implementations (both client and server) nevertheless still
342+ SHOULD implement all mentioned traffic analysis protections.
343+ That way, if the operator tunnels the traffic over TLS externally,
344+ the resulting stream meaningfully receives the protections.
345+
346+ .. note :: An alternative approach to the buffer-based delaying and padding
347+ could be to more aggressively use JSON-RPC batching to batch messages, and to use the
348+ optional Record Padding of
349+ `TLS 1.3 <https://www.rfc-editor.org/rfc/rfc8446#section-5.4 >`_.
350+ See `SSL_CONF_cmd RecordPadding ` in openssl. However this only allows
351+ padding to multiples of a constant, while above the recommendation was to pad to powers of 2.
352+ The implementation might still want to delay messages a bit
353+ to accumulate them into a larger JSON-RPC batch. Also note if users
354+ (e.g. server operators) are expected to do their own TLS termination
355+ (e.g. using a reverse proxy), configuring TLS RecordPadding would become an externality
356+ for them to do, which they might forget.
357+
358+ .. note :: Buffering the messages to introduce timing delays
359+ and padding to ~bucketed sizes is a good baseline.
360+ However even approximate timing and direction of TCP packets
361+ can leak too much information in some scenarios.
362+
363+ To combat timing analysis, both the client and the server
364+ COULD send dummy RPCs with a random timer, but more importantly at strategically selected events.
365+ For example, when the client receives a new block header notification,
366+ it COULD probabilistically send a random number of "server.ping" messages
367+ with small random sleeps in-between.
368+
369+ Protocol version 1.7 extends "server.ping" so that either party can send it, and
370+ that it can be sent either as a JSON-RPC "Request" or as a JSON-RPC "Notification".
371+ If sent as a notification, the receiver is expected not to respond.
372+
373+ When the server sends a block header notification to the client,
374+ it COULD also probabilistically send noise ("server.ping") notifications to the client,
375+ perhaps conditioned on whether it will also send
376+ :func: `blockchain.scriptpubkey.subscribe ` notifications.
377+ (so server could send noise if there are no status notifications to be sent)
0 commit comments