Subject: [ppsp] Proposal to solve Issue #26

From: Arno Bakker <[email-masked]>
Date: Wed, 25 Jan 2012 09:30:16 +0100

Hi all

in this mail a proposal to solve issue:

26. Evaluate the handshake procedure if it needs strengthening against 
"state-building attacks"?

Proposal
========
Following the analysis in RFC 5971, the PPSP peer protocol may be 
attacked with 2 types of denial-of-service attacks:

1. DOS amplification attack: attackers try to use a PPSPP peer to 
generate more traffic to a victim.

2. DOS flood attack: attackers try to deny service to other peers by 
allocating lots of state at a PPSPP peer.

The current -00 draft already contains the basic scheme to protect 
against these attacks in the UDP encapsulation. I'll describe the scheme 
first (WG item, Sec. 6.1.3+4):

When UDP is used, all datagrams carrying PPSPP messages are prefixed 
with a 4-byte channel ID. These channel IDs are random numbers, 
established during the handshake phase as follows. Peer A initiates an 
exchange with peer B by sending a datagram containing a HANDSHAKE 
message prefixed with the channel ID consisting of all 0s. Peer A's 
HANDSHAKE contains a randomly chosen channel ID, chanA:

A->B:	chan0 + HANDSHAKE(chanA) + ...

When peer B receives this datagram, it creates some state for peer A, 
that at least contains the channel ID chanA. Next, peer B sends a 
response to A, consisting of a datagram containing a HANDSHAKE message 
prefixed with the chanA channel ID. Peer B's HANDSHAKE contains a 
randomly chosen channel ID, chanB.

B->A:	chanA + HANDSHAKE(chanB) + ...

Peer A now knows that peer B really responds, as it echoed chanA. So the 
next datagram that A sends may already contain heavy payload, i.e.,
a chunk. This next datagram to B will be prefixed with the chanB channel 
ID. When B receives this datagram, both peers have the proof
they are really talking to eachother, the three-way handshake is 
complete. In other words, the randomly chosen channel IDs act as cookies
(cf. RFC5971, Sec. 4.4.1).

A->B:	chanB + HAVE + DATA + ...

Protection against attack 1
---------------------------
In short, the draft already prescribes a so-called return routability 
check before heavy payload is sent. This means that attack 1 is fended 
off: PPSPP does not send back much more data than it received, unless it 
knows it is talking to a live peer. Attackers now need to intercept the 
message from B to A to get B to send heavy payload, and ensure that
that heavy payload goes to the victim, something assumed too hard to be 
a pratical attack.

Care should also be taken that a PPSPP implementation doesn't consider 
an unacknowledged peer as a subscriber to updates from that peer, i.e.,
the PPSPP peer must not send any HAVEs when push-based chunk 
availability updating is used. I propose to add a clarification
to the draft.

Note the rule is that no heavy payload may be sent until the third 
datagram. This has implications for PPSPP implementations that use chunk 
addressing schemes that are verbose. If a PPSPP implementation uses 
large bitmaps to convey chunk availability these may not be sent by peer 
B in the second datagram.

Protection against attack 2
---------------------------
In WG draft -00, on receiving the first datagram peer B will record some 
state about peer A. At present this state consists of the chanA channel 
ID, and the results of processing the other messages in the first 
datagram. In particular, if A included some HAVE messages, B may add a 
chunk availability map to A's state. In addition, B may request
some chunks from A in the second datagram, and B will maintain state 
about these outgoing requests.

Theoretically, peer A could also have included HINTs and HASHes in the 
first datagram. This could happen if peer A received some additional 
information about B's progress along with B's IP address+port. Such 
HINTs would lead to a request queue being added to A's state, and any 
HASHes, e.g., the peak hashes for the content if B is a new peer, would 
lead to the allocation by B of a partial hash tree and adding that to 
B's overall state.

Practically, there currently is no such extra progress information 
associated with peer addresses. At present, HINTs and HAVEs are sent by 
A in the third datagram or later. If HAVEs are light (e.g., bin numbers 
are used for chunk availability), B will include some HAVE messages in 
the second datagram. Only after receiving this info, A knows what chunks 
B has and will B send requests or bootstrap B with peak hashes.

So presently, PPSPP is somewhat vulnerable to attack 2. An attacker 
could send many datagrams with HANDSHAKEs and HAVEs and thus allocate 
state at the PPSPP peer. A proper implementation of PPSPP, however, will 
add a timer to this state and if the third datagram is not received 
soon, it will discard it.

I propose to modify the draft to require that peer A responds 
immediately to the second datagram, if it is still interested in peer B. 
If there is immediate interest, the response contains HINTs or DATA 
messages. If there is long term interest, e.g. in receiving HAVEs from 
B, the response may be just a keep-alive (=datagram is just chanB 
channel ID). If A has lost interest in B, A should send an explicit 
close (HANDSHAKE with all 0 channel number as payload and prefixed with 
chanB) to B.

By making quick response the rule the DOS protection improves, as the 
timeout for cleaning up stale state can be small.

With this modification I think the current protection is sufficient. If 
the WG thinks otherwise, we can introduce the mechanism from RFC5971 in 
which the receiving peer may refuse to install state on the first 
datagram. In other words, in the second datagram B will signal to A that 
is has not installed any state yet (other than remembering the channel 
ID chanA), and that A should resend any extra info it included in the 
first datagram in the third datagram (of which B knows it comes from a 
routable peer). See RFC 5971, Sec. 4.4.1.

Requirements for channel IDs
----------------------------
The safety of this scheme depends on the randomly chosen channel IDs.
RFC5971 Sec. 8.5 lists the following requirements for initial (chanA) 
cookies:

"Liveness:  The cookie must be live; that is, it must change from one
       handshake to the next.  This prevents replay attacks.

Unpredictability:  The cookie must not be guessable, e.g., from a
       sequence or timestamp.  This prevents direct forgery after
       capturing a set of earlier messages.

Easily validated:  It must be efficient for the [peer] to validate
      that a particular cookie matches an in-progress handshake, [...]
      This allows to discard responses that have been randomly generated
      by an adversary, or to discard responses to queries that were
      generated with forged source addresses [...].

Uniqueness:  Each handshake must have a unique cookie since the
      cookie is used to match responses within a handshake, e.g., when
      multiple messaging associations are multiplexed over the same
      transport connection.
"

For response (chanB) cookies RFC5971 lists the following requirements
that apply:

"Liveness:  The cookie must be live as above, to prevent replay
       attacks.

Creation simplicity:  The cookie must be lightweight to generate in
      order to avoid resource exhaustion at the responding node.

Validation simplicity:  It must be simple for the R-node to validate
      that an R-Cookie was generated by itself and no one else, without
      storing state about the handshake for which it was generated.
"
(Binding requirement does not apply)

4-byte channel IDs meet all but the last criterion. This last criterion 
would enable peer B to remain stateless during the handshake. However,
to keep latency low, I would like peer B to be able to at least request 
some data from A in the second datagram, so B needs to store some state 
about A anyway. Hence, I propose to ignore the last criterion.

What do you think?
        Arno