How to secure php scripts? - php

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.

Related

How to secure PHP API from unauthorized AJAX calls (Phonegap mobile app)? [duplicate]

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.
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.
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.
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.
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.
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
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.
It works like any other web page: login authentication, check the referrer.
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
}

Preventing CSRF with tokens in a AJAX based application

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.

PHP random key verification

I am making an AJAX request to a script called return.php that will look like this:
http://www.example.com/return.php?type=3&filter=2
This occurs when a browsing user hits a button on example.com
I want additional security measures so that this can only be requested by a user browsing my site. No direct type ins, etc.
So I was thinking to send some type of randomly generated key along with the request. What methodology would I use to verify at return.php that a correct key has been sent?
Can I generate a key and store it in a session variable that is then accessible in return.php?
pseudo code:
if ($random_key_sent == what it should){
//go ahead and execute code
}
else{
//sorry can't help
}
And Ultimately my request would look something like:
http://www.example.com/return.php?type=3&filter=2&key=8fu5jtugy489kgvuri09984ufjlgi (or whatever the key would be)
Bottom line I am looking for a way to generate some type of added security so that return.php is only being used when it should be, along the similar lines of using API keys etc.
You're looking for cross-site request forgery (CSRF or XSRF) protection.
Typically, you generate and save an anti-CSRF token in the user's session data, and put it in a hidden form field (using either GET or POST), or for normal links you place the token in a query parameter. On the server side, you check that the anti-CSRF token matches the one in the user's session data.
Some suggest that you can achieve the same level of security by simply checking the HTTP referer header. That can work, but is less reliable since people can block the referer for privacy reasons.
If you are worried about "direct type-ins" but still need to use GET requests, you can check the request headers in PHP to only allow Ajax requests using $_SERVER['HTTP_X_REQUESTED_WITH'].
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
// Do what you need to do
} else {
die("Ajax Only");
}
(Modified from David Walsh)
Unless you're going to have a list of preset keys that your PHP code checks against and the browser can receive to then send in the URL, it would be impractical to check the key for a specific value. You could just check if the $_GET["key"] array value is set:
if(isset($_GET["key"])){
// go ahead and execute code
}else{
// sorry can't help
}
Alternatively, you may want to consider requiring the browser to set some POST data which is sent along with the request to the webpage, but cannot be typed into the address bar. Then just use $_POST["key"} rather than $_GET["key"] to verify.

protecting/authenticating JSON requests to server

i am using Ajax to send JSON data over to my server for a php script to parse.
for example this is the JSON which will be outputted:
http://myserver.com/parse.php?user=123&point=100&callback......
and the "parse.php" script will GET the points in the URL and give it to that user which the user id is stored in the user=123.
However , if a person directly use "http://myserver.com/parse.php?user=123&point=100&callback......" on their browser without letting my javascript to initiate it , they can cheat their points , which they can set to any amount they like in the URL.
So how can i protect/authenticate the JSON request??
If you're passing the user points via an AJAX request or something similar client-side, then you simply cannot protect your application against cheating. Your user is telling the script he/she scored 100 points, how can you be sure that's the fair number? Pass over the initial data you're using to compute your score, like valid answers for the questions or whatever it is you're measuring.
If you have a login mechanism in your application, you could check for the valid credentials on the server-side when executing your script, without actually passing the user identifier via GET/POST.
Lastly, in your method you can check for the AJAX header and the referer ($_SERVER['HTTP_X_REQUESTED_WITH'] and $_SERVER['HTTP_REFERER']) to make sure the request comes from your JS code, but this is really just a minor tweak which is easy to compromize. Also, not every browser passes the referer header (depends on privacy settings), so further problems may arise.
Require Users to be logged in to invoke parse.php. If the request doesn't supply a valid session id, refuse to take action.
Don't put any game data and logic in client side.
Never trust the client. You always must calculate server-side.
More infos (don't rely on link title, there is a lot infos in answers) : https://gamedev.stackexchange.com/questions/3695/how-do-you-prevent-your-javascript-html5-web-game-from-being-copied-or-altered

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']

Categories