Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Punch me now, but let's keep it safe #19

Open
huitema opened this issue Oct 18, 2023 · 1 comment
Open

Punch me now, but let's keep it safe #19

huitema opened this issue Oct 18, 2023 · 1 comment

Comments

@huitema
Copy link

huitema commented Oct 18, 2023

PR #11 introduced the "Punch me now" mechanism, as part of bringing the ICE capability inside QUIC. This is great, but we need to beef up the security analysis. As it stands, the client sends a list of "punch me" addresses to the server, and the server send probing packets to each address. This can cause a lot of amplification: one packet from the client, as many packets as there are addresses to be punched from the server. It could also cause request spoofing attacks, targeting unrelated services with packets that can be partially predicted by the client.

I can think of a few mitigations:

  • mitigate request spoofing by making the probing packets somewhat unpredictable. This is a bit hard, because the packets have to include a CID proposed by the client.
  • mitigate request spoofing by using the same heuristics used today on client side, such as implement a list of port numbers that will never be punched, check the scope of addresses, etc.
  • mitigate amplification by limiting the number of addresses that a server will punch. Consider that if the client sends a new PUNCH ME NOW frame, the previous one is abandoned.
  • mitigate amplification by having at most one PUNCH ME NOW frame in a packet. Or maybe limit PUNCH ME NOW to just one address, and just keep act on the last N (3?) PUNCH ME NOW frame received
  • mitigate amplification by requiring that PUNCH ME NOW frames be carried in fully padded packets, like "initial" or "challenge"
  • mitigate amplification by allowing servers to send small size probing packets.

Discuss?

@marten-seemann
Copy link
Owner

Thanks for opening this issue @huitema! You're right that in the current iteration the details of the amplification protection still need a lot of work.

  • mitigate request spoofing by making the probing packets somewhat unpredictable. This is a bit hard, because the packets have to include a CID proposed by the client.

Right. There's a risk of a request forgery attack here, but the risk is a lot smaller than what RFC 9000 section 21.5 describes. The attacker doesn't control more than 20 bytes of the packet (the CID), the size of the packet is set to at least 1200 bytes, all of which (except for the first one) will be indistinguishable from random for a 3rd party.

  • mitigate request spoofing by using the same heuristics used today on client side, such as implement a list of port numbers that will never be punched, check the scope of addresses, etc.

This will work in certain scenarios, and break in others. We can list this as a possible mitigation strategy, but I don't think we can require it.

  • mitigate amplification by limiting the number of addresses that a server will punch. Consider that if the client sends a new PUNCH ME NOW frame, the previous one is abandoned.
  • mitigate amplification by having at most one PUNCH ME NOW frame in a packet. Or maybe limit PUNCH ME NOW to just one address, and just keep act on the last N (3?) PUNCH ME NOW frame received

Limiting concurrency sounds reasonable, and the protocol provides a mechanism for that: The transport parameter already allows limiting the number of concurrent path probes. We should add some text that this can be used to mitigate the amplification attack as well.

  • mitigate amplification by requiring that PUNCH ME NOW frames be carried in fully padded packets, like "initial" or "challenge"

We could also reuse the byte counting logic we're using during the handshake: A node is only allowed to send 3x the number of received bytes to unverified addresses (note the plural here). You wouldn't necessarily need to pad the PUNCH_ME_NOW packets, any bytes sent on the connection would suffice.

  • mitigate amplification by allowing servers to send small size probing packets.

This would make people concerned about bandwidth requirements happy. However, it would also mean that you don't verify that the path actually supports QUIC (i.e. UDP datagrams >= 1200 bytes), which seems bad. Maybe a 2-step procedure would help here: First verify connectivity using small probe packets, then confirm that the path supports 1200 bytes. Obviously, this takes one additional roundtrip, which is a tradeoff that might or might not be worthwhile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants