ipfs / kubo

An IPFS implementation in Go
https://docs.ipfs.tech/how-to/command-line-quick-start/
Other
16.05k stars 3k forks source link

Enable the websocket listener by default #5251

Open Stebalien opened 6 years ago

Stebalien commented 6 years ago

Currently, we don't because we considered it useless. Browsers usually still can't dial go nodes because they need a wss listener (https) and we can't get the certs in go.

However, it turns out that our ws transport supports proxies out of the box :man_shrugging:. Simply turning on the websocket listeners should open up the network to users behind corporate firewalls. We don't even have to worry about corporate MITMs because we do our own crypto inside the websocket.

parkan commented 5 years ago

it's been long enough since I looked at the wss/ws issue that I forgot: is it solely because the libraries/page are loaded in the HTTPS context (requiring all ws connections to be secure as well), or is there a reason beyond that?

Stebalien commented 5 years ago

There are two separate issues here:

  1. The issue you're describing. Browsers can only dial HTTPS websockets from HTTPS origins.
  2. This issue is about dialing out of corporate networks from non-browser nodes. That is, websockets (secure or not) are HTTP so they can use HTTP proxies.
hsanjuan commented 3 years ago

Is Go compiled into wasm able to use non-secure websockets to talk to other nodes when running inside a browser, or is it still limited to wss? (given that the code may run in a fully local context - local gateway, where things may be allowed?).

(@lidel perhaps you know?)

lidel commented 3 years ago

@hsanjuan wasm will behave the same way as regular JS. No difference.

TLDR: in browsers, WebSockets execute only within the boundary of secure contexts, so the only plaintext ws:// you can dial from HTTPS page is on localhost


Most of "rules" in the browser context are related to the concept of secure contexts. Spec is one thing, implementations are hairy, but for the sake of this conversation we can simplify and say "secure context" is a document loaded over TLS tunnel (https://), but also local machine at http://127.0.0.1 and thanks to our collab with Igalia http://localhost and http://*.localhost too (at least in Firefox and Chromium). Recently introduced implementation of ipfs:// and ipns:// in Brave v1.19 is also marked as a secure context.

AFAIK in the case of WebSockets, rules are straightforward: JS code executed from secure context will only be able to connect to other secure context.

This means a page loaded from secure context should not be able to establish unencrypted WebSocket connection, unless it is to localhost.

Localhost demo

To illustrate, below is a simple poc: a server that runs on localhost, and a static html page with JS that connect to it:

Click to expand PoC source code #### Server ```js const WebSocket = require('ws') const wss = new WebSocket.Server({ port: 28080 }) wss.on('connection', function connection(ws) { ws.on('message', function incoming(message) { console.log('received: %s', message) }) ws.send('Hello client!') }) ``` #### Client ```html ```

You can load the HTML from local gateway or a public page loaded over HTTPS, it works fine in both cases (below Firefox and Brave with Shields turned off):

$ node ws-server.js
received: Hello Server! 
I'm http://bafkreihqk4ie7zfeedkexb5yfjo7y4ngcjlcydy3behxwd7hkkptcvlliy.ipfs.localhost:8080/ 
loaded via Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0

received: Hello Server! 
I'm https://ipfs.io/ipfs/bafkreihqk4ie7zfeedkexb5yfjo7y4ngcjlcydy3behxwd7hkkptcvlliy 
loaded via Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.89 Safari/537.36

received: Hello Server! 
I'm https://ipfs.io/ipfs/bafkreihqk4ie7zfeedkexb5yfjo7y4ngcjlcydy3behxwd7hkkptcvlliy 
loaded via Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.89 Safari/537.36
hsanjuan commented 3 years ago

Thanks @lidel :)

Gozala commented 3 years ago

This is coming up over and over again. Any reason not to make this a default ? Unless there is one how do we make this happen ?

lidel commented 3 years ago

It should be pretty safe to enable this on localhost addr (because it is only useful on localhost + if someone wants to add TLS then they put it behind Nginx anyway).

I can make this happen with some help/guidance.

@Stebalien @aschmahmann Is there a prior art or policy for enabling a new transport by default?

Gozala commented 3 years ago

(because it is only useful on localhost + if someone wants to add TLS then they put it behind Nginx anyway).

Is it not useful for nodejs nodes ? I suppose they could dial TCP instead, but still unless there is a reason to have it disabled I'd go with you can disable as a default as opposed you can enable.

Gozala commented 3 years ago

http sites are rare these days, but they could potentially also benefit from having /ws enabled on nodes even if those aren't setup with TLS.

Stebalien commented 3 years ago

The main reason not to enable this right now is that we dial all transports in parallel. We already have QUIC+TCP, both IPv6 and IPv4.

Someone would need to take that on as a (possibly mini) project. @vyzo was looking to handle this as part of https://github.com/libp2p/go-libp2p-swarm/pull/250 but it's looking like it'll be... complicated and should happen in a followup patch.

Stebalien commented 3 years ago

Hm. Actually, this change is much easier than that. We just need to say "if a peer supports both TCP and WS, only try WS if we don't support TCP".

Doing this generically is tricky... but we might just have to be a bit less generic for now.

Stebalien commented 3 years ago

http sites are rare these days, but they could potentially also benefit from having /ws enabled on nodes even if those aren't setup with TLS.

Yeah, but not enough for us to prioritize this.

BladeMcCool commented 3 years ago

why can't you get the certs in go? this guy did for his thing .... i use this for my go project with gorilla mux to serve a ui via HTTPS. it works perfectly so far.

https://blog.kowalczyk.info/article/Jl3G/https-for-free-in-go-with-little-help-of-lets-encrypt.html