5

I have a web application, say http://web.app/. It is local for every given user and accessible without authorisation. It uses an API of a service https://service.app/. The user can log in to it and see his API key. The user just copy-pastes it from the service to the app and there is an intention to make it a little easier.

The first idea is to use OAuth, but it is slightly overcomplicated. I just need to pass a key and I don't need to be sure it is correct. If a user passes a wrong key the services just will not work.

The second idea is to pass it via post request. Web.app has alink to https://service.app/getapikey/ with a button 'Pass the key', it makes post request to http://web.app/saveapikey/, so web-app gets the key.

Is it a good practice not to use OAuth for such a purpose? Is there something better?

kaidentity
  • 2,634
  • 13
  • 30

2 Answers2

3

You need to consider several factors here. I hope your API key do have an expiration time ? Even if it do so, it is vulnerable to a replay attack if an adversary get hold into your HTTPS request. As a remedy, you can introduce a Time stamp or counter to your request.

Counter Replay attacks

A timestamp can be added to the message and encrypted along with the rest of the message content. The service can retrieve the timestamp after decrypting the message and fail the request if the timestamp is too old for the threshold that is already agreed on. This cuts down on the window of opportunity to replay a request. Downside to this approach is both server and client need be be in sync with time.

An alternative to a timestamp is a counter . With a counter, you don’t need to be concerned about the skew between the clocks. However, clients must implement a counter to ensure the count sent in a request is greater than the count in the previous request at least by one, and the server must keep a record of the last received counter. Of course, the message has to be signed so that a malicious user does not increment the counter and replay the rest of the request.

Hash-Based Message Authentication Code to Counter MITM Attack

The primary mechanism to ensure data integrity of messages is a Hash-Based Message Authentication Code (HMAC). HMAC is just a piece of data created through a cryptographic hashing algorithm and a shared secret key. However, if the message needs to be encrypted for confidentiality, you can easily add that functionality using the same private key we use for HMAC or you can introduce a new key specifically for encryption. When a user sends a request, you need to concern on following three important parameters.

  1. The public key, which is the key associated with the user
  2. The counter
  3. The Timestamp

In addition to the parameters, the request includes a signature that ensures that none of the parameters are tampered with. It is possible to create the signature based not only on the three parameters but also on the entire body of the request if the objective is to make sure nothing in the request gets modified. To make sure no one tampers with the parameters, we can include an HMAC-SHA256 of all three values plus the request URI and HTTP method.

You can introduce following 4 attributes to your header.

X-KEY

This is your API Key

X-Signature

If the value sent by the client application in the X-Signature matches the HMAC-SHA256 of the values of X-KEY, X-Counter, X-Stamp, request URI, and the HTTP method, we can safely conclude that nothing was altered in transit.

X-Stamp

The value sent by the client and the UNIX time of the current time are compared. If the skew between these two are within the allowable tolerance limit, the request is not a replay. UNIX time is the number of seconds elapsed since midnight of January 1, 1970 Coordinated Universal Time (UTC).

X-Counter

If the value sent by the client is greater than the last received counter in the record kept by the server, the request is not a replay. Although I use both the timestamp and counter in the implementation example in this chapter, one typically is good enough, depending on your needs. If clock times are reasonably in sync, a timestamp is the best approach because there is no overhead in terms of storing the counter in the web API side or incrementing it in the client side.

conclusion

It is better to use already battle tested framework such as OAuth to cater your need. But if you think it is too complex, you need to consider the things that are being explained in this answer.

user3496510
  • 1,257
  • 2
  • 12
  • 26
  • Do you keep in mind that client and web.app is in the same local network? How can I pass API key from service.app to web.app with X-Key header? It is just a web application in client's browser. – shukshin.ivan Jan 27 '17 at 00:34
  • What is the technology you use to implement your solution (.Net, PHP , JSP...) ? – user3496510 Jan 27 '17 at 00:47
  • I use PHP for my web.app – shukshin.ivan Jan 27 '17 at 10:11
  • It is still not clear who passes an api key from a service to a local app. Is it a user's browser with an ajax request? Please keep in mind the second idea in question - it seems that I have to improve it if I skip OAuth approach. – shukshin.ivan Jan 31 '17 at 01:29
  • @Ivan : What you need to is, do a POST after the authentication is successful to your 2nd application. You can pass-in the Key using the POST request body. I hope both apps are living in the same box? If not you need to secure the POST request from your Auth app to APP you using the Key. – user3496510 Jan 31 '17 at 02:11
  • No, service app is at Amazon aws, web.app is at his own home controller (usually RaspberryPi). Local app is accessed via `http://192.168.X.X`, so my idea is to use local `post` request to pass a key to my `web.app`. Then web.app uses it to access amazon-located service via `https`. I didn't catch how do you suppose to pass a key, which application does that and what technology with (ajax, curl etc.). – shukshin.ivan Jan 31 '17 at 13:52
  • 1
    @Ivan: Now things are getting cleared. This is what you should do. You need to maintain a Key store(Something like PHP Keystore) in your IoT device. Place your API Key in that Key store and secure it. Read the key from your web.app hosted in your IoT Device when ever required and then you can pass that Key in to your AWS Web app. Normally IoT devices are vulnerable securing keys(eg: if someone remove your SD card and plug into their own IoT device). If this is a concern to you, you an use hardware+software Key securing mechanism such as Zymbit. – user3496510 Feb 01 '17 at 02:14
  • Following are the useful links for further reading (Ref: my comment above). https://phpkeystore.org/ https://github.com/kumatch/php-keystore https://zymbit.com/securing-your-iot-devices-2/ – user3496510 Feb 01 '17 at 02:14
0

You can encrypt the key, then use base64_encode on it, and post it. Or you can send it through curl.

The key can be encrypted or decrypted through more then one way and it is always easier to handel an encrypted key/pass with base 64 encoding to save it or transport it.


If it's a local network and you need to use it from station to station then curl is a good idea by making those stations static (LOCAL) IPs.

Otherwise if you use it on one machine then use php session to transfer the Key