API authentication design and hackability

2019-03-08 22:15发布

问题:

Question: Is this API authentication technique easily hackable?

apiKey = "123456789"
apiCallId = "1256341451"
apiSecret = "67d48e91ab2b7471d4be2a8c2e007d13"
sig = md5(apiKey + apiCallId + apiSecret) = 09c297a354219f173bfc49c2e203ce03

where

  • apiKey: some unique identifier for the user
  • apiCallId: a unique integer that must be increasing in value (e.g. UNIX time stamp)
  • apiSecret: string known only to the user, and us - not passed in URL
  • sig: "unhackable" signature of this API call - MD5 hash

Example API call:

http://api.domain.com/?apiKey=123456789&apiCallId=1256341451&sig=09c297a354219f173bfc49c2e203ce03&param1=x&param2=y

This API does not require a session, and is not designed for a 3rd party to use on behalf of a user. Instead, it is to be used by the user themselves.

I really like the simplicity of this. The requirement of apiCallId being unique, and always increasing means reusing a sig is not possible, so I feel like it is secure (protected against replay attacks), but I am not an expert.

Other APIs use all of the GET parameters sorted alphabetically when calculating the sig, but I do not see why this is necessary when including apiCallId.

Please try and hack this now before it is implemented and released.

I welcome any feedback, suggestions and security education.

回答1:

What you are doing seems reasonably sane, except for not checking the parameters (which is going to be a pretty big problem).

Something which is very similar to your design which it might be wise to copy is the Amazon Web Services Request Authentication Scheme

In particular make sure your encoding scheme for the parameters is unambiguous and invertible; Amazon screwed this up at one point. Learn from their mistakes. :)

Cryptographically speaking, what you are doing is not called a signature but rather a message authentication code (MAC). A MAC can be created and verified by anyone who shares the secret key (the term 'signature' is normally reserved for public key schemes like DSA or RSA). MD5(msg || K) is a known and reasonably sane MAC; I'm not sure if you missed it by accident or on purpose, but a method that seems on the surface to be equivalent, MD5(K || msg), is quite insecure, because a quirk in how MD5 (and most other hash functions) are designed means that if you know H(m) you can easily compute H(m || m2) for any m2 - so if you were using MD5(K || param1=5), someone could pull this off the wire and then create MD5(K || param1=5,param2=666). (It's perhaps a bit more technical than you're interested in, but this is called the length extension property).

However while MD5(K || msg) is probably 'fine', you are better off using something like HMAC, because it was actually designed as a MAC. MD5 has a lot of problems but nothing directly affecting its use as a MAC (yet - MD4 has been broken in this way). So for future-proofing (and audit-proofing) use HMAC with SHA-1 or SHA-256 instead. Even if you don't want to pull in a crypto library, HMAC is quite simple and there are known values available for SHA-1 and SHA-2 so you can check your code.



回答2:

No. The integrity of the other parameters (param1 and param2 in your example) is not protected. An attacker can intercept the call and alter these as he likes before forwarding it. The apiCallId only prevents replays, not alteration of the first call.

I'm no expert. If I saw that immediately, there are probably other problems lurking.



回答3:

Well suppose i knew the secret, then i could generate the sig and pass it. What were doing for one of my startups is taking the sig param even further by making the sig rely on the other parameters and also a requestID (UUID) and timestamp and store that UUID(security reasons for a couple of hours to deny the hacker of calling the same function over and over again). This way you cant call the same call again, you would have to generate a new UUID and if the hacker replaces the UUID in the param the sig invalidates, and he does not know how to generate the sig because, other than secret, we are also generating signature based on an internal key which is 30 characters in length. So essenity

MD5(Alphabetical List of Params + APiKEY + callID + Secert + someLonginternalKey)

not sure if i answered your question but thats another way of doing security for api



回答4:

I would suggest to use digital signatures in this case since they're more appropriate. A digital signature over for example the apikey is more than enough. You dont even need the apisecret and the hash of it. You'd only have to make sure that the digital signature stays private (just like the md5 hash).

If you want to prevent replay attack, you need some kind of randomness in every request. So I would suggest the following:

Server -> API: Nonce (= some random number)

API -> Server: Enc(nonce + digital signature)

this is encrypted with the public key of the server and the digital signature is placed with the private key of the server.

Now you cannot have a replay attack. However there is still the problem of a man in the middle attack, but fixing this is not so trivial (but quite doable). So depending on the level of security you want/need you can adapt your technical measures.