I have an app that uses an API server and I do not want to have anything other than it to be able to use that API. I know this isn't totally possible, but I want to do what I can.
I don't think my current method of achieving this is the greatest and I'd like to scrap it and start over fresh. Here's how it works:
- The app picks a string from a set that I'll call the "entropy".
- Using that string it makes a hash of the current UTC date using the entropy as the salt
- It sends that hash to the API server which then creates the hash using every possible entropy from the set until it finds a match
- If it finds a match, a API key is generated for the app and sent back.
The server stores the entropy string, the API key, as well as the IDFV in a database.
When the app makes a request, it sends their API key, the IDFV, and a bearer token. The bearer token is a hash of the URL with the entropy string as the salt.
When the server recieves a request it:
- Selects the entropy string from the database using the API Key and the IDFV as search parameters.
- Generate it's own bearer using the URL it's responding to, and the entryopy from the above select.
- Verify that the entropy strings match
If the select query returns nothing, or if the bearers don't match the server will return a 403 and not proceed.
The problems I'm worried about are:
- If the user has an incorrect date on their device the registration will fail. Likewise,
- If the server has an incorrect date the registration will fail
- If the app starts registration at 23:59:59 and there's a 1s delay time to the server (which over 3G is totally plausible), the registration will fail
- With a hard-coded list of entropy strings can the app be decompiled and the strings extracted
- With only a limited number of entropy strings it's possible to find all of them with enough time.
Some of the things I have took into consideration:
- All requests and responses are served over HTTPS
- The API server rate-limits requests to hamper brute force attempts
- The API server is behind CloudFlare to also do some basic attack prevention.
What I want to know is what would be a better way of going about this that doesn't require any extra user interaction? The iOS app is built using Objective-C and the API server is built using Ruby.