1

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

  1. 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
  2. Gets the variables posted by the AJAX requests
  3. Restructures the variables for the API (e.g. receives $_GET['request'] then reconstructs as $_GET['req'])
  4. Adds the API key that is held as a variable within the PHP to the string
  5. 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

  1. Have I missed anything in this concept?
  2. Are there any flaws that haven't been thought about?
  3. 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

  1. 2 keys have been created, a private and public key
  2. The public key is hashed first
  3. A base calculation is carried out on part of the current time stamp
  4. 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
  5. 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
  6. 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.

4
  • 3
    A referrer header can be set to anything by a programmer so it provides no real security.
    – jfriend00
    Commented Mar 7, 2012 at 17:33
  • Any suggestions @jfriend00?
    – Ryan
    Commented Mar 7, 2012 at 17:45
  • It is not clear to me what your objective is. You have a public API. What usage restrictions are you trying to enforce on the public API?
    – jfriend00
    Commented Mar 7, 2012 at 17:54
  • As @Karl Bielefeldt said below, I have a public API that I don't want to be usable to the public, it is only to be accessed by our front end site. We may put restrictions in place and make it available to our repair center partners in the future but for now it's just for us. I basically need it to communicate cross domain as if it was with another company all together with a reasonable degree of security.
    – Ryan
    Commented Mar 7, 2012 at 18:10

3 Answers 3

1

If I understand you correctly, you have a public API that you don't want to be usable by the public? Referrer headers can be spoofed. The best you're going to be able to do is issue temporary keys when the page is created that expire after a certain amount of time. Even then, all they'd have to do is refresh the page to get a new key.

1
  • Yep, you understood correctly... it's a thought... for this to work however I will need to come up with a key generation script that can generate the same key at 2 slightly different times by 2 separate and un-linked systems. I will think about that thanks mate.
    – Ryan
    Commented Mar 7, 2012 at 18:12
1

Karl is correct, though you can do a bit more around the edges:

You can have both parts of the application tie the temporary key to a user with limited rights and always verify those rights. Never trust the client of an API not to cheat. You must think of both sets of APIs as public if there is any way for the public to get to them.

If you feel the need to say:

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.

then I think you've answered your third question already.

5
  • Thanks for the feedback @psr, with your comment on the 3rd question, I was referring to hiding the API key within PHP and putting some verification in-place to protect its use is what I'm asking about in question 3, not the jQuery AJAX implementation of the key where it can be publicly seen in the page source. Unless you're saying an API shouldn't be used at all?
    – Ryan
    Commented Mar 7, 2012 at 18:17
  • @Ryan, unless all your users are authenticated, there's no added benefit to hiding a key in the PHP. Commented Mar 7, 2012 at 18:56
  • @KarlBielefeldt as a matter of fact I was just thinking about the log-in aspect and started updating my question when I was distracted. First, could you please explain how there is no benefit to hiding the key in PHP unless the user is logged in? Secondly, we only 1 API will be accessible before users authenticate, ironically it is the login API that only compares hashed login credentials and only returns another hashed code that means either "ok to login" or "kill login"
    – Ryan
    Commented Mar 7, 2012 at 19:43
  • @Ryan, because then the key can be tied to a session. You may as well have no key if you just forward unauthenticated requests. Commented Mar 7, 2012 at 20:00
  • @KarlBielefeldt I wouldn't actually assign the key to any session or a variable, I would just statically write it in the URL that will be constructed, e.g. admin.example.com/apis/this_api.php?key=XYZabc123098&req=$_GET['request']&i=$_GET['hashedid'] - I think you get the idea... but I just realized the real answer to my question I just asked, when the request is made it will be visible in the network traffic headers via the browser
    – Ryan
    Commented Mar 7, 2012 at 20:07
0

This is straight off the top of my head, but....

On the admin side, make a key generator that produces a guid and stores it, along with an expiration timestamp.

Make it so only your PHP from the web server side can access it. Since the PHP doesn't come to the browser, it's not super horrible to hard-code access creds for that.

The web server hits the admin, gets a new key, and statically embeds that in the javascript coming to the page.

The javascript then uses that key to authorize in its time window for requests. You need a way to notice when it's timed out and poke the server to create a new request.

At the very least, your window of opportunity for automated suckage is closed. This may not be much better than security through obfuscation, though.

1
  • Thanks for the idea... I will look at it closer tomorrow but sounds like an interesting idea at face value... cheers
    – Ryan
    Commented Mar 8, 2012 at 2:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.