I have an application that uses several different forms to perform various actions. Some of the forms access data from submissions in other forms.
For example: a user places a new order on one form and adds a new item in another, the items can be added to orders.
So this leads to the possibility that a user may be adding an order and realize that an item must be added first. So naturally a new tab will be opened to do so instead of losing the information added to the order.
Currently I have a $_SESSION['form'] variable to let the form handling script know which function to use after form submission. The problem is that with multiple tabs open, this value will get overwritten by the last opened tab. I have had a couple ideas on how to handle this but so far nothing ideal.
Idea one: use a hash value to identify different page loads and send the hash as a hidden field
$hash = $_POST['hash'];
$form = $_SESSION[$hash]['form'];
Issue: session overloading. This method will make a new session value each time a form is loaded to uniquely identify the form submission. I could unset the value upon submission, but what if a form page is loaded and never submit, or if the page is refreshed. I would prefer to keep the session as light weight as possible.
Idea two: use AJAX to set the $_SESSION['form'] value upon clicking submit
Issue: users that do not use JS. I would like to be able to continue providing support to users that prefer to disable JS if possible, although this method seems like it could be a bit better. However, I am unsure whether there could be browser compatibility issues here.
Idea three: create a hash id for each window
Issue: PHP can't distinguish between browser tabs. This would be the most ideal by far.
Idea four: split the form handling script into multiple files, thus removing the need for a value to select which function to use.
Issue: inconvenient, but I am open to this idea if it proves to be the only real method to handle this issue. It would require a fair bit of re-structuring though.
Any ideas on how to securely manage different tabs and session information in PHP?
This is just my opinion, but I would use idea #1-- each time the form loads, give it a random hash (just md5 of the time() + random number would suffice), and then keep up with those hashes like they are unique window identifiers.
Yes, it might bloat your session a little, but if it doesn't slow down the user's experience, I wouldn't worry about it. If it really bothers you, you can keep track of how many window ID's you've created for the user (in the session) and limit it to 100 or 1000. This would prevent a malicious user from writing a script to open millions of windows.
Remember, when the user's session is destroyed (by logging out/closing the browser), all those hashes are gone too. And if you were REALLY feeling industrious, you could have a system of expiration on hashes. Like, after 2 hours they will be removed from the session.
But honestly-- if it were me, I'd just leave them in the session and not worry about it.
Just my 2 cents,
Richard
Related
I'm doing research on internet behavior. The participants of my study are asked to fill in a questionnaire.
What they don't know is that this questionnaire consists of an infinite series of forms:
whenever they submit one form, they are presented with another one. From their perspective, the questionnaire never ends. It is filled from an array containing thousands of random questions from old studies.
I want to test, how long different users keep going.
I have two options:
Save each form to the database, when it is submitted. Each successive form UPDATEs the same data record with the current page count. This is easy, and I know how to do it.
No data is saved while the user performs the task. The current page count is saved from the SESSION, when the user abandons the task, i.e. when he closes the browser window.
How do I do this? How can I tell PHP to save a $_SESSION variable, when the user closes the browser? Is this even possible in a reliable way, i.e. the solution does not rely on functionality that is not available in all browsers, such as onbeforeunload (which does not work in Opera)?
$_SESSION is profoundly unfit for the task you want to perform. It is designed (and works well enough) as a vehicle to introduce state into an application relying on the stateless HTTP protocol, not to do something on the absence of further HTTP requests.
When relying on a server-sided mechanism, one of the main points to consider is, that session cleanup can happen concurrently, which is not a problem for dumb destruction of a session, but will hand you problems if you want to do something else.
Relying on client-sided code is much worse: What if the user doesn't close the browser, but it crashes? Or the user is on mobile and drives into a tunnel?
My recommendation would be, to understand, that your problem at hand is not one of session keeping, but one of analytics. This would argue heavily into inserting one row per page into a database:
Do your analytics a posteriori: Are you sure, you already know all questions, you want to ask? Only raw data is able to allow you to change or append to your research problem.
Including a timestamp in the rows will allow you to ask for correlation between response time and total time ... was the user doing your survey just as a side-distraction or was he concentrated on it?
Basically you create a specialized log, that can be analyzed by lots of tools - it being in the DB making it easier to query it.
What I do now is save the current state of the session into a database with session_encode() after each form is sent. Before I show any user any page, I check if there is a session with isset($_SESSION['whatever']). If there is none, I check in the database, if a session was stored for this user (they are identified through a login, all this takes place on a site that requires registration). If a session was stored, I drag it from the database and resore it with session_decode(). If there is none, I create a new one. Now, when the browser was closed, the user gets returned to the last page with all variables (of all previous pages) prefilled, including current error messages ("Please choose ..."), if there where any.
I started writing a web application that stores certain user information in the $_SESSION variable. Usual stuff - user_id, username etc.
I then started using the variables to store certain navigation information. For instance, $_SESSION['organisation_id'] so that wherever the user is in the application, I can easily add 'organisation_id' to any table without having to parse 'organisation_id' across every page request (eg. index.php?organisation_id=456&var2=6 or anotherpage.php?organisation_id=456& etc)
All hunky dory until a user opens a new tab and starts navigating to another organisation so hence creating a new $_SESSION['organisation_id'] value and creating an epic fail on the original tab.
The only solution I can think of is to go back to putting organisation_id into every form and navigation element within the application but yeesh, I'm thinking there must be a more elegant solution.
Normally, I find everything I need on StackOverflow but the answer to this question still eludes me!
"The only solution i can think of is to go back to putting organisation_id into every form and navigation element within the application but yeesh, i'm thinking there must be a more elegant solution."
No there isn't.
Maybe you can check if $_SESSION['organisation_id'] exist, and if so you can write new variable in session with different name, and so one.
Currently there is no way to solve the problem. But to avoid a similar task in the future, I would suggest split up all your files into different includes.
So even if you have to add a couple of variables to the entire site, you could modify 1 file and get it done than doing the whole thing again.
I think this is a logic problem. The session represents a state for the user. This is because HTTP is a stateless protocol in it's essence (it don't know who is who, just undersdants requests and responses).
So the organization_id is a state. If a user can login to just one organization, you just store this in the session var like you did and use it. If the user logs out and in again with another organization_id, it makes sense that only the last one remain available.
If your application has to support multiple organization_id's, you should reflect that logic in your session handling, saving an array of organization ids for instance (instead of just one). But then you have to change your application to allow the user to navigate from organization to organization, etc. There's no point in letting the user be in two organizations at once if the screen just shows one of them.
you can store the value into session during onblur of that username, etc and you can get it before you clicking the next tab
(i.e) using Jquery/Javascript u can get that value of username, etc while onblur and store it in session.
You can resolve this by simply moving the data you currently put into the $_SESSION array into a sub-array within $_SESSION, so that you can store multiple sets of data at once in the session.
It would end up looking a bit like this:
$_SESSION[organisations] = array(
'456' => array('organisationID'=>456, 'otherdata'=>'blah'),
'678' => array('organisationID'=>678, 'otherdata'=>'blah'),
...etc...
);
This will allow you to keep the data for multiple orgs in the session data at once, so you don't have to load all the data every time.
But yes, you will need to send the relevant organisationID with every request, so that your code knows which element of the session data to work with. You can't really work around that. Every request will need tell PHP which orgID to work with.
The down-sides here are that by storing all that data in the session, you're using a lot more memory for your session data, so if there's a chance that the user will browse a lot of organisations during a session, I would advise limiting the size of $_SESSION by dropping data that hasn't been used for a while.
The other down-side is that if this is a multi-user system, storing the data in session means that it will be unaware of any updates made by other users. If you were to load the data fresh from the database on every request, yes it would create more work for the DB, but it would ensure that the data given to the user was always up-to-date.
Good day,
I would like to know how to protect my website from ajax-spam. I'm looking to limit any ajax action per
users. Let's say 8 ajax-actions per minute.
An example of an action would be: a button to add/remove a blog posts "as my favorites".
Unless I'm wrong, I believe the best way would be using $_SESSION's variable and to avoid someone/a bot to clear
cookies to avoid my protection. I'm allowing ajax-functions only to logged-on users.
Using database would make my protection useless because it's the unwanted database's writes I'm trying to avoid.
I have to mention that I actually use PHP as server-language and jQuery to proceeds my ajax calls.
Thank you
Edit:
The sentense
... to protect my website ...
is confusing but it's not about cross-domain ajax.
Edit 2011-04-20:
I added a bounty of 50 to it.
Since you're only allowing AJAX actions to logged in users, this is really simple to solve.
Create a timestamp field for each account. You can do this in the database, or leverage Memcached, or alternatively use a flat file.
Each time the user makes a request through your AJAX interface, add the current timestamp to your records, and:
Check to make sure the last eight timestamps aren't all before one minute ago.
From there you can add additional magic, like tempbanning accounts that flagrantly violate the speed limit, or comparing the IPs of violators against blacklists of known spammers, et cetera.
Are you talking about specific ajax-spam to your site, or ajax-spam in general?
If the latter, you can use hashes to prevent auto-sending forms, i.e. write your hash() one-way function which takes string and makes sha1-checksum of it.
So that's how you use it:
// the page is a blog post #357
$id = 357;
$type = 'post';
$hash = hash($_SERVER['REMOTE_ADDR'].$type.$id);
Put that hash in hidden field which is not within the comment form or even hidden div, somewhere at the bottom of the page, and name it "control_hash" or something. Attach it's value to the ajax-request on form submit. When the form is received by the script, make a new hash from $_REQUEST data (excluding existing $control_hash) and check if they match.
If the form was submitted by bot, it won't have $control_hash, so it won't pass.
Yes, your idea in principle is good. Some things to consider though:
If you track the limits globally then you may run into the issue of a bot DoSing your server and preventing legitimate users from being able to use your "Favourite" button.
If you track the requests based on their IP then someone could use a bot network (multiple IPs) to get around your blocking. Depending on your site and what your preference is, perhaps limit based on a subnet of the IP.
Install and use Memcache to store and track the requests, particularly if you are going to be tracking based on the IP. This should be faster than using session variables (someone might correct me on this).
If you have access to the source code of the web-site, you can rewrite some of the javascript code that actually performs AJAX-request. I.e. your pages can have a hidden counter field, that is incremented every time a user clicks the button. And also you can have a timefield hidden on the page, in order to rate the frequency of clicks.
The idea is that you don't even have to send anything to the server at all - just check it on the client side inside the script. Of course, that will not help against the bots adressing directly to the server.
It really depends on the result of such a spam. If you just want to avoid writing to your database, all these check could end up taking more ressources than actually writing to the database.
Does the end justify the means?
You also have to judge what's the probability of such a spam. Most bots are not very smart and will miserably fail when there's some logging involved.
Just my 2 cents, the other answers are perfectly valid to avoid spam.
Buy more powerful hosting to be able serve requests, don't limit them.
8 requests per minute it's ridiculous.
Anyway, if requests are 'legal', you should find ways how to serve requests, not how to limit them. And if not 'legal' - then deny them without any 'time' limitations.
You can use a session field with a global variable holding the time of last ajax request. Since you want to allow 8 requests, make it an array of size 8 and check for the time differences. If it increases, (important) it might not always be a bot. give the user a chance with captcha or something similar. (a math problem maybe?)
once the captcha is validated, allow the next few posts etc..
But do make sure that you are checking for that particular session and user.
Kerin's answer is good, I just wanted to emphasize on captcha.
yes you need to use a function in every function views can interact, also, it should be in global library so you can use it anywhere.
if(is_logged_in())
{
// do you code here
}
while is_logged in is defined as follows
function is_logged_in($activated = TRUE)
{
return $this->ci->session->userdata('status') === ($activated ? STATUS_ACTIVATED : STATUS_NOT_ACTIVATED);
}
you should set the status session when user login successfully.
I have a form I am creating and I would like to send information, not just from the form itself (easy enough to do with $_POST), but also generated information that corresponds to form data but is not visible to the user.
I could create a hidden input to put the data in, but I wonder if there's a way to do it that doesn't seem so hackish :)
(it's to submit a number of items, some new and some edited, I have a variable that increments for the edited ones but not the existing ones, and I need to be able to separate them out on the other end)
You're trying to maintain state across HTTP requests...
In any case you'll have to create a temporary variable server side. Something in the $_SESSION variable. There's not safer place to put data, primarily because only the developer can access this variable.
The disadvantage of this approach is the developer will have to start maintaining sessions.
I see nothing particularly hackish in using hidden fields. If your concern is about security (you don't want that the end user is able to tamper with the data) you'll have to use some sort of persistent server-side storage such as a database or a PHP session. Whatever approach you choose, make sure your app doesn't break when the user opens several tabs.
Well, I have a new project, and I've not done anything like it before, but so far so good. I am in need of having to pass some data from one page to another, and there is no limit to the amount of data that gets passed.
At first, I was thinking of POST-ing it, and then when each page loads, just grab the POST data, and store it in an array, but to me that sounds a bit too over complicated or something for what I want to do.
Then I thought about HTML5 and localStorage, but since there is a limit on localStorage, and the fact that the majority of users browsers still don't support it yet (that is, the majority of my clients customers browsers), that's a big no no, at this point.
So, now I'm all out of ideas.
Here's what I'm trying to do, it sounds pretty simple to me, yet I can't figure out how to go about it:
On any given page, there are a probably over a hundred links, each link represents either a name of a product or information about a product, if they click on of these links, and then move off to another page, then the information about what product name they clicked on would follow them to that new page, and then the same thing happens on the new page, if they click on one of those links again, then new info will be added to existing information, and passed on to whatever new page they visit.
I guess you could say that it works almost exactly like a shopping cart, whereby if a user Adds to Cart, their Cart, and all data inside it follows them right to Checkout.
I'd appreciate any help at all?
You are looking for sessions. With the limitation that you shouldn't be storing unlimited amounts of data in a session file, either; better create a temporary file that is named after the session ID, or store the data in a database.
Alternatively, you can also implement a custom session handler.
Either way, Sessions are the standard way of persisting state across page requests for the same user.
You could store the data in a session, or even in a database table (if there truly is "no limit").
For more information on sessions, see Session Handling in the PHP online docs.
I think you really want to use a database for this purpose. Each page pulls the data out of the database as the user clicks through. I guarantee you that for a hundred or so objects from the database, the time to access the database from each new page is an order of magnitude smaller than the round trip HTTP time from the user's browser.
what you are looking for is php sessions.
Yes, for your purpose you should use sessions, I'm agree with others users.
But keep in mind that: sessions expire. If you were looking for a persistent solution, you can store your PHP objects (vars, array, object instances, etc...) using the serialization and unserialization. Using this method you can store your objects in plain text everywhere (eg. DBMS) and restore them at any time. If you're working with objects you can also use the magic methods __sleep() and __wake().