IPIP-501: Amino DHT HTTP Trustless Gateway compatible Provider Records - #501
IPIP-501: Amino DHT HTTP Trustless Gateway compatible Provider Records#501guillaumemichel wants to merge 4 commits into
Conversation
🚀 Build Preview on IPFS ready
|
There was a problem hiding this comment.
Thank you @guillaumemichel
This IPIP draft is ready for feedback from the ecosystem and stakeholders.
We want to make decision here before end of Q2, but we will have opt-in code in GO/JS before that.
There was a problem hiding this comment.
cc @aschmahmann as it aims to address concerns from #496
cc @willscott @masih for visibility and feedback from IPNI
cc @vasco-santos @ribasushi @alanshaw from Storacha side of things
Context: this IPIP explores idea of only authorized PeerIDs being able to announce /tls/http endpoint on Amino DHT (DHT servers would be ignoring multiaddrs that dont pass this validation), but could also act as blueprint for other routing systems that don't want to be used for amplification attacks.
Why we need this and how this relates to Storacha if it does not use DHT?
- HTTP retrieval is still wip, and remains opt-in for now
- We are already running HTTP-only retrieval from Storacha at ipfs.io/dweb.link/trustless-gateway.link, however Storacha still has to run Bitswap for the rest of the swarm, because HTTP retrieval is not enabled by default everywhere
- To be able to enable HTTP retrieval client by default across the stack (GO/JS), we need to resolve Spec for HTTPS-only providers on Amino DHT #496 first.
How does this relate to IPNI or other routing systems?
- The way IPFS clients query routing systems does not care about details of specific routing system. Query for CID produces a list of providers as PeerID + multiaddrs.
- IPNI itself could benefit from similar validation of multiaddrs and HTTP providers (afaik none exists today, addrs are accepted blindly, same amplification attack concerns as Amino DHT)
- IPNI+DHT+FOO hybrid announcement during the initial data onboarding
- The onboarding latency between announcing new CIDs to IPNI, IPNI pulling that info, and CID being resolvable via
https://cid.contactcould be mitigated by doing a one-time announcement to Amino DHT. DHT acting as a "hot storage" for routing info, before it gets propagated to systems like IPNI. - This would be done by storage providers that onboard data, and if they, like Storacha, move towards being HTTP-only, we need to agree how to handle
/tls/httpmaddrs)
- The onboarding latency between announcing new CIDs to IPNI, IPNI pulling that info, and CID being resolvable via
aschmahmann
left a comment
There was a problem hiding this comment.
I don't think either of my concerns from the linked issue were addressed. I'd like to better understand if folks don't think the concerns are valid and they're ok moving forward as-is regardless since they don't think they're that big a deal (I might just be in the minority here), or if the concerns haven't been understood.
| in DDoS attacks through bogus DHT records. It is essential for integrating IPFS | ||
| into browsers, as browser development teams prioritize robust DDoS prevention. | ||
|
|
||
| ## Detailed design |
There was a problem hiding this comment.
cc @aschmahmann as it aims to address concerns from #496
This approach does not address my first issue from #496 (comment) if this is supposed to be "enough" to do trustless-gateway based retrieval.
How to handle more than 1 HTTP-based protocol
More info (background, some options, what IPNI does, potential solutions, etc.) is in the linked comment. If we're going to flat out ignore the issue then we should at least document the ramifications / implied spec changes that come from not choosing an explicit mechanism for handling more than 1 HTTP-based protocol
There was a problem hiding this comment.
Good point!
The focus of this IPIP is to define the verification mechanism for HTTP Trustless Gateways advertisements in the Amino DHT, to prevent HTTP-only clients from being used in a DDoS (reflection) attack.
In parallel, we should have another IPIP defining the handling of multiple transfer protocols in the DHT. The current IPIP (#501) will probably depend on the future IPIP, so it will block on that.
There was a problem hiding this comment.
The follow-up IPIP @guillaumemichel promised does exist. It is #518, which puts URIs in /routing/v1 instead of multiaddrs. So your question about more than one HTTP protocol has a home, and it outlived this PR i think.
| When a DHT Server receives an `ADD_PROVIDER` RPC that includes `/tls/http` | ||
| multiaddresses, it MUST verify that the provider’s peer ID is listed in the | ||
| file located at `.well-known/libp2p/amino/providers` on the advertised HTTP | ||
| server, for all `/tls/http` addresses. If the peer ID is not found, the server |
There was a problem hiding this comment.
cc @aschmahmann as it aims to address concerns from #496
This approach does not address my second issue from #496 (comment).
Inconsistency regarding attack vectors for HTTPS vs libp2p-based protocols like tcp + tls + yamux + bitswap
A particularly easy example of this is that IIUC just about all the work this proposal tries to prevent from happening with /tls/http addresses happens anyway with /tls/ws addresses.
To illustrate:
- Assume a malicious user, Malory, wants to attack
foo.tldwhich exposes an HTTPS server, but knows nothing about IPFS - The unwitting clients who will be dialing
foo.tldare expecting to speak the IPFS HTTP Trustless Gateway protocol to them - Malory now can't easily ask DHT servers to host provider records for
/dns/foo.tld/tls/http/p2p/<peerID>(where the peerID is implied since we don't have delegated providing) - However, she can ask the DHT servers to host provider records for
/dns/foo.tld/tls/ws/p2p/<peerID>which should have the same result - The result is those target HTTP servers have to handle the TLS handshake and will then fail on the first HTTP request
I gave some options in the linked comment, but I suppose another one if you wanted to push the extra burden onto the routing system (rather than to the clients/servers) is to do more checking across addresses and/or to label which ones have been checked vs not. This does mean even more work for DHT servers though (e.g. you're now exposing them to attack vectors where Malory does a little bit of work and the DHT server ends up doing a bunch of work).
There was a problem hiding this comment.
The goal here is not to make libp2p records/maddrs more secure against DDoS (reflection) attacks, nor preventing libp2p nodes from being fooled into participating to such an attack.
The goal is to avoid adding another reflection attack vector to the Amino DHT, by preventing HTTP-only clients from being used in such attacks. This is important since we want/hope for a larger number of HTTP-only clients than we have currently of libp2p clients.
HTTP-only clients are trustless gateway users in this context.
So if this IPIP is adopted, HTTP addresses will have better security guarantees in the Amino DHT than pure libp2p addresses. It is fine to have this inconsistency because 1) the check for HTTP addresses is cheap 2) we expect HTTP-only clients to outgrow libp2p clients 3) verifying libp2p addresses is probably not cost effective (for now).
A particularly easy example of this is that IIUC just about all the work this proposal tries to prevent from happening with
/tls/httpaddresses happens anyway with/tls/wsaddresses.
IIUC trustless gateways don't use tls/ws addresses anyway, so their clients cannot be fooled into dialing /tls/ws addresses, which would require them libp2p compatibility.
This approach does not address my second issue from #496 (comment)
I gave some options in the linked comment
We built on one the possible suggested solutions.
Adding additional checks to the HTTP-based approach to bring it roughly equal to the libp2p one. There are options like:
- Use some other binding to the HTTP peer to make assertions that the endpoint actually wanted to be requested (e.g. DNS, HTTP, etc. based as happens with ACME)
There was a problem hiding this comment.
You called the gap, and I do not think this IPIP can close it, which is why I lean towards closing rather than iterating. Reasoning in my comment at the bottom of the PR.
One thing to add to your Malory example: since libp2p/go-libp2p#3509 and ipfs/kubo#11333, /tls/ws and /tls/http can be the same socket with the same certificate. They stopped being two endpoints with different properties, so the inconsistency you flagged is no longer a trade we accept, it is a label Malory picks.
kubo#11333 adds HTTPProvider.AnnounceMultiaddrs, which derives /tls/http from every /tls/ws listener and announces it through identify, the DHT and IPNI. That makes the "no /tls/http advertised today" assumption in Compatibility false, and turns ordinary nodes, not static hosting, into the typical HTTP provider. It also undercuts the premise. The same PR serves libp2p and HTTP on one TCP port, so /tls/ws and /tls/http are one listener and one certificate. An attacker denied /tls/http announces the victim's HTTPS endpoint as /tls/ws instead, and the target pays for a TCP connection and a full TLS handshake before the peer ID check rejects it, which is dearer than the cached GET this document set out to prevent. Verification that covers one protocol changes which string is abused, nothing else. - summary: note the document is a record of the discussion, not a proposal we want to ship as written - detailed design: replace the identity-bound carve-out with why /tls/http is not special, and what covering every multiaddr implies - compatibility: the check protects clients only once most servers run it, since a record lands on 20 servers and any laggard still serves the unverified address - security: the verification is itself a fan-out an attacker can aim by rotating host, port or subdomain, and it must refuse loopback, link-local and private ranges - alternatives: offline delegation signed by the HTTP operator, and verification by the retrieving client Marcin Rataj moves to former_editors.
|
Thank you for carrying this, @guillaumemichel. A year on I no longer think the approach is feasible, and I would like to close the PR. I pushed 3b2e550 first, so the reasoning stays in the document rather than only in this thread. @aschmahmann already put his finger on it in April: the work this prevents for What changed is the wire, not the argument. libp2p/go-libp2p#3509 lets a WebSocket listener share its TCP port with an HTTP handler, and ipfs/kubo#11333 builds on it: one port, one certificate, one peer identity serving The same shift undercuts the other half. For a node like that, the address is already provable: it answers libp2p identify on the very port the HTTP endpoint lives on. A well-known file adds a hosting requirement to the one case that needs no help. If someone is unhappy that the Amino DHT accepts spoofed multiaddrs, and that is a fair thing to be unhappy about, the fix is a new IPIP covering every announced address rather than one protocol, with the sane default being to trust only the multiaddr of the connection the announcement arrived on. Port sharing makes that workable for HTTP providers who also run libp2p. The reason I would not expect anyone to finish that soon is the providers this was written for. The large storage providers exposing HTTPS today do not run libp2p on those ports, so an identity-bound rule asks the whole ecosystem for a lift I cannot see landing on a useful timescale. Any future proposal has to keep a path for HTTP-only providers that never speak libp2p. So i'm closing, with the analysis on the branch. Feel free to open new IPIP that is not HTTP-centric, but addresses multiaddr spoofing in general. |
This IPIP introduces a secure mechanism for advertising
/tls/httpmultiaddresses for Truesless Gateways in the Amino DHT. By requiring HTTP Trustless Gateways to host an empty file at a well-known path the DHT servers ensure that only providers safelisted by the gateways can advertise its content. This additional verification step mitigates potential DDoS attacks and prevents malicious actors from falsely claiming that HTTP server hosts content, while leaving existing libp2p records unaffected.Fixes #496
Depends on #497
TODO:
ReprovideIntervalto spec section