tags:

views:

92

answers:

5

Hi - I have in my website a PHP page which retrieves data from my database to be presented in my website. This page is called via AJAX. How can I restrict the access to it only from pages within my website so users who wants to abuse it and get this data not from the website (e.g. posting HTTP request from their server) itself won't be able to do so ?

A: 

There are a variety of options depending on what your underlying need is, whether its a service you will be letting others access, vs something internal only. Here is an article with some good in-depth explanation of the options.

http://java.sun.com/developer/technicalArticles/J2EE/usingapikeys/

fafnirbcrow
+2  A: 

This can not really be done if stated as above, you would need to redesign and implement some kind of authentication scheme, but even that can be emulated. The short answer is that if a web browser can access it then anything can access it as long as it pretends to be a browser.

There are things you could do to make it harder for someone, like verifying HTTP header fields such as Referer and User-Agent, and implementing session verification in the AJAX calls.

kb
regarding the REFERER i cannot use it since i will be risking in filtering out valid clients who just won't send this referer. How can i accomplish it using a session ?
Yossi
@kb how are you purposing that you make a cross-domain ajax request? XHR does not allow this (http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest). Further more the referer and user-agent are trivial to spoof using CURL.
Rook
@The Rook: You misread both my points. What you're remarking on is exactly what I'm pointing out in my answer. All it does it makes it more inconvenient/harder for the attacker, but there is no way to stop it. (Also; no the ajax calls can not be made cross-domain, _but_ repeated requests can be used to scrape the site.)But still, the main thing to focus on is: There is no way to do what's asked for above. If a browser has access anything can get access.
kb
@Yossi: It's really not a solution since you would need to intialize the session for regular visitors in some way and that can be equally used by any crawler/third party service collecting data from your site.
kb
@kb security is about stopping attacks. Security systems that are trivial to bypass (such as checking an attacker controlled variable) are a complete and absolute waste of time. In a sense you are purposing a secuirty system where you have a get variable `?is_hacker=True`.
Rook
@The Rook: wow, you really fail at this whole reading/comprehension thing. there is no security in this. none. zero. zilch. nada. null. as was stated in my answer and in the subsequent comments. i don't even understand how you fail to grasp it from the first paragraph of my answer. this is not the windmill you're looking for.
kb
@kb you are not hardening anything all your doing is wasting time.
Rook
@kb,@The Rook: Suppose I don't use AJAX to pull out this data for my website due to a high abuse risk, is there any other solution to accomplish this goal without being exposed to abusers/attackers ?
Yossi
A: 

Alas, that's not possible. Anything Javascript can do, an 'abuser' can also do from his server. You can make it more difficult by obfuscating the javascript and protocol, making it harder to sniff. There are various free and non-free javascript obfuscators (also knows as "minimization") available. Obfuscating the protocol you can do by implementing a simple encryption scheme (making it more advanced won't help, as the key must always be embedded in your code anyway) for the data sent and received.

wump
There must be a way. I saw something in Yahoo! finance but i didn't understand what did they do there ...Basically you tell me that no matter what i'll do i always exposed to abusers ??
Yossi
There are many people downloading data from Yahoo! finance using non-browser clients, you must be wrong there.
wump
+1  A: 

JavaScript running on another site will be unable to access your site because of the Same-Origin Policy for XHR. But nothing is stopping someone from building a PHP+CURL script to "proxy" the data from your ajax backed to make it appear as though it was running on their server. Trying to blacklist clients is messy, ip address are cheap and free http proxies are plentiful.

In short there is nothing special about your javascript. A client can do whatever he wants, and you can't force him to behave, this is the basis of "client site trust". A hacker can use something like tamperdata or even firebug to identify HTTP requests and he will be able to replay them or forge them with CURL.

You could try obfuscating your javascript. But at the end of the day an attacker is just going to replay the http request, and there is absolutely thing you can do about it.

Rook
A: 

This is what I do,

  1. On your website, create a secret string. I use the HMAC($_SERVER['REMOTE_ADDR'], key).
  2. Write the secret in a Javascript var.
  3. On the AJAX call, pass this string as a parameter.
  4. On the AJAX server, do the hash again. If it's matches the parameter, the call is from your page.

EDIT: Code examples,

In your website, you do this,

$key = 'supersecretkey'; // This is your security, don't expose this
$nonce = rand();
$timestamp = time();
$signature = hash_hmac('sha1', $_SERVER['REMOTE_ADDR'] . $nonce . $timestamp, $key);

Print out the vars to the page,

<script type="text/javascript">
<?php
echo "  var signature = '" . $signature . "';\n";
echo "  var nonce = '" . $nonce . "';\n";   
echo "  var timestamp = '" . $timestamp . "';\n";
?>
</script>

When you make AJAX call, pass the 3 parameters to the server,

  http://example.com?signature=...&amp;nonce=...&amp;timestamp=...

On the AJAX server, do the calculation again,

$key = 'supersecretkey'; // This is your security, don't expose this
$nonce = $_REQUEST['nonce'];
$timestamp = $_REQUEST['timestamp'];
$signature = hash_hmac('sha1', $_SERVER['REMOTE_ADDR'] . $nonce . $timestamp, $key);

if ($signature == $_REQUEST['signature'])
   // the call if from my page.

You can also chech timestamp for currency and nonce for replay (need session or data store).

ZZ Coder
but what happens if the user copies the string and post it to my server via his server :)
Yossi
He has different IP so the hash doesn't match. But he can certainly call your website once and use that string. My implementation is actually more complicated to prevent that. I also create a timestamp and a nonce. So the AJAX call only works once in a limited time-window.
ZZ Coder
Could you please give an example and do you managed to prevent abusing your services ?
Yossi
hamcs are used to prevent a user from modifying a message, in this case the "message" is $_SERVER['REMOTE_ADDR'] which is pulled directly from Apache's TCP socket and cannot be spoofed. In short this security system performs no useful action.
Rook
@Yossi, post some of my code. Hope that explains it more clearly.
ZZ Coder
@ZZ Coder this code baffling, I have no idea what you are trying to prevent. What is stopping someone access this via curl?
Rook
Nothing will stop someone accessing your website using curl. It's just a form of user-agent if implemented properly. That's not the point. This scheme will prevent people accessing our AJAX calls without going through our front door, which we already have protections (rate-limiting plus CAPTHCA). We have been using this scheme for over a year and it's very effective.
ZZ Coder