Skip to content

Instantly share code, notes, and snippets.

@pgte
Last active December 31, 2015 14:49
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pgte/8002426 to your computer and use it in GitHub Desktop.
Save pgte/8002426 to your computer and use it in GitHub Desktop.

I built this service rendered over HTTPS.

We're using the Hawk protocol to authenticate message producers, but since the service will use HTTPS, Hawk is an overkill in my opinion.

Some of the drawbacks of using Hawk in my opinion:

  1. Signs whole message: overkill when you're using TLS
  2. Tries to be stateless on the server-side and implements a sort of message non-repeatability by including a timestamp inside the message. The timestamp has to be equal to the server-side time take or give 1 minute. This imposes time synchronizatin between client and server, which is hard to enforce.

Goals:

  1. To authenticate the producer of the message. (message is an HTTP request to the API).
  2. Do not compromise the user identity if a message gets leaked.
  3. Try to use a standard so that client-side libraries in different languages can be used.

Here are some solutions to provide the main goal:

1. Send username and password on every message

Cons:

The user password can be easily leaked like this: the password can be leaked into a log file or a notification service, forever compromising the password and the user identification.

2. Send an API key

Generate an API key for each user. User appends the API key to every message.

Cons:

The key is a shared secret that is sent over the wire. In this case, the key acts as a password. If key is leaked somehow, the user identification is compromised forever.

3. Use a secret key and signed nonce

The user has a secret key, which he uses to sign a nonce value (a nonce is a unique value that is generated once for each message). The message contains the user ID, the nonce and the signed nonce.

The server then extracts the private key from the user id which he uses to sign the nonce and compares it with the signed version of the nonce contained in the message. If both match, user is authenticated.

Pros:

  1. The message does not leak the key.
  2. Bonus: If the server stores the nonces and checks to see if the nonce has been used before, the message is not repeatable. Even if the message is somehow leaked (in log files or into a notification service), that message is not reusable.

Cons:

  1. Does not authenticate the whole message. But since we're using TLS, TLS certifies message integrity.

4. Secret key signing whole message

Signing occurs in the whole message, which is what Hawk does, but is an overkill when using TLS.

Discussion

  1. Am I overlooking an important aspect?
  2. Given that we're using TLS, I think that the best solution here is nr. 3 or a variation on it. If you agree, then the question comes: what standards exist for implementing this?
@bpedro
Copy link

bpedro commented Dec 17, 2013

Here are my comments:

  1. cons of 1 and 2 also apply to 3.
  2. only the client can leak the key, not the transport layer since it's using TLS.
  3. your solution 2 reminds me a lot of OAuth2 Client Credentials Grant which is also used by twitter under the name of Application-only authentication.

So, I'd use OAuth2 Client Credentials Grant over TLS:

  • it authenticates the producer of the message (the consumer, in OAuth lingo);
  • it doesn't compromise the identity of the the consumer if a message is leaked (unless the message itself contains information about the consumer);
  • it uses a well known and documented standard.

You'll need to generate (and maintain) consumer keys and secrets but you'll be using a widely known standard that's well documented and easy to implement on the client side.

You might want to pay special attention when generating consumer keys to make sure that you can verify them without making a trip to your database. This is important to prevent your backend from dying when faced with brute force calls to the token endpoint. I recommend using a simple check digit algorithm, e.g., the Luhn algorithm.

The message itself is left untouched and you can user whatever method you wish to encrypt it, sign it or make sure that it's not repeatable. But that's not part of your list of goals, is it?

@janl
Copy link

janl commented Dec 17, 2013

Look into how OTR does things. it is roughly 3-shaped, but thought through by experts.

@janl
Copy link

janl commented Dec 17, 2013

now that I wrote that, I realise it does rely on PK/exchange, but maybe it works for your case. It’s worth a read either way :)

@pgte
Copy link
Author

pgte commented Dec 17, 2013

@janl yes, looking for standard proven ways to do this, thanks!
By OTR you mean http://en.wikipedia.org/wiki/Off-the-Record_Messaging ?

@pgte
Copy link
Author

pgte commented Dec 17, 2013

@bpedro thanks!

Here are some questions and clarifications:

  1. If 3 does not include the key in the message, how does it also have the cons of 1 and 2 in case the message leaking?
  2. The message can be leaked innadvertedly by in a server log or in a message sent by the server to a third party. Acknowledging that this may happen I'm trying to minimize the impact in 3.

Going to look into OAuth2 Client Credentials Grant, thanks for the tip!

@andrezero
Copy link

Hi

Regarding the original post, signing, nonces and timestamps, OMHO, do make it more difficult to have replay attacks or other MITM situations. It is added security a the cost of extra complexity for both client and server.

Regarding Q1 I guess what @bpedro is saying is that message contains all you need to authenticate. So it's the same as 1) or 2) in original post.

Regarding Q2, same same. You don't minimise the impact by minimising the amount of fields required to authenticate.

For that exact purpose I like passing authentication details (a client id + a secret) in headers. It's much more improbable that some caching, logging, proxying or debugging layer - even some temporary devops intervention - of in your system ends up storing the header insecurely.

ex:

HTTP-X-API-KEY
HTTP-X-API-SECRET

The reason I prefer a pair key/secret or user/pass is that server does not have to store secret at all. And that's always good.

@pgte
Copy link
Author

pgte commented Dec 17, 2013

@andrezero thanks for the hindsights!

@soarez
Copy link

soarez commented Dec 17, 2013

my 2 cents:

With tls there is no benefit from using hawk.

I'd be inclined to used API keys which could be produced in a special endpoint that works with username and password (Basic Auth).

For increased security you can have API keys that expire after some time.

I like how the GH Api works: http://developer.github.com/v3/#authentication

It's always https, you can use:

  • basic auth - curl -u "username" https://api.github.com
  • api token sent in header - curl -H "Authorization: token BEARER-TOKEN" https://api.github.com
  • api token sent in qs - curl https://api.github.com/?access_token=BEARER-TOKEN

You can even use basic auth to generate tokens! - I know this link talks about OAuth but you can ignore that. OAuth is just a dance to exchange a private key (for signing) or a token (to be sent plainly like in this case).

@pgte
Copy link
Author

pgte commented Dec 17, 2013

@soarez, thanks for the response!

Yup, this is a nice scheme, but I'm afraid that leaking a message may compromise the user, but this scheme is definitely easier for the API consumer...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment