Ayrton Senna Ayrton Senna - 1 year ago 114
Javascript Question

Node.js: Authenticate client using unique public key (Similar to Github SSH key authentication)

I have a central web-server (Node.js) and also have several client machines (also running Node). These clients are going to be pushing data into the web-server and so, for security, the clients will initially register with the main server - generate it's own unique SSL private/public keys and store the public key on the server.

Now, after the registration, every time a client tries to communicate with the server, it needs to present it's Public key(?) to authenticate itself.

I am trying to understand how to go about this. Should I store the contents of all the public keys of the clients in a regular database collection?

How do I actually make the clients "present" their certificates along with their data? I've seen a few packages like client-certificate-auth but I don't think this will help me for my use-case.

EDIT: I forgot to mention, I will be communicating over HTTPS (port 443) so I think that takes care of the actual security part. I just want to make sure that no rogue, unregistered client pushes data into the server using pub/private encryption / SSL certs.

Answer Source

If you're going down this path, use the Subtle Crypto API. Most likely, you shouldn't be doing this.

You want the private keys generated in javascript kept secret at the clients, and a public key sent and stored securely on the server.

During authentication, the client says what it's public key is by some unique identifier associated with it's public key, e.g. id or common name or user name.

The server then issues a challenge with a message payload encrypted with the client's public key.

The user decrypts the message with his private key, and then responds with the correct decrypted response.

This provides no security, you will have to perform this over an already established SSL connection.

It is an alternative to the traditional cookie and session token, and it's just different, harder, and not better.

The private key never arrives at the server at any time. The client does not encrypt using it's private key, that's not how public-key cryptography works.

It can however send a digital signature, and the server can verify that. That is an alternative to a unique identifier; make sure you specify a true and sufficiently long nonce to sign though.

To perform a digital signature challenge, the server sends a challenge string to the client, the client signs the challenge using it's private key and responds to the server, the server then verifies the signature using the public key. The public key must be part of the signature, and the server will have to know to trust the public key, so it'll have to have a way to look it up quickly.

Another alternative is to rely on the knowledge of the user in setting up their own client certificates, in which case passport-client-cert as mentioned in Paul's answer can handle that.