2

Let's suppose that you have a website that contains a single button.

When this button is pushed, an ajax request is sent to the server - who receives the request and adds 1 in an internal counter on its database.

An user could copy the entire request (and its headers) and create a script to send infinite requests to overload the server (and mess with the counter).

I'm trying to avoid:

  1. Recording the user IP
  2. Using Captcha

I'm using php in my back-end. Is there any way to prevent this situation? Is there some way to send an "invisible" request?

magroski
  • 193
  • 1
  • 1
  • 10
  • You cannot create an invisible request, but you can solve the problem in other ways. – Greg Pettit May 22 '12 at 02:46
  • possible duplicate of [.htaccess or PHP protection code against multiple speedy requests](http://stackoverflow.com/questions/2820699/htaccess-or-php-protection-code-against-multiple-speedy-requests) – bfavaretto May 22 '12 at 02:54

3 Answers3

3

you can create a unique token that is assigned to the button and can only be submitted once with the button press.

this will mean that the user will need to refresh the page to get a new button, if thats a problem, associate the token with the user and not the button

the above method means that you need to add server side code. you might be able to get away with using something like evercookie to log the button press on the clientside and attempt to prevent the user from sending another request and recieving another request from user - i dont recommend doing this in prod, but it might be fun ;)


ill try to be bit more clear:

generate the button so that it submits a form containing a hidden field called 'uuid' that contains a pre-generated uuid for that button. this uuid will need to be kept in the database or in memory. if you use a good uuid lib, the chance of the user generating an existing uuid are infinitesimal.

now, the user clicked the button and the action goes to /my-button/?uuid=3394b0e0-a3bb-11e1-b3dd-0800200c9a66

now the server checks if the uuid is a previously generated one. if it is, it deletes the uuid from where its stored and lets the action do whatever. the uuid does not exist, it returns a 404.

mkoryak
  • 57,086
  • 61
  • 201
  • 257
  • The server has no idea how the request was originated, it only knows it gets a request. So the request may not be in response to a button press. – RobG May 22 '12 at 02:53
  • wait wat? doesnt a button press result in a request to some url, some handler? and doesnt this handler know what this request was from a button press? and if not, cant you code it? – mkoryak May 22 '12 at 02:56
  • You can determine such things if the user has a standard browser and uses standard UI features. But you don't know if that's the case from the server, the user agent may not be a browser or even have a human controlling it. – RobG May 22 '12 at 03:00
  • what does the browser have to do with anything? if i request http://dogself.com/button-press/ via wget, the code running on dogself.com should be able to tell that a /button-press/ was requested. now add a unique param at the end of that url and check if that unique param exists in your database and you are 1/2 there – mkoryak May 22 '12 at 03:02
  • I like the anwser but don't use cookies to store the value, they can be copied from the machine and reused. For example I navigate to the page, get the uuid on a cookie, browse my cache and copy the uuid from the cookie. Then i refresh the page and get a new UUID. Since the first one i had havent been used i can store it for later use. – Shiin Zu May 22 '12 at 03:27
3

Your problem is called "cross site request forgery".

A good way to solve this problem is to generate a random string when the page with the button on it is called, write it into the users session and into the generated page, and send it together with your button press (for example in a GET request).

On the backend side you check if the submitted string matches with the string in the users session and then delete the string from the session. Only proceed if both strings matched and weren't empty.

This way every request URL is only valid one time and only valid for the user who initially opened the page with the button on it.

Pierre
  • 874
  • 6
  • 8
0

You can't possibly know how a request is initiated, all you can do is make it more difficult to fake. But if this is something to do with security, then it's the people who can successfully fake the request that you need to be most aware of. So it's likely useless (or even misleading) to attempt this as some kind of security measure.

You can try an encrypted key that the server will only accept once within a certain time lmit, but you will still not know how the request was initiated (and you really shouldn't depend on that). Buttons are a UI feature that might be converted into some other UI artifact based on whatever the user agent has been configured to present to the user (if there is a user invovled at all).

RobG
  • 142,382
  • 31
  • 172
  • 209