-
Notifications
You must be signed in to change notification settings - Fork 298
WebSockets: add opt-in delegation of encryption to TLS #625
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
base: master
Are you sure you want to change the base?
Changes from 2 commits
17c7ccc
b680589
3c3a3a9
d9402f6
08a0665
f7837dc
76ca6ec
cc8b242
7c2f77f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # libp2p WebSockets | ||
|
|
||
| | Lifecycle Stage | Maturity | Status | Latest Revision | | ||
| |-----------------|--------------------------|--------|-----------------| | ||
| | 2A | Candidate Recommendation | Active | r0, 2022-10-12 | | ||
|
|
||
| Authors: [@achingbrain] | ||
|
|
||
| Interest Group: [@MarcoPolo] | ||
|
|
||
| [@achingbrain]: https://github.com/achingbrain | ||
| [@MarcoPolo]: https://github.com/MarcoPolo | ||
|
|
||
| See the [lifecycle document](../00-framework-01-spec-lifecycle.md) for context about maturity level | ||
| and spec status. | ||
|
|
||
| ## Introduction | ||
|
|
||
| [WebSockets](https://websockets.spec.whatwg.org/) are a way for web applications to maintain bidirectional communications with server-side processes. | ||
|
|
||
| All major browsers have shipped WebSocket support and the implementations are both robust and well understood. | ||
|
|
||
| A WebSocket request starts as a regular HTTP request, which is renegotiated as a WebSocket connection using the [HTTP protocol upgrade mechanism](https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism). | ||
|
|
||
| ## Drawbacks | ||
|
|
||
| WebSockets suffer from [head of line blocking](https://en.wikipedia.org/wiki/Head-of-line_blocking) and provide no mechanism for stream multiplexing, encryption or authentication so additional features must be added by the developer or by libp2p. | ||
|
|
||
| In practice they only run over TCP so are less effective with [DCuTR Holepunching](../relay/DCUtR.md). | ||
|
|
||
| ## Certificates | ||
|
|
||
| With [some exceptions](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure) browsers will prevent making connections to unencrypted WebSockets when the request is made from a [Secure Context](https://www.w3.org/TR/secure-contexts/). | ||
|
|
||
| Given that libp2p makes extensive use of the [SubtleCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto), and that API is only available in Secure Contexts, it's safe to assume that any incoming libp2p connections initiated over WebSockets originate from a Secure Context. | ||
|
|
||
| Consequently server-side processes listening for incoming libp2p connections via WebSockets must use TLS certificates that can be verified by the connecting user agent. | ||
|
|
||
| These must be obtained externally and configured in the same way as you would for an HTTP server. | ||
|
|
||
| The only exception to this is if both server and client are operating exclusively on loopback or localhost addresses such as in a testing or offline environment. Such addresses should not be shared outside of these environments. | ||
|
|
||
| ## Stream Multiplexing | ||
|
|
||
| WebSockets have no built in stream multiplexing. Server-side processes listening for incoming libp2p connections via WebSockets should support [multi-stream select](https://github.com/multiformats/multistream-select) and negotiate an appropriate stream multiplexer such as [yamux](../yamux/README.md). | ||
|
|
||
| ## Authentication | ||
|
|
||
| WebSockets have no built in authentication mechanism. Server-side processes listening for incoming libp2p connections via WebSockets should support [multi-stream select](https://github.com/multiformats/multistream-select) and negotiate an appropriate authentication mechanism such as [noise](../noise/README.md). | ||
|
|
||
| ## Encryption | ||
|
|
||
| Server-side processes listening on WebSocket addresses should use TLS certificates to secure transmitted data at the transport level. | ||
|
|
||
| This does not provide any assurance that the remote peer possesses the private key that corresponds to their public key, so an additional handshake is necessary. | ||
|
|
||
| During connection establishment over WebSockets, before the connection is made available to the rest of the application, if all of the following criteria are met: | ||
|
|
||
| 1. `noise` is negotiated as the connection encryption protocol | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So despite
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's correct. Noise does a handshake and encryption, and here we only want the handshake since encryption is done by TLS at the transport layer. This is similar to how the WebTransport and WebRTC transports work. We still negotiate a connection encryption protocol for backwards compatibility and to allow for alternatives to noise in the future. |
||
| 2. An initial handshake is performed with the `handshake_only` boolean extension set to true | ||
| 3. The transport layer is secured by TLS | ||
|
|
||
| Then all subsequent data is sent without encrypting it at the libp2p level, instead relying on TLS encryption at the transport layer. | ||
|
|
||
| If any of the above is not true, all data is encrypted with the negotiated connection encryption method before sending. | ||
|
|
||
| This prevents double-encryption but only when both ends opt-in to ensure backwards compatibility with existing deployments. | ||
|
|
||
| ### MITM mitigation | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't work unless the server somehow includes their domain name in their noise handshake. Otherwise, an attacker can simply announce that some peer id Furthermore, by including the domain name in the noise handshake, the server is opting-in to trusting the CA system.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this also doesn't work unless the server trusts all owners of the given domain name. If the server operator is the sole owner of the domain name, this is fine. But if another party controls the domain name as well, but not the private key to the peer ID, they would be able to MITM/intercept this connection.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good points both.
I've added a further
I've added a note to this effect.
I've copied the Do you think this covers it? |
||
|
|
||
| The TLS certificate used should be signed by a trusted certificate authority, and the host name should correspond to the common name contained within the certificate. | ||
|
|
||
| This requires trusting the certificate authority to issue correct certificates, but is necessary due to limitations of certain user agents, namely web browsers which do not allow use of self-signed certificates that could be otherwise be verified via preshared certificate fingerprints. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’d include a sentence that mentions Keying Material Exporters (RFC 5705), which, in a perfect world, would be the preferred solution.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a sentence - please suggest an edit if you think it needs more exposition. |
||
|
|
||
| ## Addressing | ||
|
|
||
| A WebSocket address contains `/ws`, `/tls/ws` or `/wss` and runs over TCP. If a TCP port is omitted, a secure WebSocket (e.g. `/tls/ws` or `/wss` is assumed to run on TCP port 443), an insecure WebSocket is assumed to run on TCP port 80 similar to HTTP addresses. | ||
|
|
||
| Examples: | ||
|
|
||
| * `/ip4/192.0.2.0/tcp/1234/ws` (an insecure address with a TCP port) | ||
| * `/ip4/192.0.2.0/tcp/1234/tls/ws` (a secure address with a TCP port) | ||
| * `/ip4/192.0.2.0/ws` (an insecure address that defaults to TCP port 80) | ||
| * `/ip4/192.0.2.0/tls/ws` (a secure address that defaults to TCP port 443) | ||
| * `/ip4/192.0.2.0/wss` (`/tls` may be omitted when using `/wss`) | ||
| * `/dns/example.com/wss` (a DNS address) | ||
| * `/dns/example.com/wss/http-path/path%2Fto%2Fendpoint` (an address with a path) | ||
Uh oh!
There was an error while loading. Please reload this page.