Preventing CSRF with tokens in a AJAX based application - php

I'm using tokens to prevent CSRF attacks in my application. But this application is single page and heavily AJAX based, so I need to find a way to provide a valid token for N actions in a single page:
e.g. A document fragment loads with 3 possible actions, each action needs a token to work properly but server side has just one valid token at time...
Since each token is just a encrypted nonce (the value isn't based in a specific form), I came with the idea of automatize the token assignation for each action with something like this:
The App intercepts an AJAX call, and check if it's a sensitive action (i.e. delete a user)
A token is requested to the server before the action proceed
The token is generated and then added to the action request
The action in executed since the request included a valid token
Do the same for any subsequent actions executed via AJAX
I believe that method isn't effective enough because the attacker can use a script that does exactly the same my App does (retrieve token and append to the request).
How can I improve my method to be effective against CSRF attacks?
Additional info: My backend environment is PHP/Phalcon and the tokens are generated using Phalcon.

A simpler method than using tokens for an AJAX only might be to check headers that can only be present in an AJAX request from your own domain.
Two options are:
Checking the Origin Header
Checking the X-Requested-With header
The Origin header can also be used for normal HTML form submissions, and you would verify that this contains the URL of your own site before the form submission does its processing.
If you decide to check the X-Requested-With header, you will need to make sure it is added to each AJAX request client side (JQuery will do this by default). As this header cannot be sent cross domain (without your server's consent to the browser first), checking that this is present and set to your own value (e.g. "XMLHttpRequest") will verify that the request is not a CSRF attack.

I had to deal with something similar awhile ago. Requesting nonces with ajax is a super bad idea – IMHO, it invalidates the whole point of having them if the attacker can simply generate it without reloading the page. I ended up implementing the following:
Nonce module (the brain of the operation) that handles creation, destruction, validation and hierarchy of nonces (e.g., child nonces for one page with multiple inputs).
Whenever a form / certain input is rendered, nonce is generated and stored in a session with expire timestamp.
When the user is done with an action / form / page, the nonce with it's hierarchy is destroyed. Request may return a new nonce if the action is repetitive.
Upon generating a new nonce old ones are checked and expired ones are removed.
The major trouble with it is deciding when the nonce expires and cleaning them up, because they grow like bacteria on steroids. You don't want a user to submit a form that was open for an hour and get stuck because the nonce is expired / deleted. In those situations you can return 'time out, please try again' message with the regenerated nonce, so upon the following request everything would pass.
As already suggested, nothing is 100% bullet proof and in most cases is an overkill. I think this approach is a good balance between being paranoid and not wasting days of time on it. Did it help me a lot? It did more with being paranoid about it compared to improving the security dramatically.
Logically thinking, the best thing you could do in those situations is to analyse the behaviour behind the requests and time them out if they get suspicious. For example, 20 requests per minute from one ip, track mouse / keyboard, make sure they are active between the requests. In other words ensure that requests are not automated, instead of ensuring they come with valid nonces.

Related

How to stop people from flooding PHP API with requests?

I am using a simple PHP API that takes requests and connects to a MySQL DB to store/retrieve user information. Example: Login is done using a HTTP POST to the API with username and password.
How do I prevent people from flooding my API with requests, potentially making thousands of accounts in a few seconds.
Thanks
You could serve a token generated and remembered on the server side which is rendered with your forms and validated when the form is sent back to your server. That prevents the user from just generating new post requests without actually requesting the according form from your server since they need the according token generated on your server to get it through.
Then there is the mentioned captcha which would be way too much for a login form from my point but when it comes to things like registering a new user the captcha in combination with the token sounds very good to me.
UPDATE
I Just found this article which is about floot protection of script execution in general. I think their approach is good as is the ip tracking provided you have the ability to use memcache or something similar to speed the checks up.
First, when registering a user, also save her IP address at the time of registration in the DB.
If the IP already exists within 45 minutes of previous registration, reject the request.
Another method is the Captcha, I personally prefer a different method that I found to be even more effective against robots.
Instead of asking the user to "type what they see in an image", and verify they are humans (or robots with sophisticated image processing),
Add another field (for example city), and make it hidden with javascript.
The robots would submit that field to the server, and humans would not.
Note that the robots must run the javascript in order to know what fields are hidden, and this is a time consuming process that they usually don't do.
(see turing halting problem)

Send CSRF token to javascript

Suppose I maintain a anti CSRF token at server side in a session
How am I supposed to pass the token to client side application if my form generation is going to be dynamic(i.e. form will be created after some action has been performed by javascript)
Is there a way to pass the token to javascript so that I can inject the token in the form.
One working way that I found is send a cookie to the browser containing the token which will be then extracted by javascript.
Any suggestions?
I would suggest starting out from a secure token, and then improving it through JavaScript according to dynamic form Creation.
Eg, like:
<input type="hidden" name="csrftoken" value="hgdillksdbgjksdbkvbskb">
Where the "value" parameter is generated on server-side when page loads.
And then you have a script like:
csrftoken = document.mainform.csrftoken.value;
# Do something with the CSRF token, like add dynamic values, like sha256(csrftoken + "dynamicvalue");
document.mainform.csrftoken.value = csrftoken;
The main idea of this, is to prevent, that even if they manage to get a exploit that would allow a adverisary to read the JavaScript code, they still cannot make up a valid CSRF token, since they cannot read the original "csrftoken" value that was inside the form at page load.
This can also be used to "chain" AJAX requests, like that you start out with the token X during page load. Then you transform it to Y using JavaScript, send it in a AJAX request. In the next AJAX request, you can use Y as base in the algoritm, to create Z, and send to the server. A attacker cannot gain access to X, thus they cannot either get access to Y neither Z, even if they would in some way be able to exploit running JavaScript code to reveal itself.
Note that page contents cannot be read by a adversiary due to Same origin policy. But Javascript can contain exploits that would make it possible to read the actual running JavaScript code. Theres no such exploits currently, but better be safe than sorry.
Sure. If you're dynamically generating the form on the client side then you're doing it from some kind of template. The token should be an argument to that creation function.
Pass the token along to the client at request/render time and then inject it into the form as a hidden element at form generation time.

How to secure php scripts?

If I have an AJAX call to a php script, like this (using jQuery)
$.ajax(url: "../myscript.php");
and myscript looks like this:
<?php
//code that does something to db
?>
I want to know how to prevent a user from just going to example.com/myscript.php to execute the script.
Ajax queries are just user queries
Every XmlHTTP request can be replayed and tampered (just check your favorite browser console, capture the POST or GET requests and check if there is a replay options), you can also try Live HTTP Headers module (or many more) and capture anything to replay it.
So if you set an entry point in your application, anybody can try to access it and inject some bad stuff there.
Note that they can also alter any HTTP headers in their requests to alter things like the referrer page or the host header, anything.
Insecure Inputs
So in term of security every user input has to be considered unsafe (GET parameters, POST data, used url -- OMG so much application are never filtering data coming from the url path --, cookies, ...)
Filtered output
So you may wonder "How can I do something with insecure inputs?", well ...you can. The rule is to filter all the outputs. Take the output canal (database storage, html page, json response, csv file) and escape your data accordingly (htmlentites for HTML, json escapes for json, sql escaper or parametized queries for SQL queries -- check the libs--), especially the parts coming from the user input, which are really unsafe as stated before.
Access control
Now your main problem here is access control, you have an entry point where you perform some database actions and you do not want anybody to access this entry point and perform actions.
Several things to do:
ensure this is not a GET entry point (only POST, PUT, DELETE HTTP actions should perform modifications on the database), this will prevent usage of this url in an image tag later, loading the action without user interaction.
manage a user session, using cookies (PHP does that for you) you can share some data between several HTTP requests, this is called a session. The user cookie will be used to load the server-side session storage, containing important data, such as Is my user an anonymous user or a connected one?. This is the Identification part.
manage log-in log-out pages to get the Authentication part, theses pages will feed the session with the logged-in status. For a simple solution you can also check for HTTP basic authentication (.htpasswd files), it will also work for ajax, but never use HTTP basic Authentication without SSL. This Http auth mode will manage both identification and authentication parts.
manage ACL (Access Control List), the way you want, and use that to decide if your ajax page can be accessed by the current user (you get the user from the session). If not, send a 403 HTTP response.
Public Access
Now if your 'database' stuff that should run is not related to any user privilege, but you just want to prevent abuse of it, like, say, a statistical ajax query, doing a counter increment, that every user should call at least once. In this case you will have some problems. It's very hard to prevent abuse of a public entry point (just think of how hard it is to protect websites from DOS and DDOS). You'll have to build a functional system, application-based, things like generating a unique token in the user page and checking that this token is used only once (but an anonymous page could be used by thousands of users, coming from a proxy cache), maybe you'll have to record user IP and restrict the token usage by IP (but some users may share the same IP), or maybe you'll have to send the unique token to the user using ajax.
We could talk of a lot of things, but that depends on the things you are trying to do. The important thing are:
never trust user inputs
filter outputs
manage sessions and ACL
never consider anything as hidden, there's no such thing.
Some answers here give you an overview of the concepts behind your question, let me give you a more pragmatic approach (you should at least read and understand what others say about this matter though!).
You just need to ask yourself: Do your app must enforce that all requests to myscript.php should be controlled?
If so then you need to use some sort of token: you create a token and send it to the client (browser), then the browser must send back the token and you check if it matches before doing some action:
<?php
// somefile.php (this file serves the page that contains your AJAX call)
session_start();
//...
$_SESSION['token'] = createNewToken(); // creates unique tokens
//add the token as a JS variable and send it back in your AJAX CALL
// some where you'll have something similar to this:
<script>
var token = <?php echo $_SESSION['token'] ?>;
$.ajax({
url: "myscript.php",
data: form_data, // include the token here!
//...
})
And then in your script:
<?php
// myscript.php
session_start();
// you can check if it's an AJAX call, if the user is logged and then the token:
if (!isset($_SESSION['token')) {
header("HTTP/1.0 403 Forbidden");
die("Direct access not allowed!");
}
// Assuming your AJAX is a POST though you didn't tell us
if (!isset($_POST['token'] || $_POST['token'] != $_SESSION['token']) {
header("HTTP/1.0 400 Bad request");
die("You didn't provide a valid token!");
}
// do something with your DB
Otherwise you just need to check if the user is logged as you would normally do with the rest of your scripts:
<?php
// myscript.php
session_start();
// Check if logged in user
if (!isset($_SESSION['loggedIn']) || !$_SESSION['loggedIn']) {
header("HTTP/1.0 403 Forbidden");
die("You need to be logged in!");
}
// Do something with your DB
TO SUM UP
Using the first method allows a more controlled access as you force the user to send a secret (the token, which will be different in every request) that a normal user won't have (if some other user gets the token, then you have bigger problems like session hijacking). Notice that this method prevents the user opening on multiple tabs / different browsers as only the last token will be saved. In order to avoid that you have this fantastic answer on SO
On the other hand, the second approach allows (logged) users to request directly your myscript.php, but maybe you don't need to prevent that (if you need, just use the first method). Notice here you won't have the issue of multiple tabs / different browsers as you'll only check if the user is logged in.
how to prevent a user from just going to example.com/myscript.php to execute the script
From a security perspective, the AJAX call is the same as the user going to that URL. That is, the human user and the script you use to make the AJAX call are part of the same security principal. If you don't trust the user with access to the PHP script, you can't trust the JavaScript running on the user-controlled computer either.
So in what cases can there be separate security principals? You could, for example, only deploy the client JavaScript on some kind of tamper-proof kiosk. That way, you could store a secret value in the kiosk, shared with the server. The kiosk would send the secret value with each request for the server to validate.
But if you're doing this for a usability reason, to prevent accidental invocation of the script, then yeah, maybe try that one thing Dirk Pitt linked to.

Preventing erroneous AJAX Calls by the user

I have a webpage in which the user is awarded X points on clicking a button. The button sends a AJAX request(JQuery) to a PHP file which then awards the points. It uses POST.
As its client side, the php file, parameters are visible to the user.
Can the user automate this process by making a form with the same fields and sending the request ?
How can I avoid this type of CSRF ? Even session authentication is not useful.
You should handle that on the server-side, If you really want to prevent multi-vote or prevent the same people from voting several time on the same subject.
This is why real votes always use authenticated users and never anonymous votes.
By checking the request is really a XmlHttpRequest (with #Shaun Hare response code or with the linked stackoverflow question in your questions comments) you will eventually block some of the CSRF but you won't prevent a repost from the user, using tools like LiveHttpHeaders 'replay' and such. Everything coming from the client side can be forged, everything.
edit* if it's not a voting system as you commented, the problem is teh same, you nedd 'something' to know if the user is doing this action for the first time, or if he can still do this action. There's a lot of different things available.
You can set a token on your page, use that token in the ajax requests, and invalidate this token for later usage server side. This is one way. the problem is where to store these tokens server-side (sessions, caches, etc)
Another way is to check on the server side the situation is still a valid situation (for example a request asking to update 'something' should maybe handle a hash/marker/timestamp that you can verify with current server side state.
This is a very generic question, solutions depends on the reality of the 'performed action'.
Check it is an ajax call in php by checking
$_SERVER['HTTP_X_REQUESTED_WITH']

Security problem with sending ajax requests remotely?

iam using ajax for sending requests to one of my php pages in the site... but i do this from my html page. This is secure....
But what if others know my php page and they send ajax requests to that page from their script? This may cause any security problems.
How can i avoid this ?
You seem to be trying to defend against CSRF attacks.
You can include a nonce in your page, then require that all AJAX requests have that nonce.
Since the attacker is on a different domain, he will have no way of getting the nonce.
The only way they can send AJAX requests to your page is if they are on the same domain (ie. their script would have to be hosted on your domain).
AJAX won't work cross-domain, so it's quite secure.
There is very little you can do to stop this, the only think that can help prevent this is by having a good application architecture.
For example, the following rules will help:
Try and keep your Ajax down to read only.
If you have to use Ajax to write then you should follow these rules
Only allow users that are logged in to submit data
Validate Validate & Validate your post data, Make sure its exactly as you expect it
Implement a form hashing technique that generates a unique hash for every form on every page, and validate against a variable within the session Aka (Nonce)
If the user is logged in make sure there's a validation period, such as "You must wait 30 seconds before posting".
Always use session_regenerate_id() before you call session_start
These are just a few pointers that should get you on your way, when researching these you will come across other techniques used by other site owners but you should always remember the following 2 rules.
Never trust your users, just act like you do
Whitelist and never blacklist.

Categories