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

Enable the websocket listener by default #5251

Open
Stebalien opened this issue Jul 18, 2018 · 13 comments
Open

Enable the websocket listener by default #5251

Stebalien opened this issue Jul 18, 2018 · 13 comments
Labels
kind/enhancement A net-new feature or improvement to an existing feature

Comments

@Stebalien
Copy link
Member

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 🤷‍♂️. 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
Copy link

parkan commented Jan 21, 2019

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
Copy link
Member Author

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
Copy link
Contributor

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
Copy link
Member

lidel commented Jan 26, 2021

@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

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

<script>
const socket = new WebSocket('ws://localhost:28080');
socket.addEventListener('open', function (event) {
  socket.send(`Hello Server! I'm ${window.location.href} loaded via ${navigator.userAgent}`)
})
socket.addEventListener('message', function (event) {
  console.log('Message from server ', event.data)
})
socket.addEventListener('close', function (event) {
  console.log('The connection has been closed')
})
</script>

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
Copy link
Contributor

Thanks @lidel :)

@Gozala
Copy link

Gozala commented Mar 29, 2021

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
Copy link
Member

lidel commented Mar 30, 2021

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?

  • How did we handle existing users when we added /quic?
  • For new users, I think it is a matter of adding /ws addr to the default list of addrs: go-ipfs-config/init.go#L109-L115 – is there more to this?

@Gozala
Copy link

Gozala commented Mar 30, 2021

(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
Copy link

Gozala commented Mar 30, 2021

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
Copy link
Member Author

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 libp2p/go-libp2p-swarm#250 but it's looking like it'll be... complicated and should happen in a followup patch.

@Stebalien
Copy link
Member Author

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
Copy link
Member Author

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
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/enhancement A net-new feature or improvement to an existing feature
Projects
None yet
Development

No branches or pull requests

6 participants