1

Background

I'm setting up an API which will be used primarily over HTTPS (only calls not needing any security what so ever is available over HTTP). Some aspects of it need to be accessed only by authenticated users. To allow this without using passwords each user possesses one or more RSA keypairs. The public key is kept on the API server.

When the user want to be authenticated they sign the current timestamp with their private key and send it, the timestamp and an ID to what keypair was used over to the server.

The server verifies that the message (the timestamp) was signed by a user with the corresponding key.

The server verifies that the timestamp has not surpassed a certain amount of time and returns a JWT token signed with the server's private key which will be used later to authenticate the user.

Concerns

The timestamp (which acts as a nounce(?) and a way to restrict access according to time) should not be sent along with the authentication request to the server, since knowing what message was signed the key could be reverse engineered.

An uncautious user could misplace a signed key which would practically be just as bad as losing a password if not worse.

Question

Is it wrong supplying what "nonce" that was signed along with the request or should the server already "know" (via some previous exchange)?

Does using the timestamp as a message when creating the signature defeat rogue digests? I.e. is it enough to make the digest unusable after the expired time - since the message can't be altered without not passing a verification?

  • You say "primarily over HTTPS". Does that mean that there will be actions taken by an authenticated user over non-HTTPS connections? – Neil Smithline Jan 18 '16 at 17:06
  • 1
    Why aren't you just using passwords? – Neil Smithline Jan 18 '16 at 17:07
  • @NeilSmithline The scope of this question only affects the bit over HTTPS but there are calls allowed over HTTP which don't need any security what so ever. I've updated the question to clarify that. – Alex Jan 18 '16 at 17:33
  • Why aren't you just using passwords Alex? That workflow is well understood and supported. – Neil Smithline Jan 19 '16 at 22:19
1

It is unclear to me exactly why you are implementing such a complex authentication mechanism. Homegrown authentication solutions are notoriously difficult to get correct. So my first thoughts are to try and steer you to more standard mechanisms.

In summary, my recommendation is to use username/password for authentication. If you have a good reason not to do that, use SSL mutual authentication. And if you have a really good reason for not doing that, use your suggested method with changing the time stamp to a server-side generated nonce.

Details follow...

Option 1: Simply use username/password for authentication. You don't mention why you're not choosing this more common route. Perhaps you are hoping for a higher degree of security?

Option 2: Use TLS/SSL mutual authentication. This is a tried and true standard supported by nearly every web browser and TLS library. In mutual auth, the client has a private key and an X.509 cert, similar to the server. When the SSL connection is initiated, it uses not just the server's cert, but the client's as well. Both sides of the communication can confirm the party they are communicating with. Unlike the server's cert, the client's cert doesn't need to be signed by a certificate authority. This means it could be a self-signed cert or created by your own certificate authority. All that matters is that the server can validate that it is the right cert for a specific user. My preference is to simply store the cert (really the cert's fingerprint) in the user database. This allows for easy revoking as it just means deleting the revoked cert from the DB.

Based on the limited understanding I have of your project, I see no advantage to your proposed solution over mutual auth SSL. You are recreating parts of the mutual auth protocol instead of just using an established solution.

Option 3: Your homegrown solution. I see no problem passing the nonce in the same message as the signature. As this is done over SSL, only the client and the server could see this information. So it doesn't matter if the server gets the nonce in the message or "knows" the nonce from an earlier part of the conversation. Either way, the server has both the nonce and its signature and nobody else should have access to this information.

As far as defeating a replay attack (what I assume you mean by "rogue digests"), I'm not thrilled about using a client-side generated nonce. I think it is more secure to have the server pass the nonce to the client and then let the client sign that data. This requires an extra round of communication, but as we're discussing long-lived conversations in this scenario, I think this should be OK. Once you move to using a server-side chosen nonce, you can just use a cryptographically secure random number as the nonce and store this nonce on the server. The server can then handle the lifespan of the nonce. Also, I'm not a big fan of using time stamps that span computers as, even in 2016, clock synchronization between server and client can be a hassle.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.