2

I asked a similar question before, and the answer was simply:

if JavaScript can do it, then any client can do it.

But I still want to find out a way do restrict AJAX calls to JavaScript.

The reason is :

I'm building a web application, when a user clicks on an image, tagged like this:

<img src='src.jpg' data-id='42'/>

JavaScript calls a PHP page like this:

$.ajax("action.php?action=click&id=42");

then action.php inserts rows in database.

But I'm afraid that some users can automate entries that "clicks" all the id's and such, by calling necessary url's, since they are visible in the source code.

How can I prevent such a thing, and make sure it works only on click, and not by calling the url from a browser tab?

p.s.

I think a possible solution would be using encryption, like generate a key on user visit, and call the action page with that key, or hash/md5sum/whatever of it. But I think it can be done without transforming it into a security problem. Am I right ? Moreover, I'm not sure this method is a solution, since I don't know anything about this kind of security, or it's implementation.

3
  • 2
    jQuery sends the X-Requested-With header with all it's AJAX requests (documentation here) however this isn't really a solution as the header can simply be spoofed Commented Aug 7, 2013 at 13:18
  • 2
    You could generate a key on user visit and require that key in the action. Of course, wouldn't a user just be able to script requesting the key over and over and use those keys to continue to invoke that action? What, exactly, are you trying to prevent? The "correct" place for the security shouldn't be in the page that invokes the action, it should be in the action itself. That action should internally validate, server-side, that the user invoking it is permitted to do so. Commented Aug 7, 2013 at 13:28
  • 1
    This question appears to be off-topic because "I asked a similar question before" … and got a correct answer which is quoted in the question. Commented Aug 7, 2013 at 13:52

5 Answers 5

2

I'm not sure there is a 100% secure answer. A combination of a server generated token that is inserted into a hidden form element and anti-automation techniques like limiting the number of requests over a certain time period is the best thing I can come up with.

[EDIT] Actually a good solution would be to use CAPTCHAS

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, limiting request/time is the one solution I have in mind. But a "patient" hacker can mess up stuff in one day :)
That's true, CAPTCHAS are probably a good idea then, though there are places where you can pay to have them broken (often by cheap foreign labour)
@CengizFrostclaw If you're worried about spamming requests, limiting requests per x time is a good method. That's what Stackoverflow does with comment votes, for instance...
@Slicedpan, no one will pay to hack my application :) But, if I put captcha, no one will use it either. So my temporary solution will be time limit..
2

Your question isn't really "How can I tell AJAX from non-AJAX?" It's "How do I stop someone inflating a score by repeated clicks and ballot stuffing?"

In answer to the question you asked, the answer you quoted was essentially right. There is no reliable way to determine whether a request is being made by AJAX, a particular browser, a CURL session or a guy typing raw HTTP commands into a telnet session. We might see a browser or a script or an app, but all PHP sees is:

GET /resource.html HTTP/1.1
host:www.example.com

If there's some convenience reason for wanting to know whether a request was AJAX, some javascript libraries such as jQuery add an additional HTTP header to AJAX requests that you can look for, or you could manually add a header or include a field to your payload such as AJAX=1. Then you can check for those server side and take whatever action you think should be made for an AJAX request.

Of course there's nothing stopping me using CURL to make the same request with the right headers set to make the server think it's an AJAX request. You should therefore only use such tricks where whether or not the request was AJAX is of interest so you can format the response properly (send a HTML page if it's not AJAX, or JSON if it is). The security of your application can't rely on such tricks, and if the design of your application requires the ability to tell AJAX from non-AJAX for security or reliability reasons then you need to rethink the design of your application.

In answer to what you're actually trying to achieve, there are a couple of approaches. None are completely reliable, though. The first approach is to deposit a cookie on the user's machine on first click, and to ignore any subsequent requests from that user agent if the cookie is in any subsequent requests. It's a fairly simple, lightweight approach, but it's also easily defeated by simply deleting the cookie, or refusing to accept it in the first place.

Alternatively, when the user makes the AJAX request, you can record some information about the requesting user agent along with the fact that a click was submitted. You can, for example store a hash (stored with something stronger than MD5!) of the client's IP and user agent string, along with a timestamp for the click. If you see a lot of the same hash, along with closely grouped timestamps, then there's possibly abuse being attempted. Again, this trick isn't 100% reliable because user agents can see any string they want as their user agent string.

Comments

0

Use post method instead of get.Read the documentation here http://api.jquery.com/jQuery.post/ to learn how to use post method in jquery

10 Comments

It is still possible to automate POST requests
@Slicedpan doesn't POST require a form? I can turn my images into form inputs, then will it still be possible to automate POST requests, without having a form ?
You can simply use the console in chrome to POST arbitrary data to any URL, without creating a form at all
@Cengiz Frostclaw : yes via a command line with curl for example, or simply from the chrome's console with few lines
@David they can request token but if they can't see it, they can't use it, right ? The application presents two images, user chooses one of them. Then it inserts choices into DB, like winner_id=42 , loser_id = 43 etc.
|
0

You could, for example, implement a check if the request is really done with AJAX, and not by just calling the URL.

if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    // Yay, it is ajax!
} else {
    // no AJAX, man..
}

5 Comments

Nice. But I saw such an answer before, and people said that, one can also manipulate $_SERVER variables. Is it true?
@CengizFrostclaw Yes, it's true. The client is responsible for sending that information, so the client can control what information it sends. Your average user will have no idea how to change it, but it is possible to change nonetheless.
@Mansfield of course, probably 99% of them won't know what AJAX is. But I still want to make sure it is hack-proof :)
@CengizFrostclaw If making it "hack proof" is what you want, this answer will not work then.
true. this solution is not 100% hack proof. i think you have to use captchas.
0

This solution may need more reflexion but might do the trick

You could use tokens as stated in Slicedpan's answer. When serving your page, you would generate uuids for each images and store them in session / database.

Then serve your html as

<img src='src.jpg' data-id='42' data-uuid='uuidgenerated'/>

Your ajax request would become

$.ajax("action.php?action=click&uuid=uuidgenerated");

Then on php side, check for the uuid in your memory/database, and allow or not the transaction. (You can also check for custom headers sent on ajax as stated in other responses)

You would also need to purge uuids, on token lifetime, on window unload, on session expired...

This method won't allow you to know if the request comes from an xhr but you'll be able to limit their number.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.