Subject: [quicwg/base-drafts] Fix for off-path migration attack (#2033)

From: Martin Thomson <[email-masked]>
Date: Tue, 20 Nov 2018 22:13:37 -0800

This is not an easy attack to defend against, except for
probabilistically.  So what we do is recommend more probing on old paths
to give the endpoint that is apparently migrating more opportunities to
cause the connection to migrate away from the path chosen by an
attacker.

I've tweaked surrounding text a little.  The most interesting being the
3RTO timer on path validation.  It's not the right number, but I don't
think that the right number is attainable, and this is close enough.

This text isn't final. I'd like it to be more accurate AND shorter, but
lack the skills and perspective.

Closes #1278, #1749.
You can view, comment on, or merge this pull request online at:

  https://github.com/quicwg/base-drafts/pull/2033

-- Commit Summary --

  * Fix for off-path migration attack

-- File Changes --

    M draft-ietf-quic-transport.md (80)

-- Patch Links --

https://github.com/quicwg/base-drafts/pull/2033.patch
https://github.com/quicwg/base-drafts/pull/2033.diff

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 20 Nov 2018 22:45:46 -0800

Thank you for writing down the PR.

I know that this question has been asked before, but do we need PATH_CHALLENGE and PATH_RESPONSE to verify NAT rebinding?

IIUC a client has only one path that can be used for send non-probing packets. Therefore, a server receiving a non-probing packet (with a PN greater than what it has seen before) can be used as a way to determine the current active path.

So to me, it seems that just using PING will be sufficient for the server to verify what the client thinks as the current path. In other words, there is no reason for a _server_ to send PATH_CHALLENGE (and for a client to send PATH_RESPONSE).

The reason I raise the question, even though I understand that the PATH_CHALLENGE / PATH_RESPONSE is nevertheless required for the client to "probe" for a new path, is because removing the requirement for the server to send a challenge / wait for response seems like a simplification (at the cost of increasing asymmetry).

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#issuecomment-440556206

---

From: Marten Seemann <[email-masked]>
Date: Wed, 21 Nov 2018 06:17:58 -0800

marten-seemann commented on this pull request.

> @@ -1766,7 +1768,8 @@ abandons its attempt to validate the path.
 
 Endpoints SHOULD abandon path validation based on a timer. When setting this
 timer, implementations are cautioned that the new path could have a longer
-round-trip time than the original.
+round-trip time than the original.  A value of three times the current
+Retransmittion Timeout (RTO) as defined in {{QUIC-RECOVERY}} is RECOMMENDED.

This won’t work out well when switching from a 10ms WiFi. 
I don’t think any value derived from the current RTT helps here. We don’t have any information about the new path, so I suggest we define a constant duration. 

> @@ -1938,6 +1941,52 @@ Note that receipt of packets with higher packet numbers from the legitimate peer
 address will trigger another connection migration.  This will cause the
 validation of the address of the spurious migration to be abandoned.
 
+
+### Off-Path Packet Forwarding {#off-path-forward}
+
+An off-path attacker that can observe packets might forward copies of genuine
+packets to endpoints.  If the copied packet arrives before the genuine packet,
+this will appear as a NAT rebinding.  Any genuine packet will be discarded as a

We should be more precise in describing the attack:
* when racing packets to the server, the attacker uses his own sender address on the UDP packet
* when forwarding packets to the client, the attacker doesn’t spoofs the server’s address

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#pullrequestreview-177241028

---

From: MikkelFJ <[email-masked]>
Date: Wed, 21 Nov 2018 10:07:07 -0800

mikkelfj commented on this pull request.

I had the same thought, or a minimum value of sorts.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#discussion_r235491326

---

From: Mike Bishop <[email-masked]>
Date: Wed, 21 Nov 2018 10:38:40 -0800

MikeBishop commented on this pull request.

I agree it feels a bit verbose, but I think all the right information is there.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#pullrequestreview-177381294

---

From: Christian Huitema <[email-masked]>
Date: Wed, 21 Nov 2018 22:00:43 -0800

huitema commented on this pull request.

> +relatively few packets are sent or if packet loss coincides with the attempted
+attack.
+
+A non-probing packet received on the original path that increases the maximum
+received packet number will cause the endpoint to move back to that path.
+Eliciting packets on this path increases the likelihood that the attack is
+unsuccessful.  Therefore, mitigation of this attack relies on triggering the
+exchange of packets.
+
+In response to an apparent migration, endpoints MUST validate the previously
+active path using a PATH_CHALLENGE frame.  This induces the sending of new
+packets on that path.  If the path is no longer viable, the validation attempt
+will time out and fail; if the path is viable, but no longer desired, the
+validation will succeed, but only result in a probing packet being sent on the
+path.
+

Since this is all heuristics, we may want to be a bit more explicit. If the destination CID in the packet is new, then the migration is more likely to be voluntary. If the address family is IPv6, NAT rebinding is not expected quite as much, even with NAT66, since NAT66 is very unlikely to run out of address space. If the last rebinding happened fewer than X seconds ago, this is probably very suspicious. Etc.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#pullrequestreview-177513087

---

From: Christian Huitema <[email-masked]>
Date: Wed, 21 Nov 2018 22:02:28 -0800

> +path.
+
+An endpoint that receives a PATH_CHALLENGE on an active path SHOULD send a
+non-probing packet in response.  If the non-probing packet arrives before any
+copy made by an attacker, this results in the connection being migrated back to
+the original path.  Any subsequent migration to another path resets this entire
+process.
+
+Abandoning this validation attempt before it either succeeds or times out
+increases exposure to the packet copying attack.
+
+This defense is imperfect, but this is not considered a serious problem. If the
+path via the attack is reliably faster than the original path despite multiple
+attempts to use that original path, it is not possible to distinguish between
+attack and an improvement in routing.
+

Well, yeah, except if the improvement in routing only last for a short while, and after that the connection is dropped.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#pullrequestreview-177513379

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 21 Nov 2018 22:24:36 -0800

kazuho commented on this pull request.

+

Yeah but doesn't the connection simply move back to the original path once the attacker stops racing the packets?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#discussion_r235612497

---

From: erickinnear <[email-masked]>
Date: Thu, 22 Nov 2018 11:32:10 -0800

erickinnear approved this pull request.

There is a fair bit of text here, but overall seems like a good balance of addressing the concern without adding significant complexity. Thanks for putting this together and writing it up! 

> @@ -1753,10 +1753,12 @@ have failed, even if the data matches that sent in the PATH_CHALLENGE.
 Additionally, the PATH_RESPONSE frame MUST be received on the same local address
 from which the corresponding PATH_CHALLENGE was sent.  If a PATH_RESPONSE frame
 is received on a different local address than the one from which the
-PATH_CHALLENGE was sent, path validation is considered to have failed, even if
-the data matches that sent in the PATH_CHALLENGE.  Thus, the endpoint considers
-the path to be valid when a PATH_RESPONSE frame is received on the same path
-with the same payload as the PATH_CHALLENGE frame.
+PATH_CHALLENGE was sent, path validation is not considered to be successful,
+even if the data matches that sent in the PATH_CHALLENGE.  This doesn't result
+in path validation failure, as it might be a result of a forwarded packet (see
+{{off-path-forward}}) or misrouting.  Thus, the endpoint considers the path to
+be valid when a PATH_RESPONSE frame is received on the same path with the same

We now have three options for path validation: success, failure, and neither. Are there any other places that reference this where we need to update the wording around expected behaviors? 

Is this a necessary (independent) paragraph? 

> @@ -1963,13 +2012,16 @@ multiple paths will still send ACK frames covering all received packets.
 
 While multiple paths might be used during connection migration, a single
 congestion control context and a single loss recovery context (as described in
-{{QUIC-RECOVERY}}) may be adequate.  A sender can make exceptions for probe
-packets so that their loss detection is independent and does not unduly cause
-the congestion controller to reduce its sending rate.  An endpoint might set a
-separate timer when a PATH_CHALLENGE is sent, which is cancelled when the
-corresponding PATH_RESPONSE is received.  If the timer fires before the
-PATH_RESPONSE is received, the endpoint might send a new PATH_CHALLENGE, and
-restart the timer for a longer period of time.
+{{QUIC-RECOVERY}}) may be adequate.  For instance, an endpoint might delay
+switching to a new congestion control context until it is confirmed that an old
+path is no longer needed (for the case in {{off-path-forward}}).

Nit: wording
```suggestion
path is no longer needed (such as the case in {{off-path-forward}}).
```
(or something of that sort)

+

Right, since there will still be duplicate packets from the client and you can't make the client actually change the remote address that it sends to. So even if the attack succeeds, if the attacker stops delivering packets (or even starts delivering them more slowly), I think you would automatically just go back to the original path (as long as the client is still sending). 

My understanding here is that this overall change is mostly necessary to prompt traffic from a client that might otherwise have quiesced. 

> -packets so that their loss detection is independent and does not unduly cause
-the congestion controller to reduce its sending rate.  An endpoint might set a
-separate timer when a PATH_CHALLENGE is sent, which is cancelled when the
-corresponding PATH_RESPONSE is received.  If the timer fires before the
-PATH_RESPONSE is received, the endpoint might send a new PATH_CHALLENGE, and
-restart the timer for a longer period of time.
+{{QUIC-RECOVERY}}) may be adequate.  For instance, an endpoint might delay
+switching to a new congestion control context until it is confirmed that an old
+path is no longer needed (for the case in {{off-path-forward}}).
+
+A sender can make exceptions for probe packets so that their loss detection is
+independent and does not unduly cause the congestion controller to reduce its
+sending rate.  An endpoint might set a separate timer when a PATH_CHALLENGE is
+sent, which is cancelled when the corresponding PATH_RESPONSE is received.  If
+the timer fires before the PATH_RESPONSE is received, the endpoint might send a
+new PATH_CHALLENGE, and restart the timer for a longer period of time.

I thought we'd already addressed this elsewhere, but I can't find it anymore, so this looks good. 
My memory was that we said to retransmit PATH_CHALLENGE based on a timer until you got a response or decide that validation failed, although now we have three states for validation result. If we have that elsewhere (and I just missed it) then we should reconcile with this.

> @@ -1963,13 +2012,16 @@ multiple paths will still send ACK frames covering all received packets.
 
 While multiple paths might be used during connection migration, a single
 congestion control context and a single loss recovery context (as described in
-{{QUIC-RECOVERY}}) may be adequate.  A sender can make exceptions for probe
-packets so that their loss detection is independent and does not unduly cause
-the congestion controller to reduce its sending rate.  An endpoint might set a
-separate timer when a PATH_CHALLENGE is sent, which is cancelled when the
-corresponding PATH_RESPONSE is received.  If the timer fires before the
-PATH_RESPONSE is received, the endpoint might send a new PATH_CHALLENGE, and
-restart the timer for a longer period of time.
+{{QUIC-RECOVERY}}) may be adequate.  For instance, an endpoint might delay
+switching to a new congestion control context until it is confirmed that an old
+path is no longer needed (for the case in {{off-path-forward}}).
+
+A sender can make exceptions for probe packets so that their loss detection is
+independent and does not unduly cause the congestion controller to reduce its
+sending rate.  An endpoint might set a separate timer when a PATH_CHALLENGE is

...which makes sense, given that you don't retransmit PATH_CHALLENGE or PATH_RESPONSE, maybe we should note that here or nearby as well?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#pullrequestreview-177753396

---

From: Martin Thomson <[email-masked]>
Date: Thu, 22 Nov 2018 15:35:41 -0800

@martinthomson pushed 2 commits.

8a385be  Some editorial tweaks
567ab8e  Heuristics are the worst

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033/files/316f7f1313bd89656f467f036916047fbc45a182..567ab8e3619bc25b72a0937656c9cf1e14bc84b0

---

From: Martin Thomson <[email-masked]>
Date: Thu, 22 Nov 2018 15:39:16 -0800

martinthomson commented on this pull request.

We always had that (this is just changing this text to be consistent with the text in other places).

I considered that, but we still have a minimum on the RTO, which should cover this case well enough.

+

I don't think that we need a precise description of the attack.  This is already far too many words.

+attack.
+

The point here is that this isn't heuristics-based decision-making.  It's currently arranged to be mechanical.  The only discretionary part is the rate at which probes are generated.  I think that the right thing to do is acknowledge that heuristics might be used to make this defense more robust and to mention some of the things you point to.

+

The risk is that the attacker can convince a peer that the connection is dead, meaning that no more packets are sent.  The interaction between validation timers and dead path detection probably need some work.

This is just the old text, with the paragraph split to allow for the new text.  If you have a suggestion here, that would be great, but I can't figure out how to add that without doing a lot of damage to the existing text.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#discussion_r235828354

---

From: Ken McMillan <[email-masked]>
Date: Thu, 22 Nov 2018 18:15:22 -0800

kenmcmil commented on this pull request.

Maybe this statement should be made more explicit. That is, the server should not abandon or even postpone a pending path validation when a new apparent migration is seen. Consider the case where the copying attacker's path to the server has about the same latency as the client's path. The server will see a random mix of packets from both paths, which results in a rapid sequence of apparent migrations. If each apparent migration causes pending validation attempts to be abandoned, or just causes the timer to be reset, then no validation will succeed and the server will never send another non-probing packet. This is what I observed in picoquic -- successive timer resets caused the server to become completely silent. 

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2033#discussion_r235836963