JR_
JR_

Reputation: 31

API Authentication Method - am I doing it correctly?

I'm incredibly new to building API authentication - so wanted to ensure I'm going about this the correct way as there could be major security flaws that I'm not aware of.

It's based on a secret/private key pair, where both the client and the server know the secret key, but it's obviously never passed along the wire.

Any feedback, insights or holes in this method would be greatly appreciated.


Step 1:


The client wants to make a request to the API, so asks for a nonce from the server - passing their public key.



Step 2:


The server lookups the users private key (using the provided public key) and hashes it (sha256) with a random 32 character string (the nonce).

The hashed nonce and public key are then stored to a local array.

The server then responds to the client with the un-hashed version of the nonce.



Step 3:


The client takes the nonce from the response and also hashes it with it's private key (which the client has locally).

It then makes a request to the server (along with the API task it wants to perform) and sends its version of the hashed nonce and public key.



Step 4:


The server takes the clients public key and hashed nonce, then checks the local array to see if the public key/nonce pair exist.

If the pair exist; authentication is passed, the request is allowed and the public key/nonce pair is removed from the local array.

Upvotes: 1

Views: 182

Answers (1)

awendt
awendt

Reputation: 13633

Let me start by saying I don't have any credentials in the security world. Please take everything I say with a grain of salt.

A couple of general thoughts

It seems like you want to roll your own which is a bad idea in any security-related area. Even more so when there are several alternatives in the wild that have been battle-tested.

Off the top of my head, I can name three ways for API authentication that are in wide use:

  1. Basic authentication. Github provides this as a fall-back: “intended to be used for scripts or testing (i.e., cases where full OAuth would be overkill).”

  2. OAuth. Github, Twitter, Facebook, LinkedIn, Google all use this. This protocol is well-specified but might be overkill for smaller projects. Thanks to widespread client library, it's fairly easy to implement.

  3. Hash-based message authentication code (HMAC). All Amazon Webservices use this. This might be the most under-appreciated solution since it's conceptually easier than OAuth: The client uses its private key to sign requests and send the signature + public key in the request. The server looks up the private key using the public key sent by the client and in turn creates a signature of the request. If the signatures match, the request is valid. Public and private keys have to be exchanged beforehand (AWS lets you download the private key once).

From what you describe, HMAC is the closest candidate to what you want.

A couple of thoughts specific to what you suggested

  1. Your algorithm requires you to keep state on the server (cue “local array”). This is fine for a single server, but what do you do when you scale? When step #2 hits one server and step #3 another, the state has to be shared. You can of course use a shared DB (or cache) or whatever, but you have to think about this.

  2. Roundtrips. Requiring a 2-step authentication like you suggested, every client has to either send an additional request (to get the nonce) for each (payload) request or you have think about when to invalidate your pairs on the server. HMAC essentially does the same thing without request overhead.

  3. Possible attack: I can flood your servers with client requests for nonces. Depending on your public key length, I might come up with valid public keys and I can tie up resources that are never used for the second request. Depending on how you handle that (see also point #1), I might bring your server down.

Upvotes: 1

Related Questions