How to block external http requests? (securing AJAX calls)
Asked Answered
R

9

7

I want to use post to update a database and don't want people doing it manually, i.e., it should only be possible through AJAX in a client. Is there some well known cryptographic trick to use in this scenario?

Say I'm issuing a GET request to insert a new user into my database at site.com/adduser/<userid>. Someone could overpopulate my database by issuing fake requests.

Rivero answered 17/5, 2012 at 14:43 Comment(5)
clarify your question please ....Ayeshaayin
You should not use GET for any purpose other than data retrieval.Alliaceous
It's just easier to use GET an example, I would probably be using POST anyways.Rivero
Sadly, cryptography is not a magic wand that you can wave over anything to make it only do what you want. Some people spend billions of dollars to figure that out (the entire DRM industry is trying very, very hard to square that particular circle). Don't be those people.Mown
possible duplicate of Prevent Direct Access To File Called By ajax FunctionBean
S
7

There is no way to avoid forged requests in this case, as the client browser already has everything necessary to make the request; it is only a matter of some debugging for a malicious user to figure out how to make arbitrary requests to your backend, and probably even using your own code to make it easier. You don't need "cryptographic tricks", you need only obfuscation, and that will only make forging a bit inconvenient, but still not impossible.

Stolen answered 26/5, 2012 at 20:18 Comment(1)
I was afraid this would be the case. If anyone has any obfuscation tricks to suggest, I'm all ears.Rivero
W
4

It can be achieved.
Whenever you render a page which is supposed to make such request. Generate a random token and store it in session (for authenticated user) or database (in case this request is publicly allowed).
and instead of calling site.com/adduser/<userid> call site.com/adduser/<userid>/<token>
whenever you receive such request if the token is valid or not (from session or database)
In case token is correct, process the request and remove used token from session / db
In case token is incorrect, reject the request.

Worcester answered 21/11, 2012 at 22:54 Comment(0)
M
3

I don't really need to restrict access to the server (although that would be great), I'm looking for a cryptographic trick that would allow the server to know when things are coming from the app and not forged by the user using a sniffed token.

You cannot do this. It's almost one of the fundamental problems with client/server applications. Here's why it doesn't work: Say you had a way for your client app to authenticate itself to the server - whether it's a secret password or some other method. The information that the app needs is necessarily accessible to the app (the password is hidden in there somewhere, or whatever). But because it runs on the user's computer, that means they also have access to this information: All they need is to look at the source, or the binary, or the network traffic between your app and the server, and eventually they will figure out the mechanism by which your app authenticates, and replicate it. Maybe they'll even copy it. Maybe they'll write a clever hack to make your app do the heavy lifting (You can always just send fake user input to the app). But no matter how, they've got all the information required, and there is no way to stop them from having it that wouldn't also stop your app from having it.

Mown answered 26/5, 2012 at 18:24 Comment(2)
This is the best explanation I've seen on the various duplicate questions. You should add it to #1757091 which is the oldest dupe of this question.Bean
You're right, @IMSoP, there is a lot of incompetence in that thread's answers. I adapted my reply a little bit, because what the OP really needed was to be pointed in the direction of authentication.Mown
R
1

Prevent Direct Access To File Called By ajax Function seems to address the question.

You can (among other solutions, I'm sure)...

  • use session management (log in to create a session);
  • send a unique key to the client which needs to be returned before it expires (can't be re-used, and can't be stored for use later on);
  • and/or set headers as in the linked answer.

But anything can be spoofed if people try hard enough. The only completely secure system is one which no-one can access at all.

Rambow answered 21/5, 2012 at 8:4 Comment(0)
S
1

This is the same problem as CSRF - and the solution is the same: use a token in the AJAX request which you've perviously stored eslewhere (or can regenerate, e.g. by encrypting the parameters using the sessin id as a key). Chriss Shiflett has some sensible notes on this, and there's an OWASP project for detecting CSRF with PHP

Sarcous answered 21/5, 2012 at 8:25 Comment(4)
This is not quite the same problem as CSRF. In CSRF, it is an identity issue, but I'm worried that the user himself might abuse their own login credentials, their own session token, and use their own account to artificially populate the database.Rivero
Given that it is impossible to restrict access to the server to just your ajax APIs, it's exactly the same as CSRFSarcous
I don't really need to restrict access to the server (although that would be great), I'm looking for a cryptographic trick that would allow the server to know when things are coming from the app and not forged by the user using a sniffed token.Rivero
Why don't you use a token that's valid only for a short lifespan? (But enough to complete your AJAX request). You can generate a code based on server's time with a secret algorithm, implemented in both client and server. The client will add this code to its request, and the server will check if the code is still valid. Something like IPsec's "trick" to avoid replication attacks. If the number is not valid, the request will be just trashed. Please note that this is just an idea, I've got no working code for it!Cheyenne
N
0

It works like any other web page: login authentication, check the referrer.

Naranjo answered 17/5, 2012 at 18:46 Comment(5)
Could you clarify? Are you saying that the server application will know who is issuing the request and that it's possible for it to recognize AJAX requests only?Rivero
See: #7128186 Session authentication is up to you. You can give the client a key that is passed back with each request.Naranjo
I can't really find any safe solutions there. I've considered sending client authentication, but then the client himself can sniff around the headers and reuse the key for their own sake. There must be a more robust solution, because all web apps need this.Rivero
Relying on the referer is not a good idea. OTOH, there is NOTHING you can do using AJAX that a user cannot replicate via other means.Sarcous
It's fairly easy to fake referrers.Mown
D
0

The solution is adding the bold line to ajax requests. Also you should look to basic authentication, this will not be the only protector. You can catch the incomes with these code from your ajax page

Ajax Call

function callit()
{
 if(window.XMLHttpRequest){xmlhttp=new XMLHttpRequest();}else{xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
 xmlhttp.onreadystatechange=function(){if(xmlhttp.readyState==4&&xmlhttp.status==200){document.getElementById('alp').innerHTML=xmlhttp.responseText;}}
 xmlhttp.open("get", "call.asp", true);
 **xmlhttp.setRequestHeader("X-Requested-With","XMLHttpRequest");**
 xmlhttp.send();
}

PHP/ASP Requested Page Answer

ASP

If Request.ServerVariables("HTTP_X-Requested-With") = "XMLHttpRequest" Then
 'Do stuff
Else
 'Kill it
End If

PHP

if( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && ( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) )
{
 //Do stuff
} else {
 //Kill it
}
Densimeter answered 23/5, 2012 at 23:11 Comment(1)
Thanks for the effort, but that's just a header check as others have mentioned. It's not secure enough, since the user can fake the header.Rivero
A
0

This is some authorization issue: only authorized requests should result in the creation of a new user. So when receiving such a request, your sever needs to check whether it’s from a client that is authorized to create new users.

Now the main issue is how to decide what request is authorized. In most cases, this is done via user roles and/or some ticketing system. With user roles, you’ll have additional problems to solve like user identification and user authentication. But if that is already solved, you can easily map the users onto roles like Alice is an admin and Bob is a regular user and only admins are authorized to create new users.

Alliaceous answered 26/5, 2012 at 18:44 Comment(0)
D
0

I have read many posts on this topic and desperately looking for a solution for this exact same question. I have several PHP script sitting on my server and my client app uses these to talk to a SQL database. Naturally I worried for somebody else to uses these script and make harm to my database.

In the end I did the following, and I wonder if it can be usefull to anybody and welcome critic identifying weakness to my solution.

In my post I add a TOKEN which is encrypted using the crypto-es package. Part of this token is a timestamp (UNC).

In my PHP script I decode the TOKEN, identify the timestamp and compare the time to the current time (UNC) and return an error if the difference is more than a short interval.

I found much help in the encrypting/decrypting in this article

Doughboy answered 22/7 at 10:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.