What you did
You used three ssh commands:
While inside a B console you did:
ssh -4 -N -f -R 18822:localhost:22 <user>@<vps>
Command sshd (the server) to open port
18822, a remote port
vps:18822 connected to localhost (B) port 22.
While at a vps console you did:
ssh -g -f -N -L 0.0.0.0:18888:localhost:18822 <user>@localhost
Command ssh (the client) to open port
18888 available as an external (
0.0.0.0) port on (
vps) that connects to internal port 18822.
That opens an internet visible port
vps:18888 that redirects traffic to
18822 which, in turn, redirects to
While at a A console (and the only connection in which A participate):
Connect from Client A directly to Client B at
What matters is this last connection.
The whole SSH security depends on the authentication of A to B.
What it means
The SSH protocol
SSH provides a secure channel over an unsecured network
By using end-to-end encryption
End-to-end encryption (E2EE) is a system of communication where only the communicating users can read the messages. In principle, it prevents potential eavesdroppers – including telecom providers, Internet providers, and even the provider of the communication service – from being able to access the cryptographic keys needed to decrypt the conversation.
End to end encryption is a concept. SSH is a protocol. SSH implements end to end encryption. So can https, or any other number of protocols with encryption.
If the protocol is strong,and the implementation is correct, the only parties that know the encrypting keys are the two authenticated (end) parties.
Not knowing the keys and not being able to break the security of the protocol, any other party is excluded from the contents of the communication.
If, as you describe: from Client A directly to Client B you are authenticating directly to system B, then, only Client A and client B have the keys. No other.
Case A: The VPS itself is not altered with, but traffic and files are monitored completely.
Only the fact that a communication (day, time, end IPs, etc.) is taking place and that some amount of traffic (kbytes, MBytes) could be monitored but not the actual contents of what was communicated.
Case B: The VPS is completely compromised, filesystem content can be altered.
It doesn't matter, even if the communication is re-routed through some other sites/places, the only two parties that know the keys are A and B. That is: If the authentication at the start of the communication was between A and B.
Optionally, check the validity of the IP to which A is connecting, then: use public key authentication (use only once a private-public key pair that only A and B know), done.
Understand that you must ensure that the public key used is carried securely to the system B. You can not trust the same channel to carry the keys and then carry the encryption. There are Man-in-the-middle attacks that could break the protocol.
If I now send a file from Client A to Client B over SFTP, would it be possible for the company hosting the VPS to "intercept" it and read the file's (unencrypted) content?
No, if the public keys were safely placed on both ends, there is a vanishingly small probability of that happening.
Walk with the disk with the public key to the other side to install it, never worry again.
From your comment:
So, basically the VPS in my setup does nothing but forward the ports, and is not involved in the actual SSH connection or authentication happening from Client A to B, correct?
Kind of. Yes the VPS should not be involved in the authentication. But it is "In-The-Middle", that is, it receives packets from one side and delivers them (if it is working correctly) to the other side. But there is an alternative, the VPS (or anything In-The-Middle) could choose to lie and perform a "Man-In-The-Middle-Attack". It could lie to Client-A pretending to be Client-B and lie to Client-B pretending to be Client-A. That would reveal everything inside the communication to the "Man-In-The-Middle". That is why I stress the word should above.
I should also say that:
...there are no tools implementing MITM against an SSH connection authenticated using public-key method...
Password-based authentication is not the public-key method.
If you authenticate with a password, you could be subject to a Man-In-The-Middle-Attack. There are several other alternatives but are out of scope for this post.
Basically, use ssh-keygen to generate a pair of keys (lets assume on side A), and (for correct security) carry the public part inside a disk to Side B and install it in the Authorized-keys file. Do not use the network to install the public key, that is: do not use the ssh-copy-id over the network unless you really do know exactly what you are doing and you are capable of verifying the side B identity. You need to be an expert to do this securely.
About the public key though, isn't it, well, public?
Yes, its public.
Well, yes, the entity that generated the public-private pair could publish the public part to anyone (everyone) and have lost no secrets. If anybody encrypts with its public key only it could decrypt any message with the matching (and secret) private key.
By the way, the SSH encryption is symmetric not asymmetric (public). The authentication is asymmetric (either DH (Diffie-Hellman) (for passwords) or RSA, DSA, Ed25519 Key strength or others (for public keys)), then a symmetric key is generated from that authentication and used as communication encryption key.
Used for authentication.
But to SSH, the public key (generated with ssh-keygen) carry an additional secret: It authenticates the owner of the public key.
If you receive a public key from the internet: How do you know to whom it belongs? Do you trust whatever that public key claims it is? You should not !!
That is why you should carry the public key file to the remote server (in a secure way) and install it there. After that, you could trust that (already verified) public key as a method to authenticate you to log-in to that server.
I've connected from the VPS, mostly for testing, to Client B before too, doesn't that exchange the public key already?
It exchange one set of public keys (a set of DH generated public keys) used for encryption. Not the authentication public key generated with ssh-keygen. The key used on that communication is erased and forgotten once the communication is closed.
Well, you also accepted (and used) a key to authenticate the IP of the remote server. To ensure that an IP is secure gets even more complex than simple(??) public-key authentication.
My impression was that the public key can be shared, but the private key or passphrase must be kept safe.
And your (general) impression is correct, but the devil is in the details ...
Who generated a key pair could publish his public key without any decrease of his security.
Who receives a public key must independently confirm that the public key belongs to whom he believes it belongs.
Otherwise, the receiver of a public key could be communicating with an evil partner.
Generate your key