Secure AJAX request to URI - php

I know there have been lots of question about AJAX security. I've searched and read but am still unclear as to what the best approach is.
I have a very specific senario:
I have an application that is build on top a PHP MVC framework. I've turned presentation elements such as a "navigation menu" modular. The navigation menu module has a controller (sever side). The controller uses a model to retrieving data from the database and then it responds with a php echo of the data. I can make the http request to the controller using AJAX because the controller is routed to by a URI. I believe this is call a RESTful API. When the user clicks a link in the navigation menu a static content area is update with the data that was retrieved from the AJAX request. Lets say that I Make a different action in the same controller that is capable of writing data to the database. Having a publicly available URI that allows writing to the database is obviously bad. How does one secure the URI interface so that AJAX can retrieve and write data, but those individuals with malicious intent can do harm?

You must treat an ajax request as you treat a get request or post request.
In other words never trust the user. You have server side control, ajax is client side so never trust "CLIENT SIDE" that makes a request(check the data, if data is ok then return a response if not return another response).

Controller is able to write to database:
There is no true way to secure an public URI interface so that it is only able to be accessed by the part of your application that exists on the client side. The idea is then to not make the interface so public, meaning it cannot be accessed by everyone! If a URI were to point to a “controller” (MVC architecture) and in turn the controller has access to manipulate a critical database, you best make it so the client who sends the request to the controller must “Authenticate”. This concept is true whether the http requests are coming from a web form or Ajax. Typically before Authentication credentials are transmitted using https (http + SSL) to keep a “Man In The Middle” from seeing the credentials.
Controller is able to read from the database:
When a read request is made you can simply return the data, or if its sensitive data require an authenticated client.
The “Navigation menu module” should only be edited by an administrator, so authentication is a must. However, any web surfer who views a page containing the module should not have to authenticate to use the navigation, that would be silly.

The main rule is to validate all inputs - check all data coming in and clear from unwanted chars.
Also, it all depends if You allow user change Your DB without loging in or not. Logged users are easier to verify and You always can put on serwer - side checking scripts - if current user is allowed to do this operation.
Things are harder when You allow annonymous user to write to Your DB. Then, its good to operate mainly on ID`s and if You allow user to insert data from inputs - filter all from unwanted things. The good way of doing it is to create whitelists of chars You approve and cut everything else.
You have to remember, that Ajax is nothing else but sending POST request to url - and You should do the same protection as with standard forms. Also good practice is to add a token to Your send data - wich You can verify by server side.

Related

PHP splitting up classes

I'm fairly new to PHP and trying to figure out how to logically split up my classes. Here is the very basic setup.
index.php -- Top page. When login button is pressed, it calls an external authentication server.
callback.php -- Authentication server sends call back here. I store the user's login name.
game.php -- this is where I have a web game that makes a POST request to callback.php
Here is what I thought is "correct" practice from other OO languages.
I'd like to get the data received in callback.php and store it somewhere else (data.php). The only way I can figure out how to do this is to use a session in callback.php and read it in data.php. Is there a better way to do this or should I keep the data in callback.php (and make the POST request to callback.php instead of data.php)?
After the callback.php gets the data from the authentication server, I use a redirect to go to game.php. If the user goes straight to game.php and isn't logged in, I also use a redirect. Is there a better way?
header("Location: http://www.mypage.com/game.php");
I'm happy to post any code but I'm guessing it's not necessary for these types of questions. Let me know and thanks!
The purpose of OO programing to keep code as module as possible while bundling relative modules together.
Example:
User Object - contains all code relative to users
Game Object - contains all code relative to games
It is still very likely that you will have code that doesn't belong to a specific object, but more to a particular set of actions. However, OO programming can still be applied even to these.
Example:
Action page: contains all code relative to dealing with a specific group type of actions (Like handling all the actions/callbacks from a specific frontend page).
That being said, your initial statement of separating into the 3 different files is fine.
I'm assuming the index.php is the front facing said that the user interacts with, so separating that from the backend process or controller is good. It would be better to use an require_once("data.php") versus sending the data over the network again and this way you can save the data to that instance and access it without having to use session variables. I can process the data however you want, and once you get the desired results you can do your header() redirect.

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.

Using HTTP Authentication

I am building a REST API in PHP to work with a JavaScript based app. All requests are handled as JSON and some requests require authentication.
An example request would be:
$.ajax({
type: 'GET',
url: 'http://domain.com/api/posts/recent.json',
headers: {
Authorization: 'X-TRUEREST ' + $.param({
username: 'johndoe',
password: '********'
})
},
success: function(response){
// Handle response here (includes auth errors too)
},
error: function(a,b,c) {
}
});
I have based the use of HTTP Authentication headers on the code in this plugin: https://github.com/kvz/cakephp-rest-plugin/blob/master/Controller/Component/RestComponent.php#L532
As you can see they take passed parameters with the header and then they are used to log a user into the system if they are not already. From what I can tell they expect the auth credentials to be passed WITH the request for data.
An example of this is (note not using CakePHP in my example app):
if ( $loggedIn ) { // logged in is true of false based on session existing
// Then return the JSON as normal
} else {
// Grab HEADERS INFO
$headers = $_SERVER['HTTP_AUTHORIZATION'];
$parts = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);
// Then use the parts to find a user in the DB... and populate $user
if($user){
$this->Auth->login($user); // login the user with our authentication code
// Then return JSON as normal
} else {
print json_encode(array('auth'=>false))
}
}
A few questions that I have though:
Question 1: Why use the HTTP Authentication and headers? As as far as I can tell, they are not offering me anything unless I am using them incorrectly? Why not just pass the username and password in the data param of the JS?
Question 2: As stated earlier I have based my API design on the Cake plugin above, but from what I can see they ALWAYS pass the username and password with every request and then decide to use it or not if the user is logged in. Is this correct? To me, it seems more likely that authentication and requests for data should be handled separately. Otherwise I would have to store the username and password in my JavaScript somewhere so that I can send it with each request.
Which brings me to the next question...
Question 3: How do I know if a user is logged in? I could set a variable to true and then pass that as part of my JSON with every request, but can a session work with an external device?
If you are designing a REST api, you should adhere to REST principles. There are two important ones to highlight for authentication:
Identification of resources through URIs
State transitions through server-supplied links.
To adhere to principle 1, you need to keep your authentication out of your URI. http://example.org/list-of-stuff?auth-token=12345 is not a different resource from http://example.org/list-of-stuff?auth-token=67890, so it should not have a different URI. Having different URIs also makes it impossible to cache the resource across different users.
In general, if the resource would be different depending on some condition, that condition needs to be in the URI. For example, many websites have a /profile url, but what profile you see depends on the invisible "who is logged in" state. This is not RESTful. Instead the url should contain the user, e.g. /profiles/username. Whether you actually get to see that resource depends on whether you are authorized to see it, which depends on whether you are authenticated as a user that is authorized. Authentication is a separate layer from resource identification. (For example, suppose you have an admin user which can see other people's profiles. If you have just a /profile url, how would you architect a method for him to see other profiles? Clearly the presence of a resource is something different from the ability to see it and from who is looking at it.)
So we have established that authentication should not be via parameters in the URI. Since we are using HTTP, we can either provide it in a header, or provide it outside HTTP itself.
Although it's not very common, some REST apis handle authentication at the SSL layer using client certificates. This is great from a technical standpoint, but the user experience is baffling and terrible. Although this article is from 2008, nothing has improved. This approach is also not easily scriptable from browser JS, and even outside the browser it's cumbersome to write an application that has to provide client certificates. Development on the server side is difficult, too, because most web scripting environments do not give you easy access to SSL-layer stuff at all, let alone more esoteric SSL features like client-certificates. Your application may not be able to know what certificate identity was provided with the request.
So that leaves HTTP in the header. We can either use a traditional cookie-based auth, where we "log in" at a special url and get a token back, or HTTP authentication which is natively supported by HTTP.
HTTP authentication is far superior in terms of RESTful principles because it is stateless. (This makes your third question nonsensical--there is no "logged in" or "logged out" state--you either provided the right credentials for the request or you didn't!) You don't need to ensure you first visited a special url and got a magic token you need to save (which might suddenly expire), you just issue a request with your credentials every time. If you are not authorized to access a resource, there's a specific HTTP response code (401) and header (WWW-Authenticate, Authorization) and set of well-defined behaviors. It's also extensible with different authorization methods. There's a fair amount of javascript support too, at least if you stick to XmlHTTPRequest. (Heck, jQuery 1.7.2 even has username and password options, so you don't even need to base64-encode it yourself!)
The downside is that the only HTTP auth methods that are in common use and well supported are Basic and Digest, and both of them are not very secure. They're probably fine if you only use https, but otherwise they are terrible.
Also HTTP auth is useless for normal browser use by humans: no custom login pages, no way to present "forgot password" functionality or other authentication customizations, and still browser makers have provided no easy way to "log out" (i.e., forget the credentials for the current realm)!
Cookie-based auth provides you the most control, but you need to keep server- and client-side authentication state and worry about a whole host of other security issues, such as session fixation or even what constitutes a session! Is it IP address, user agent, some combination? How long should an authenticated session be valid before we expire it? What if there's a proxy involved and the IP address changes frequently? What should we do when the magic token expires? What should we do when the user is not authorized? (You can't use an HTTP 401 response--you need to define your own method specific to your site.) In essence, you need to define your own complex session and authentication protocol or adopt someone else's. At least with HTTP auth, the only thing you need to worry about is an attacker reading your Authenticate headers, and using SSL solves that problem.
Question 1: Why use the HTTP Authentication and headers? As as far as I can tell, they are not offering me anything unless I am using them incorrectly? Why not just pass the username and password in the data param of the JS?
HTTP Authentication here appears to be a personal choice of the developer. You could use OpenID. You could use a token. You could use HTTP Header Authentication. You could use sessions/cookies. Heck, you could even use RSA Key Authentication or SSL Client Certificates if you liked.
Question 2: As stated earlier I have based my API design on the Cake plugin above, but from what I can see they ALWAYS pass the username and password with every request and then decide to use it or not if the user is logged in. Is this correct? To me, it seems more likely that authentication and requests for data should be handled separately. Otherwise I would have to store the username and password in my JavaScript somewhere so that I can send it with each request.
You shouldn't expose the username and password of anything in plaintext, ever (technically you shouldn't even store it as such, but that's not what the question is about). Use a public token with an API, or a unique cookie ID. Personally, I use $_SESSION["id"] to see if a user is logged into anything. Let the AJAX submit and then map the ID to a token internally, if you have to.
Question 3: How do I know if a user is logged in? I could set a variable to true and then pass that as part of my JSON with every request, but can a session work with an external device?
I have a function I use for this linked in this answer. You should ideally check for a valid login using a session and setting the value of an index (such as $_SESSION["id"]) to a value that is unique to that account (usually, this is their database ID).
Edit: after reading the comments on the OP, you would have to make sure the session cookie was on any device that was logged in before making the request
Do not take a value: true field to be a login, as this is a security vulnerability.
I think you are mixing (perhaps on purpose) between passing information to the REST api using the URI and authorizing access to the specific server with http simple Authentication.
HTTP authentication can also be used to handle users, but It wouldn't be a very good choice (as elobrated in other answers). users, sessions, security tokens etc should be handled by the app logic while api access can also be safe guarded by the server (with http simple or digest security, NTLM, IP filtering or whatever). letting the web server take some of the security burden/seperating concerns/some kind of testing site/etc'.
an example scenerio is handling http security to protected server access in a Testing zone server, while the app REST api would accept and handle different users, tokens, permission levels etc to everyone who passed the server security checks.
look for this question for more reference
Question 1: Why use the HTTP Authentication and headers? As as far as
I can tell, they are not offering me anything unless I am using them
incorrectly? Why not just pass the username and password in the data
param of the JS?
The query string is part of the URI. The URI is a resource identifier by REST, so it is part of the resource state. The identity, credentials, etc... of the user is part of the client state. Mixing the client state and the resource state by adding client state to the URI would be a violation of the stateless constraint of REST. The data part of other requests, like POST, PUT, DELETE is for describing resource representations, so you should not send auth data with it. Sending headers is the best approach and since HTTP has a dedicated Authorization header, you should use that.
Question 2: As stated earlier I have based my API design on the Cake
plugin above, but from what I can see they ALWAYS pass the username
and password with every request and then decide to use it or not if
the user is logged in. Is this correct? To me, it seems more likely
that authentication and requests for data should be handled
separately. Otherwise I would have to store the username and password
in my JavaScript somewhere so that I can send it with each request.
Your server should authenticate every request, in order to stay stateless. I am not sure about the logic of this lib, I think login is the wrong term to describe what happens, but from REST perspective the implementation details does not matter as long as it uses the HTTP standard properly, and the communication is stateless. The code has changed since you asked your question.
Question 3: How do I know if a user is logged in? I could set a
variable to true and then pass that as part of my JSON with every
request, but can a session work with an external device?
The server does not care whether the client is logged in, since it is client state. If you send a request that requires permissions, then you have to send the data necessary to authenticate the user.

Securing GET call

I have a file, caller.php, which takes a GET URI that specifies a value to search the database for. The data is then returned in JSON format using php.
I want to protect caller.php so that it is only accessible from another page, get.php, using an AJAX call.
What is the best way to go about this?
I want to protect caller.php so that it is only accessible from another page, get.php, using an AJAX call.
You can't. An AJAX call can be easily faked, as can its origin.
There is no reliable way for you on server side to tell whether a call is an Ajax one or not, nor where it came from.
You need to secure your Ajax resource the same way you would secure a normal page - e.g. through an authorization system like a user login, etcetera.
Without such an authorization system in place, you have to assume that everyone can access the URL.
You could check the session to see if the call is authorized or not. AJAX requests will send you the PHP session cookie. This assumes that caller.php is secured by some kind of user login system that uses sessions

proper way to craft an ajax call with php and auth

From a security standpoint, can someone give me a step-by-step (but very simple) path to securing an ajax call when logged in to PHP?
Example:
on the php page, there is a session id given to the logged in user.
the session id is placed dynamically into the javascript before pushing the page to the client.
the client clicks a "submit" button which sends the data (including the session id) back to the php processing page.
the php processing page confirms the session id, performs the task, and sends back data
I'm stuck on how (and whether) the session data should be secured before sending it through an ajax request. I'm not building a bank here, but i'm concerned about so many ajax calls going to "open-ended" php pages that can just accept requests from anywhere (given that sources can be spoofed).
PHP can get the session data without you having to send a session ID via javascript. Just use the $_SESSION variable. If you want to check if a session exists you can just do
if(isset($_SESSION['some_val'))
//do work son.
You'll need to use JavaScript to asynchronously pass user input back to the server, but not to keep track of a session.
Don't send your session data with javascript.
You don't need to (in most cases).
Just post the data with javascript and let PHP retrieve the session data from... the session.
Depends on how you setup your session data.
One simple example would be you have a session called username.
When PHP gets the request from javascript you can do: $_SESSION['username'] to retrieve the sessiondata.
This is a very simple example just to show how it can be done.
As noted above, you don't need to send any session identifiers out with your javascript, to the server an AJAX request is the same as any other request and it will know your session just fine. So basically, just don't worry about it, it's already taken care of.
It's another part of your question that worries me.
i'm concerned about so many ajax calls going to "open-ended" php pages that can just accept requests from anywhere
It worries me too; you shouldn't have any "open-ended" PHP pages hanging around at all. Every public .php script should have authentication and authorisation done. The easiest and most maintainable way to achieve this, IMHO, is to have a single controller script (e.g. index.php) that does authentication and authorisation then sends the request to an appropriate controller. Aside from this controller, all other scripts should be outside the document root so that they cannot be called directly.
This means that you only ever have to worry about authentication and authorisation in one place; if you need to change it, it only changes in one place. It means you don't need to worry about accidentally leaving some executable stuff in some library PHP file that's not meant to be called directly. It means you don't need to shag around with mod_rewrite rules trying to protect .php files that shouldn't be in the doc root at all.

Categories