FIRST, THE SCENARIO
We have an internal system that is effectively split into 2 very separate parts across 2 sub-domains, our back-end administrative system for internal access only we will call this admin.example.com and our public-facing interface for customers via our website - lets call this www.example.com/customers
We have built a series of APIs with PHP in the back-end system for the public interface to access, the APIs are split into multiple files based around the type of activity that is being performed and are also used in the admin interface, these are held in admin.example.com/apis/activity_api.php we have no problems here.
We also have API keys that are in-use, 1 for the front-end and one for the back-end so we can determine access levels without thinking about it.
SECOND, THE ISSUE
Now you know the structure of the application here is the issue, we are using jQuery AJAX to call the APIs but I don't like placing the API keys here as they are publicly visible and anyone with a little programming knowledge will be able to pull a huge range of data, at the same time we need to use them.
Note that the issue is only in the public interface.
What I am thinking of doing is calling a connecting script in PHP with AJAX that is stored locally on our public facing server, this would do a few things
- Check the referrer, if it comes from example.com/customers/ or www.example.com/customers/ it continues, if not the request is killed with an unauthorized error
- Gets the variables posted by the AJAX requests
- Restructures the variables for the API (e.g. receives
$_GET['request']
then reconstructs as$_GET['req']
) - Adds the API key that is held as a variable within the PHP to the string
- Uses
file_get_contents()
to make the actual request to the API, this would in turn populate the connecting PHP script with the required returned API data to the site
My questions are
- Have I missed anything in this concept?
- Are there any flaws that haven't been thought about?
- Are there any compelling reasons why this type of structure should not be used?
I appreciate the input!
WHAT I HAVE DONE
I really want to thank you guys for your help and comments on this, you have pointed out what I missed and that was the purpose of posting the question in the first place. You also helped me spot the obvious weaknesses.
I have just written an algorithm that has taken into account HMAC principles. As with anything in this space there is room for unauthorized access but I believe my algorithm minimizes it.
The basic process we're going with is as follows
- 2 keys have been created, a private and public key
- The public key is hashed first
- A base calculation is carried out on part of the current time stamp
- 2 random keys for the get request are generated that will be used to transport the access keys, to determine the request keys a mathematical calculation is carried out on the base calculation in step 3, the result is then split into 2 parts, the 2 parts are verified as unique and converted to the final values, 1 part belongs to the public access key and the other to the private access key key
- 9 unique public values, plus the private access key issued are then taken, they are re-ordered based on a final calculation on the base value in step 3 creating a "signature" so to speak
- The signature is then hashed and assigned to the private get key generated in step 4
On a quick calculation and basic testing, each request will be valid for approximately 27 seconds (give or take a few milliseconds) - enough time to process everything needed but not enough for much more. As the calculations are fairly basic the server load hasn't gone up an inch - I have only tested with 10 connections per second for 5 minutes however, I am going to run a series of load tests on it over the next 24-hours that will range from 20 request per second to 400 requests per second and compare with load test results taken last week.
So what my new algorithm does in a nutshell is disguises the public and private keys by hashing both - however after time the public access key will be obvious unless I assign an algorithm to randomize it, it assigns both access keys random get request keys and has a short validity time based on the request. It doesn't need to store any data in cookies or sessions. In addition, with exception to the login API, all requests are going via a PHP connector that requires the user to be logged in.
I spent more time explaining what I'm doing than actually creating it!
Thanks again for your help guys, it helped me open my eyes a bit more and reminded me about what I had forgotten.