What's the best practice for making sure that certain ajax calls to certain pages are only accepted from authenticated users?
For example:
Let's say that I have a main page called blog.php (I know, creativity abounds). Let's also say that there is a page called delete.php which looks for the parameter post_id and then deletes some entry from a database.
In this very contrived example, there's some mechanism on blog.php which sends a request via ajax to delete.php to delete an entry.
Now this mechanism is only going to be available to authenticated users on blog.php. But what's to stop someone from just calling delete.php with a bunch of random numbers and deleting everything in site?
I did a quick test where I set a session variable in blog.php and then did an ajax call to delete.php to return if the session variable was set or not (it wasn't).
What's the accepted way to handle this sort of thing?
OK. I must have been crazy the first time I tried this.
I just did another test like the one I described above and it worked perfectly.
You were correct in trying to use session variables. Once your user authenticates, you should store that information in their session so that each subsequent page view will see that. Make sure you are calling session_start() on both pages (blog.php and delete.php) before accessing $_SESSION. Also make sure you have cookies enabled -- and if not, you should pass an additional parameter in the query string, usually PHPSESSID=<session_id()>.
It is not recommended that you rely on sessions for authentication without taking additional actions.
Read more on.
Related
There seem to be two principle ways of setting out a login system with PHP from the code I have studied as a beginner. I would like to know which is the "better" way to do it.
The first way calls session_start() in the header of every page, regardless of whether the user is logged in or not. The login script when called adds variables via $_SESSION. If the variables match the Users table then the user is logged in and gains access to the login area.
The second way first calls session_start() in the login script, and then in every further page within the user area.
Given that session_start() needs to be called to create or resume sessions, is best practice simply to put it in the header and forget about it?
OR
Should session_start() be called for the first time in the login script?
What are the implications of this decision?
The first way calls session_start() in the header of every page, regardless of whether the user is logged in or not.
This is ideally the best option for a number of reasons.
Maybe additional functionality can be added for security (or other reasons) from the very start. For example, maybe you could have some blocked IP addresses which you do not want to access your website, or you could use the session for gaining statistics.
So maybe you want to see where a person was redirected from to get to a certain page, even when they are not logged in.
Overall it helps to develop easier session management for security reasons and develop statistic functions.
I am using Code Igniter and I am implementing a remember user functionality.
Basically, from another stack overflow post, I implemented this the right way where I generate a random string for that user, save it in the database AND in a cookie. On site load, I check for that cookie, if that cookie is found I check it in the database. If it is found in the database then recrease the session for that user.
The problem I am having is when I load the site. I am getting the value of the cookie and I am also getting the correct response from the AJAX call. However, I have to click on a link in order for the session to get recreated (such as menu is displayed for logged in user and so on).
I am thinking that I am recreating the session AFTER the index method of the main controller is called. How can I get around this in Code Igniter? Where can I put this code which preferably gets run first thing on every page? As for instance I also want to recreate the session if the user enters the site's contact us page instead of the home page.
Many thanks in advance.
CodeIgniter allows the developer to create hooks which are called at different moments before the controller method is called.
Here is a short description of how to use hooks:
http://codeigniter.com/user_guide/general/hooks.html
If you want to access the session, I would recommend to use a post_controller_constructor hook, which is called after the controller constructor is executed, but before the action method is called. ( access the CI session in a pre controller codeigniter hook )
In light of my recent issue (PHP - Session lost/emptied on form post), the session ID almost by random regenerates itself upon a form being posted (login -> add item to basket OR add item to basket -> login), resulting in the session data being lost. A work around was brought to light that I could pass the session ID as a hidden input to force the session ID to maintain itself. Is this a practical fix? And would this open me up to any vulnerabilities?
Please note that my website is run on a shared server.
It doesn't affect the level of your security. The session ID is stored as a cookie on the user's browser and you propose saving it in the HTML source. Either way, the end user or a malicious entity using a network sniffer will be able to access this data. So you can use it if it makes your job easier.
I'll take a stab in the dark and guess that when you're submitting the form to a different subdomain, i.e. you're on http://www.example.com, and you're submitting to https://secure.example.com or the like.
If so, you need to make sure that the session cookie domain is set to use all subdomains of your website, not just your current one. You can check that with:
ini_get('session.cookie_domain');
// if this outputs something like "www.example.com" and you're submitting to
// "somethingelse.example.com", here's your problem.
If it's not set properly, you can set it either in php.ini or in your scripts:
ini_set('session.cookie_domain', '.example.com'); // or...
session_set_cookie_params(ini_get('session.cookie_lifetime'), ini_get('session.cookie_path'), '.example.com');
session_start();
... alternatively, you can just make sure that you're using the same subdomain when you submit the form as there's rarely a good reason to use a different one in this context.
Or your problem could be completely unrelated. Worth checking out in any case.
But, as #Kaustubh Karkare said, the security of passing session variables through your form is identical to passing them through cookies. And as for practicality, it's a perfectly reasonable, if not often used, way to pass session ids around.
Instead of posting it, go to your action page from your form and use this
<?php
//let's start the session
session_start();
$_SESSION['whateveryouwanttocallit'] = session_id()
?>
So basically don't post it at all....
You can check it by the following:
<?php print_r($_SESSION)?>
And can confirm it to: <?php echo session_id()?>
In answer to your question however, this is not a good work around.
By posting a session id to your session, you're just creating a duplicate of the information and naming it whatever you want, the session ID is already in your session.
Also, if you're intending to use your session ID in a hidden input as a form of cookie to ensure they information on that user isn't lost, the problems will be:
The session with this newly created session id will also get wiped.
Even if it stayed, the session id will have been regenerated and so be a different string.
I have designed a website which uses AJAX. I have a PHP page named store.php which accepts data sent by POST method and stores in the database.
How do I implement authentication into store.php? I only want a user logged into my site to use store.php.
Currently I am using htaccess to redirect the requests for store.php but I don't think that is a good solution.
Any AJAX Call to a Server Script will still include the session id in the request. If you are implementing sessions in your site, then start the session and you will be able to see session variables for the currently logged in user.
Store a token associated with the user in your database. Make sure that the token will be unique and not guessable. Also store the same token in a hidden form field so that it gets posted back to the page. Ensure on the server that the token is present in the posted form values and check that it is valid.
The security of Ajax requests is not a simple matter. They can be susceptible to man-in-the-middle attacks and replay attacks, to name a few. I'd recommend reading this book: http://www.amazon.com/Ajax-Security-Billy-Hoffman/dp/0321491939. It will give you lots of good information on the subject.
As for your question, specifically: once your PHP session has been set up, those session cookies will apply to Ajax requests as well.
What you are looking for is a persistent state for the user. The best way to implement this in PHP is to utilize sessions.
There is great documentation on it: http://www.php.net/manual/en/book.session.php
I normally just include the exact same code I use to authenticate on the rest of my site in the ajax-called page. I use SESSION to hold a sessionID, and the rest is handled in my DB. I usually end up just adding a line like this..
require_once('loginProcedures.php');
//Login Authentication takes place here using SESSION ID
if (!$me['validLogin']) die("Invalid Authentication");
//perform actions and echo your result for a valid login.
If I had a user logged onto my site, having his id stored in $_SESSION, and from his browser he clicked a 'Save' button which would make an AJAX request to the server. Will his $_SESSION and cookies be retained in this request, and can I safely rely on the id being present in the $_SESSION?
The answer is yes:
Sessions are maintained server-side. As far as the server is concerned, there is no difference between an AJAX request and a regular page request. They are both HTTP requests, and they both contain cookie information in the header in the same way.
From the client side, the same cookies will always be sent to the server whether it's a regular request or an AJAX request. The Javascript code does not need to do anything special or even to be aware of this happening, it just works the same as it does with regular requests.
If the PHP file the AJAX requests has a session_start() the session info will be retained. (baring the requests are within the same domain)
What you're really getting at is: are cookies sent to with the AJAX request? Assuming the AJAX request is to the same domain (or within the domain constraints of the cookie), the answer is yes. So AJAX requests back to the same server do retain the same session info (assuming the called scripts issue a session_start() as per any other PHP script wanting access to session information).
Well, not always. Using cookies, you are good. But the "can I safely rely on the id being present" urged me to extend the discussion with an important point (mostly for reference, as the visitor count of this page seems quite high).
PHP can be configured to maintain sessions by URL-rewriting, instead of cookies. (How it's good or bad (<-- see e.g. the topmost comment there) is a separate question, let's now stick to the current one, with just one side-note: the most prominent issue with URL-based sessions -- the blatant visibility of the naked session ID -- is not an issue with internal Ajax calls; but then, if it's turned on for Ajax, it's turned on for the rest of the site, too, so there...)
In case of URL-rewriting (cookieless) sessions, Ajax calls must take care of it themselves that their request URLs are properly crafted. (Or you can roll your own custom solution. You can even resort to maintaining sessions on the client side, in less demanding cases.) The point is the explicit care needed for session continuity, if not using cookies:
If the Ajax calls just extract URLs verbatim from the HTML (as received from PHP), that should be OK, as they are already cooked (umm, cookified).
If they need to assemble request URIs themselves, the session ID needs to be added to the URL manually. (Check here, or the page sources generated by PHP (with URL-rewriting on) to see how to do it.)
From OWASP.org:
Effectively, the web application can use both mechanisms, cookies or
URL parameters, or even switch from one to the other (automatic URL
rewriting) if certain conditions are met (for example, the existence
of web clients without cookies support or when cookies are not
accepted due to user privacy concerns).
From a Ruby-forum post:
When using php with cookies, the session ID will automatically be sent in the request headers even for Ajax XMLHttpRequests. If you
use or allow URL-based php sessions, you'll have to add the session id
to every Ajax request url.
It is very important that AJAX requests retain session. The easiest example is when you try to do an AJAX request for the admin panel, let's say. Of course that you will protect the page that you make the request to, not to accessible by others who don't have the session you get after administrator login.
Makes sense?
One thing to watch out for though, particularly if you are using a framework, is to check if the application is regenerating session ids between requests - anything that depends explicitly on the session id will run into problems, although obviously the rest of the data in the session will unaffected.
If the application is regenerating session ids like this then you can end up with a situation where an ajax request in effect invalidates / replaces the session id in the requesting page.
That's what frameworks do, e.g. if you initialize session in Front Controller or boostrap script, you won't have to care about it's initalization either for page controllers or ajax controllers. PHP frameworks are not a panacea, but they do so many useful things like this!
put your session() auth in all server side pages accepting an ajax request:
if(require_once("auth.php")) {
//run json code
}
// do nothing otherwise
that's about the only way I've ever done it.