Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
gmaclennan
left a comment
There was a problem hiding this comment.
I left some comments on the approach. I'm not sure the division of responsiblities between the member-api and the remote-discovery class is quite right, but it depends on how you resolve the validation / authentication of incoming connections, which is the most important challenge to address.
| const swarm = await this.#ensureSwarm() | ||
| const noisePublicKey = Buffer.from(publicKey, 'hex') | ||
|
|
||
| const onConnected = pEvent(this, 'connection', { |
There was a problem hiding this comment.
Although currently unlikely, we should add defensive code for when the client is already connected to the peer when connectPeer is called.
| identityKeypair: this.#keyManager.getIdentityKeypair(), | ||
| logger, | ||
| }) | ||
| this.#remoteDiscovery.on('connection', this.#replicate.bind(this)) |
There was a problem hiding this comment.
This is where we need an authentication guard on the server, validating that the incoming connection has the shared inviteId secret, but also with the manual PIN validation based on the connection handshake hash and verified out-of-band, because otherwise we are giving any incoming connection (which could come from anywhere) access to the RPC channel, which is not secure - it could send invites or other nefarious stuff.
There was a problem hiding this comment.
Mind elaborating on the security issues you expect? Inviting internet connected peers to other projects seems like a potential use case in the future.
There was a problem hiding this comment.
The attack vector I am concerned about:
- I am a remote attacker
- I portscan your device, find the open port, and initiate a noise connection.
- I can now send RPC messages to your device like DoS invite to project - only the
invite-over-internet-redeemedhas a check on it.
Of course a similar vulnerability exists prior to this change from an attacker on the local network - our security review picked up on that - however this is a smaller and more acceptable risk.
|
I've got the connection and invite flow going. We want to make it harder to track specific peers via the DHT, therefore we want to use a fresh DHT keypair each time. The difficult part is that the keypair is used for the Gregor proposed we have something like this to send the real identity as the first packet down the noise stream after handshaking. This could leave the option to join by remote public key instead of a fresh topic. We will also need some sort of access control step to have the invite ID before we expose the protomux channel for RPC. |
…t.$member.getMany
|
Been wrestling with some sort of race condition for several hours now. I think I traced it down to the protomux channel recieving data before it's fully opened. |
gmaclennan
left a comment
There was a problem hiding this comment.
I still think we need an authentication step before connecting to the RPC channel:
Validating the inviteID and allowing the user (invitor) to confirm before connecting, which means queueing the connection somewhere until the user confirms
| }).finish() | ||
| ) | ||
|
|
||
| const data = await firstData |
There was a problem hiding this comment.
No guarantee this will come as a single chunk. Maybe needs to be length delimited or something? Or rely on it being a fixed length.
There was a problem hiding this comment.
Length delimited is probably the safest option. uint32 to be safe?
There was a problem hiding this comment.
On the other hand I'm like 99% sure that the first packet will always be a single UDP packet passed through UDX
| } | ||
|
|
||
| // @ts-ignore | ||
| socket.handshakePublicKey = msg.publicKey |
There was a problem hiding this comment.
Could just override remotePublicKey to avoid changes in the rest of the code.
|
Been blocked getting the tests to work with the handshake logic. Seems the connection is breaking when we try to write the public key down the wire and isn't draining. |
|
Might do a flag in local-peers to ignore incoming RPC messages until we get authenticated? I think this extra handshake step is making everything more fragile. |
|
Been trying a bunch of ways to rework this and I'm getting a bit stuck. Gonna write out some thoughts on approaches here. Initial approach:
This worked fine Ephemeral keys approach
This didn't work because the connection was "breaking" after sending the first packet. I think it's got something to do with how we're reading a packet of the stream before sending it off elsewhere, but it's been really difficult to debug. Edit: I got this working! I needed to pause the stream after getting the first packet, else we'd drop an event. Queue up connections before RPCIn order to guard the RPC methods from spam, we should prompt the user to verify them before replicating anything. If we queue up the connections (at the manager level) we need a new place to track them that isn't local peers and would need to somehow tie them to the project they're trying to join via the member API. This extra book keeping and connection management is IMO not ideal. We'd likely need to add the invite ID into the handshake after establishing hyperswarm, which would also mean getting the remote discovery module to ask each project's Alternate: Disable RPC until connection is verifiedInstead we could mark peers inside localPeers as being |
|
TODO: Test all the edge cases |
|
TODO: Convert all |
Closes #1207