[Security discussion] Limiting client reach

I think we need to discuss ways to implement limitations on the client side. The current version of boringproxy allow for a tunnel to be set up to any address/port connected to the client device. This essentially extend the LAN network of the client device to the cloud server.

Having the ability to create a tunnel to a device on the LAN of the client device is useful. It allows for docker containers to use boringproxy and it also allows connection to devices that can’t run boringproxy like CCTV cameras. Therefore I am not saying boringproxy should be limited to localhost, but even on localhost there should be limitations on the ports accessible via boringproxy.

For users that own their own server and set it up securely, this should not be a problem. You essentially have an always on VPN between a cloud device that you own and your local network. The biggest issue comes in for shared servers. Since the tokens are stored in plain text on the server, the admin (or anyone with access to the server) can obtain the token for clients [encrypting tokens on the server is a future discussion]. They can then create additional tunnels to devices on the client network.

I suggest we change the default of the client to only allow boring to localhost port 80. If the user want to allow access to additional ports/hosts it needs to be added with a whitelist flag. The client will then check the whitelist before making the tunnel and if the host/port requested by the server is in the whitelist, the tunnel is established otherwise it errors out.

The goal would be to create a whitelist (or blacklist) with sufficient functionality, while also keeping the implementation simple.

Some of the things to discuss:

  • Should default be block all, block most or allow all?
  • If default is block most, what do we allow? Perhaps only localhost:80 or entire localhost?
  • Should we create multiple flags with increased complexity that override each other. The basic flag can be localhost-only: yes/no with additional flags including whitelist: ["192.168.0.4:80","192.168.0.5:5432","localhost:22"]. A basic user can then use the localhost-only flag to choose between local only and entire LAN, where an advanced user can add the whitelist flag that would override the localhost-only flag and only allow tunnels to hosts:ports in whitelist?

Please give your thoughts. I haven’t written any code of this, I think its a good idea to first discuss it to find the balance between complexity and usability. We don’t want to sacrifice functionality in the pursuit of simplicity, but it also does not help if we create an overcomplicated system that no one can use.

@WGrobler as always these are excellent points, and I’ve been thinking somewhat along similar lines recently.

The good news is I think this may be solved with the work I’ve been doing on the open tunneling protocol. Basically I think I’ve designed a protocol that should allow all the functionality of boringproxy, but without the server and client needing to trust each other. So the server only connects domains to tunnels, and all the control over what happens on the other end of the tunnel is controlled by the client.

The coolest part is I think we’ll be able to still have web GUIs for controlling all these settings, but each client can have its own e2ee UI. So sensitive clients can be completely locked down with nothing exposed to the server, while still providing the convenience of remote control.

I’m still in the process of prototyping this, but I say we hold off on making other security changes until you have a chance to try it out and see if it accomplishes what you need.

If you are solving this on the open tunnel protocol side, lets hold off on this for now.

I haven’t spend sufficient time on reading and testing the new protocol, will try to carve out some time to really get into it. Understanding the basics of boringproxy is easy since it relies on reverse SSH, but I will have to read all you have done on the open protocol side to fully understand it.

There’s not much information about the protocol. I’ve made a few more design decisions, but I think the real feedback can wait until I have the prototype ready to play with. Hopefully later this week or next.

The new protocol will still support SSH though. It’s meant to be transport-agnostic, so we can add transports like QUIC as they stabilize.