How to prevent cross-domain ajax requests?

13,286

Solution 1

There isn't any absolutely foolproof method to prevent this, since any header information can be spoofed. Session-based tokens are another possible solution, but in that case your javascript is publicly accessible, so anyone who wanted to spend a little time could determine how your token system works and figure out a way around it.

A combination of methods will give you the most wide-ranging protection. You can look for the header, use and .htaccess file, and use tokens. This sort of all-of-the-above approach makes it that much harder to abuse a web server - most abuse comes from people trying to find an easy hole to exploit. The important thing to remember is that you can't become complacent because you've deployed "the best" protection, or because you've got so many layers of protection that it seems impossible to crack. If someone really wanted it bad enough and had the time, they'll find a way. These types of preventative measures are really only deterrents to keep away the lazy, curious, and idly malicious. Targeted attacks are a whole separate class of security, and usually are more centered on server-level security issues.

Sample htaccess. This would not be something you'd put in your root, but rather within a subfolder where you have scripts that should never be called from the address bar:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?_YOUR_DOMAIN_NAME_HERE.com [NC]
RewriteRule \.(php)$ - [NC,F,L]

Check out this article for info about using a token system: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet

Solution 2

You can manually deny every request whose Origin header does not match your domain name. However, not all browsers send the Origin header. In these cases, you can fallback to the Referer[sic] header, parse it and find out the domain name, and compare it as above.

Some JavaScript frameworks also set an X-Requested-With header for AJAX requests.

This should reject a significant percentage of users (I'd estimate >95%). Note that due to the Same-Origin Policy, the only thing the guy sending AJAX requests to your domain gets is timing information anyway.

Share:
13,286
Sujit Agarwal
Author by

Sujit Agarwal

For the love of Code, I Code!

Updated on June 04, 2022

Comments

  • Sujit Agarwal
    Sujit Agarwal about 2 years

    How can I detect if my php script is being called from another domain and the other domain is making illegal use of my script? Is there a way to prevent this too?

    UPDATE

    I found this question on SO, but its still not safe, it can be spoofed.

    • Marc B
      Marc B about 13 years
      Using an access token is probably your best bet. Referers aren't reliable and easily forged.
    • Sujit Agarwal
      Sujit Agarwal about 13 years
      Oh, but i dont know how to implement a access token. Could you please show some light on it through an answer?
    • Marc B
      Marc B about 13 years
      Set a cookie of some sort of authorized users of the service. Check for this cookie on each invocation of the ajax handling script. Or embed the token in your script so its sent as a parameter on each AJAX call from your own legitimate code. Basically have SOMETHING sent along with the request to identify a legit user from one of the bandwidth thieves. If they get smart and copy the token, then only provide the token via a login mechanism or some other per-user identification system.
    • phihag
      phihag about 13 years
  • Sujit Agarwal
    Sujit Agarwal about 13 years
    Check the update. BTW, in your answer's case, if all browsers dont send the Origin header, then what else can be done?
  • Sujit Agarwal
    Sujit Agarwal about 13 years
    ` the only thing the guy sending AJAX requests to your domain gets is timing information anyway.` what do you mean by this?
  • phihag
    phihag about 13 years
    @Coding Freak Updated with a detailled explanation and X-Requested-With. However, I've no idea why someone would send random AJAX requests.
  • Sujit Agarwal
    Sujit Agarwal about 13 years
    Because recently i have been checking out in my logs that many XHR requests have been made from an outside server.
  • phihag
    phihag about 13 years
    @Coding Freak The Same-Origin Policy prevents you from getting the results of an AJAX call to another domain, unless you explicitly opt in to Cross-Origin Resource Sharing. Therefore, I can't imagine the motivation somebody would have to send AJAX queries to your site.
  • phihag
    phihag about 13 years
    @Coding Freak What do you mean with "made from an outside server"? XHR requests are usually made by the client. The Referer points to another site or what? Can you provide an example log entry?
  • Sujit Agarwal
    Sujit Agarwal about 13 years
    Sorry, a bit mistake, I didnt know, that my web server is enabled for Cross-Origin Resource sharing or not, but i have been observing a huge consumption of bandwidth on my server without that number of reasonable visits on my pages.
  • Chris Fremgen
    Chris Fremgen about 9 years
    The problem here is rand() is not really random. It's a time based pseudo-random number. While this is still a preferred method, it's by no means "foolproof".
  • user3491125
    user3491125 about 9 years
    but it has no impact since the string is stored on a session so only associated to this computer ;) thanks for informing anyway
  • aug
    aug over 8 years
    I think the answer on session spoofing helps with this in some ways but not sure if this is the ideal solution OP was looking for.
  • Chris Baker
    Chris Baker about 8 years
    This is also not foolproof because the token is exposed in the script. If I were targeting an attack on this, I could use curl to load the page, parse the token out, then send the malicious request using a good token. curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Requested-With: XMLHttpRequest")); defeats the other measure, and curl doesn't care about the Same Origin Policy. As I said, there isn't really a silver bullet here.