ipfs / in-web-browsers

Tracking the endeavor towards getting web browsers to natively support IPFS and content-addressing
https://docs.ipfs.tech/how-to/address-ipfs-on-web/
MIT License
349 stars 29 forks source link

Dialing from an HTTPs Origin #143

Open Stebalien opened 5 years ago

Stebalien commented 5 years ago

This is a new meta-issue for everything related to dialing libp2p nodes from an HTTPs origin in a web browser.

Summary

When connecting to a libp2p node from an https origin, the libp2p node's websocket listener must (a) be using SSL/TLS, (b) have a domain name, and (c) have a valid certificate for that domain name. Almost no third-party libp2p nodes are configured this way because it means managing certificates, DNS records, etc.

Requirements:

  1. Completely automated.
  2. No central authority.
  3. Doesn't get us into trouble with CAs.

Stretch Goals:

  1. No third-parties.
  2. No double-encryption. That is, the connection only gets encrypted once (no TLS and/or secio over TLS).

Known "Solutions"

Global Key

  1. Create a '' key for `.some-domain.com`.
  2. Give this key away.
  3. Run a DNS server mapping IP.some-domain.com to IP.

Unfortunately, this key will get revoked pretty quickly.

Let's Encrypt

There's an existing service, nodetrust, designed for exactly this. It:

  1. Runs a DNS server mapping ipNXXX.XXX.XXX.XXX.libp2p-nodetrust.tk -> XXX.XXX.XXX.XXX.

  2. Gives out keys plus certificates to anyone that asks (over libp2p).

    However:

  3. It gives us neither of our stretch goals.

  4. It may get us into trouble with Let's Encrypt.

  5. We're definitely going to hit Let's Encrypt rate limits.

We could improve this a bit by having the libp2p node create the key locally, only sending a certificate signing request to the central server.

We could also have the libp2p nodes talk to Let's Encrypt directly. In that case, all we'd need is a DNS server mapping IP.some-domain.com to IP.

Relax Browser Policy

One solution would be to convince browser to relax mixed content rules for websocket connections in some cases. This may be palatable because it won't affect loading of actual content (the original intention of this rule).

Ideas:

  1. Only relax these rules for IP addresses. Technically, certs can be obtained for raw IP addresses but this is really rare.
  2. Require the programmer to pass some kind of "allow insecure" flag.
  3. Require the programmer to pass the expected key fingerprint. We can make this work by having libp2p nodes announce addresses of the form /ipN/.../tcp/.../tls/Fingerprint/ws.

This solution gives us our first stretch goal (no third parties) regardless. If we can specify the key fingerprint when opening the websocket, we actually get our second stretch goal as well (this gives us enough information to run a secure handshake over the encrypted channel to authenticate it).

Relay

We can already do this, it's just suboptimal and doesn't give us any of our stretch goals. That is:

  1. We can run some libp2p nodes with proper certs.
  2. These libp2p nodes can act as relays.

However:

  1. We'll triple encrypt (once for TLS, once for the connection to the relay, once for the connection through the relay to the remote peer).
  2. This isn't p2p and doesn't scale well. We do need to use relays for inbound connections to browsers. However, ideally we'd be able to (a) accept a relayed connection and then (b) dial that node back directly.
lidel commented 5 years ago

Somehow related, there is an IETF proposal to allow Let's Encrypt (ACME) certificate generation for raw IP addrs (https://tools.ietf.org/html/draft-ietf-acme-ip-05), removing the DNS from the picture.