I'd like to restrict access to a PHP file on my server. This PHP file takes data from an HTTP GET request and appends it to a file. Simple. But I don't want this PHP file executed unless the HTTP request is generated from within the smartphone app I've developed.
I don't want to authenticate each user individually. I want my app, and only my app, to be able to send the request to the PHP file. I don't want people typing in a similarly formed request (http://www.mydomain.com/check.php?string=blahblahblah) into a browser and have the same impact.
I have thought about checking the HTTP_USER_AGENT, or some other variable, but I fear that they might be easy to spoof too. I could embed a key into my app that I look for, but that key could also be compromised.
The next step would be to have the server send me a challenge to which I respond appropriately. Or I could even look into PKI. But what's a relatively easy way to do this, given that I am not trying to protect anything of real value, just to prevent minor vandalism.
Am I trying to reinvent the wheel here? Is there already an easy, proven way to do this?
Define a salt in both your app and php file, then hash that salt combined with the current time. That's unlikely to ever get spoofed.
There's no guarantee method. You can use oauth authentication... Depending upon what platform your using and how your deploying app to the phone, maybe perhaps you can compile your key into the application itself? Anything can & will always be cracked, there is no 100% security... But no shame in trying. :)
Personally what I use for my mobile apps is RESTful authentication with regular login/pass pair the token based communication till it expires. :)
FWIW, here is the most secure method I can think of without seriously affecting performance - essentially the RESTful(ish) way, as to ramp it up any further would require multiple requests and connection state information stored on the server:
In order to break through this system and successfully spoof a request, an attacker would need to know the following:
Obviously if you are working with the mobile device 1 - 3 are easy to extract, but 4 and 5 cannot be found without reverse engineering the app (which there is literally nothing you can do to prevent, for people with the knowledge and the patience to do it).
A man-in-the-middle attack would be basically impossible - even after breaking through the SSL (which is non-trivial, to say the least) and reverse engineering the app to get 4 and 5, 1-3 cannot be retrieved without a brute force attack on the hash, which is sufficiently complex that this would take an average of several hundred million years (see this page to see how I arrived at that figure), especially if one of the three is of a variable length - which the app version string could easily be.
Just add authorisation (logins, passwords, sessions etc and/or "API keys") to your PHP application and then let your phone app to authorise first before sending the needed requests. You probably didn't consider that because if your script is simple that might add some clutter to it, but then again almost every web system needs that, and you will face that as well eventually.
Let you phone application to log into your PHP app via HTTPS to exclude interception.
HTTP requests can be built character by character in whatever way the sender wants. Spoofing will always be possible.
If you don't want anything per-user, but only per-app, you will have to rely on a secret built into the application. Anyone disassembling the application will eventually be able to find that, so some obfuscation might help, but it won't keep determined people off your page.
That said, there is little point in using any public key crypto. As the app-side is what spoofers might be interested in, they'd already have access to the more valuable half of a key pair. So you might as well use some approach using a shared secret.
What you really want to check is the authenticity of the transferred data. So simply take the core of that data (i.e. all fields which really matter), concatenate them with the shared secret, hash the result and transfer it as a message digest. The server performs the same calculation and checks that the computed digest matches the transferred one. If it does, the sender of that message must have known the shared secret.
There still is some chance for a replay attack, i.e. someone recording a valid message and repeating it later on. You can detect exact duplicates on the server side, and prevent delayed replay by including a timestamp in the signed part of the message. If your server allows for a huge difference between client and server timestamps, it will have to keep duplicate information for that same amount of time. If it only accepts small differences, it can work with a smaller duplicate cache, but users with malconfigured devices might be annoyed as the server is more likely to reject their requests as being too old.
One more note: you wrote about a
GET
request causing a write to some file. I would always associate some state-changing operation with aPOST
instead. If the app is your own, it doesn't matter that much, but browsers are known to retransmitGET
requests without asking the user, thereby causing duplicate requests for some action.