I am attempting to integrate an existing payment platform into my webshop. After making a succesful transaction, the payment platform sends a request to an URL in my application with the transaction ID included in the query parameters.
However, I need to do some post-processing like sending an order confirmation, etc. In order to do this, I'd need access to the user's session, since a lot of order-related information is stored there. To do this, I include the session_id in the intial request XML and do the following after the transaction is complete:
$sessionId = 'foo'; // the sessionId is succesfully retrieved from the XML response
session_id($sessionId);
session_start();
The above code works fine, but $_SESSION is still empty. Am I overlooking something or this simply not possible?
EDIT:
Thanks for all the answers. The problem has not been solved yet. As said, the strange thing is that I can succesfully start a new session using the session_id that belongs to the user that placed the order. Any other ideas?
Not really what you ask for, but don't you need to persist the order into database before you send the customer to the payment-service? It's better to rely on persisted data in your post-processing of the order when you receive the confirmation of the payment.
Relying on sessions is not reliable since you will have no idea on how long this confirmation will take (usually it's instant, but in rare cases this will have a delay).
Also, in the event of your webserver restarting during this time span, will make you lose relevant data.
A third issue is if you have a load-balancing solution, with individual session-managment (very common) then you will have no guarantee that the payment-server and your client will reach the same webserver (since stickiness is usually source-ip based).
I will venture to guess that since domains are different from where the session is set to where you are trying to read it, php is playing it safe and not retrieving session data set by a different domain. It does so in an effort to preserve security in case somebody were to guess session ID and hijack the data.
Workaround for this, assuming the exchange happens on the same physical disk, is to temporary write order data to a serialized (and possibly encrypted depending on wether or not full credit card number is being tracked, which is a whole another story) file that once read by the receiving end is promptly removed.
In essence all that does is duplicates the functionality that you are trying to get out of sessions without annoying security side-effects.
Many thanks for all the replies.
Smazurov's answer got me thinking and made me overlook my PHP configuration once more.
PHP's default behaviour is not to encrypt the session-related data, which should make it possible to read out the session data after restarting an old session from another client. However, I use Suhosin to patch and prevent some security issues. Suhosin's default behaviour is to encrypt session data based on the User Agent, making it a lot harder to read out other people's sessions.
This was also the cause of my problems; disabling this behaviour has solved the issue.
Make sure you're closing the current session before you attempt to start the new one. So you should be doing:
$id = 'abc123';
session_write_close();
session_id($id);
session_start();
Dirty, but has worked for me:
Tell the payment gateway to use
http://yourdomain.com/callbackurl.php?PHPSESSID=SESSIONIDHERE
PHP uses that method of passing a session around itself if you set certain config vars (session.use_trans_sid), and it seems to work even if PHP has been told not to do that. Its certainly always worked for me.
Edit:
Your problem may be that you have session.auto_start set to true - so the session is starting automatically using whatever ID it generates, before your code runs.
How about do it in another PHP page, and you do a iframe include / redirect user to the second page?
I'm not sure the exact length of time between your transaction and your check; but it certainly seems that your session cookie has expired. Sessions expire usually after 45 minutes or so by default. This is to free up more uniqid's for php to use and prevent potential session hijacking.
I'm not sure if you have a custom session handler and whether it's stored in the database but guessing from your posts and comments on this page I would assume it is stored in server side cookies.
Now the solution to your problem, would be to bite the bullet and store the necessary data in the database and access it via the session id, even if it means creating another table to sit along side your orders table.
If however you are doing the action immediately then the other explanation is that either the user logged out or committed an action which destroyed their session (removing the server side cookie).
You will see these cookies in your servers /tmp folder, try have a look for your cookie, it should be named 'sess' + $session_id.
Related
I'm storing actively changing data in user sessions, which requires consistency for the user even if they log in with another browser or PC and end up with a new PHP-generated session_id
To counter this issue (and for other reasons) I store a username and session_id data pair in a maintained dedicated database, then after session_start() do something like (simplified):
$saved_sessid=$db->querySingle("SELECT sessid FROM sessions WHERE user = '".$user."'");
if(!empty($saved_sessid)){
session_write_close();//dump newly generated session
session_id($saved_sessid);//apply database-saved session_id
session_start();//launch the already existing user session
}
Would this work as might be expected to make sure a particular user (based on logged in username) only has a particular PHP session or might it cause any unforseen issues, potentially security-related ones? I've been unable to find similar cases or test it reliably enough on my own and could do with some more experienced input
as Xuzrus and nogad commented, essentially answering the "question", your method would work without any added unforeseen consequences, at least none directly. any data stored in the dropped session between session_start() and session_write_close() will of course be lost (i'm guessing you expected that), but the new user instance will then be "shared" with the "saved" session's data, with both "access points" processed in queue by php normally as if simply different pages
if you're using multiple instances of php (multithreading) i'm not sure though, i think php locking the session files in /tmp will make any risk of both clients wanting to use the session at the same time wait in line for ongoing processing to complete, but need confirmation on that
We want to use sessions instead of cookies for keeping track of a few things. However, when I close my browser, and I reopen a page to echo a session var, it doesn't exist (which is how it is suppose to be). Is it possible to prevent this from happening with some magic or anything?
This is not a duplicate question, all I see are people wanting to destroy sessions, I want to do the opposite and retain the session for as long as possible.
Any knowledge would be appreciated.
The right way of doing this is with a database, you can mimic or control php sessions and store them in a database instead of in a file ( as normal ). Then once you have control of the data you can base renewing session via the ip address or better yet by login.
So say a user logs in and then you need to store some data, you store that in the session but php will store it in your database table ( when configured correctly ). Latter the user comes back, initially any visitor would get a fresh session, however once they login you would be able to retrieve the past session they had. You generally don't have much control on if or when a client will delete expired cookies.
This topic is too extensive to put just a few pieces of example code but I did find this small article on the topic.
http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/
The guts of it is to use this function, session_set_save_handler
http://php.net/manual/en/function.session-set-save-handler.php
Once you have control of the data you can do whatever you want, however I would caution you about relying only on the IP address and it would be preferable to use a login system for something like this to prevent serving the session up to the wrong visitor.
You cannot reliably control what happens on the client side, even using a separate cookie would not be reliable and would have the disadvantage of storing data on the client where it could be accessed instead of keeping it on your server. Sessions are controlled by cookies but the data in them remains on your server, the cookie just identifies the client.
As a side note, I personally dislike using sessions at all. It may be possible to store what you need in the url, then it can be bookmarked. The classic example would be input for a search form ( via $_GET ) or for paging purposes. There is nothing wrong with doing this if it's not secure data. The problem with sessions is if the data is for a page such as my "classic example" or for paging you get only one session, so you would only be able to have one set of search data at a time, in the url you could have several sets of search data open at once. That said it does largely depend on what you need to save or persist.
Reset the session cookie manually.
$lifetime=60*60; // duration in seconds
session_start();
setcookie(session_name(),session_id(),time()+$lifetime);
You can use session.gc_maxlifetime and session_set_cookie_params, i.e.:
// server should keep session data for AT LEAST 1 Year
ini_set('session.gc_maxlifetime', 3600 * 24 * 365);
// each client should remember their session id for EXACTLY 1 Year
session_set_cookie_params(3600 * 24 * 365);
session_start();
Note:
You can also change the session options globally by editing php.ini -
Session configuration options
PHP sessions use session cookies. Browsers have their own ways of dealing with them but they all consider them to be trash if you close the browser.
Session cookies are not and can not be made persistent. If you need persistent cookies, just use a regular cookie to save a user identification code that your server would recognize, and save their session information in a database or flat file indexed on that id code.
Note that accumulating sessions on the server progressively causes important performance and security concerns.
Note on other answers: All of them mention ways to extend the session cookie expiration which will not overcome the regular behavior when you close your browser window.
I know there are hundreds of these questions but what I am asking however is slightly different.
When the user logs in I would like to get all their data from each table in a database and store it in a session variable (obviously not sensative data such as encrypted password/salts etc basically data that would be useless or have no value to a hacker!!), and whilst the user uses the website the relevant data stored in the session will be used as opposed to accessing the database everytime. Moreover when the data is changed or added this will be written or added to the session file, and upon a major action such as "saving" or "loggin out" the new/changed data will be written to the database.
The reason I wish to do this is simply for efficieny, I want my application to not only be fast but less resource consuming. I am no expert on either which may explain why my idea makes no differnece or is more resource intensive.
If there is an alternative to my solution please let me know or if there is something to improve on my solution I will be glad to hear it.
Thank you.
My application is using PHP and mysql.
If any of these don't apply to your app, then please ignore. In general, I'm against using sessions as caches (especially if anything in the session is going to be written back to the DB). Here's why.
Editing the session requires a request from the user. Editing a php session outside of the request-response cycle is very difficult. So if a user Alice makes a change which affects Bob, you have no way to dirty Bob's cache
You can't assume users will log out. They may just leave so you have to deal with saving info if the session times out. Again, this is difficult outside of the request-response cycle and you can't exactly leave session files lying around forever until the user comes back (php will gc them by default)
If the user requires authentication, you're storing private information in the session. Some users may not be happy about that. More importantly, a hacker could imploy that private information to conduct a social engineering attack against the end-user.
Mallory (a hacker) might not be able to use the information you put in the session, but she can poison it (ie. cache poisoning), thereby causing all sorts of problems when you write your cache to your permanent storage. Sessions are easier to poison then something like redis or memcache.
TL;DR Lots of considerations when using a session cache. My recommendation is redis/memcache.
You can also go for local-storage in HTML5, check The Guide and THE PAST, PRESENT & FUTURE OF LOCAL STORAGE FOR WEB APPLICATIONS
Local Storage in HTML5 actually uses your browsers sqlite database that works as cookies but it stores data permanently to your browser
unless someone by force remove the data from the browser finding the data files
Or if someone remove/uninstall browser completely,
or if someone uses the application in private/incognito mode of the browser,
What you need to do
Copy the schema for required tables and for required columns and update data at a regular interval
you dont have to worry about user's state, you only have to update the complete data from the localStorage to mysql Server (and from the mysql server to localStorage if required) every time user backs to your application and keep updating the data at regular interval
Now this is turning out to be more of localStorage but I think this is one of the best solution available for me.
redis is a good solution if it is available for you (sometimes developers can't install external modules for some reason) what I would do is either go with your Session approach but with encoded/encrypted and serialized data. Or, which I really prefer is to use HTML5 data properties such as:
<someElement id="someId" data-x="HiX" data-y="Hi-Y" />
which BTW works fine with all browsers even with IE6 but with some tweaks, specially if your application uses jquery and ajax. this would really be handful.
You need to use Memcache for this kind of work. To solve the problem of keeping the updated data everywhere you can create functions for fetching the data, for example when the user logs in you, authenticate the user and after that insert all the user data into the memcache with unique keys like :-
USER_ID_USERNAME for user's username
USER_ID_NAME for user's name
etc...
Now create some more functions to fetch all this data whenever you need it. For ex
function getName($user_id){
if(Memcache::get($user_id."_name"){
return Memcache::get($user_id."_name");
} else {
//Call another function which will fetch the data from the DB and store it in the cache
}
}
You will need to create functions to fetch every kind of data related to the user. And as you said you want to update this data on some major event. You can try updating the data using CRON or something like that, because as tazer84 mentioned users may never log out.
I also use what the OP described to avoid calls to db. For example, when a user logs-in, i have a "welcome-tip" on their control panel like
Welcome, <USERS NAME HERE>
If i stored only his user_id on $_SESSION then in every pageview i would have to retrieve his information from the database just to have his name available, like SELECT user_name FROM users WHERE user_id = $_SESSION['user']['user_id'] So to avoid this, i store some of his information in $_SESSION.
Be careful! When there is a change on data, you must modify the data in db and if successfull also modify the $_SESSION.
In my example, when a user edits his name (which i also store in $_SESSION so i can use it to welcome-tip), i do something like:
If (UpdateCurrentUserData($new_data)) // this is the function that modifies the db
{
$_SESSION['user']['user_name']=$new_data['user_name']; // update session also!
}
Attention to:
session.gc_maxlifetime in your php.ini
This value says how much time the $_SESSION is protected from being erased by the garbage collector (the file that exists on your disk in which the $_SESSION data are stored)
If you set this very low, users may start getting logged-out unexpectedly if they are idle more than this amount of time because garbage collector will delete their session file too quickly
if you set this very high, you may end up with lots of unused $_SESSION files of users that have left your website a long time ago.
also i must add that gc_maxlifetime works together with session.gc_probability where in general you need lower probability for high-traffic websites and bigger probability for lower traffic since for each pageview there is a session.gc_probability that garbage collector will be activated.
A nice more detailed explanation here http://www.appnovation.com/blog/session-garbage-collection-php
I know this sounds stupid but ....
If ur data is not sensitive the best way to make it accessible faster is to store it in hidden variables inside the forms itself. You can save comma separated or values in an array.
I'm working on a demo tool (PHP, jQuery, XHTML), so far so well, except that I have an issue, I need to save certain information temporarily and I'm doing it through cookies, however the cookies' limit in Apache is 4Kb and I have no longer space within the cookie, so I'm wondering how can I keep saving inside the cookie without a problem if I still don't want to send any information to databases nor text files.
I don't know if maybe by using path or other domain I might be able to work things out.
I would really appreciate any help you can provide me :).
Sessions are like Cookies but they just give the client a unique ID ("session ID") and keep the rest of the data on the server.
Of course this is stored within a database or file but that's totally transparent to you, there's no messing about with SQL queries or file reads or anything.
You just need to replace all $_COOKIE with $_SESSION and put session_start(); at the top of your code: http://www.tizag.com/phpT/phpsessions.php
One downside though: PHP sets all session cookies with no timeout, which the browser usually treats as "delete this cookie whenever the browser is closed". See this question for workarounds: How do I expire a PHP session after 30 minutes?
First you should consider if saving that much data in a cookie is really needed. Maybe you can compress your information or just dont need all of it?
The reason is: the cookie is send at every request to the server (this might more then 1). If you serve images from the same domain, you may get over 20 requests each is sending this large cookie. Assuming your cookie holds 5kb of data, you have 100kb just to loop your information through.
see: http://developer.yahoo.com/performance/rules.html#cookie_size
if you need your information just for the current session, why not saving it into a session var (or memcache etc.pp.)?
Maybe its okay if you just save an id in the cookie and if nothing to this id is in your session, you load it from database and save it in the session. so you have a one-time access per session.
Maybe its better if you provide some more background information.
You could create multiple cookies, but it's a bad idea. The cookies will go across the wire with every request. Consider putting your session information in a database or cache tier.
I guess you could store non-sensitive information with a DOM element. If you are using jQuery you can use .data() - http://api.jquery.com/data/
However, after the page does a full reload its gone.
There's a bug, which we can not replicate, which involves users in one specific region of our enterprise customers swapping. For example, a user logs in as themselves on the login page, and when arriving at the home, they are another user.
It seems like accidental session hijacking, here are the clues:
cakephp security is set to low (this only means the cookie doesn't
rewrite every page load, and the the cookie does not do a user agent
check )
our cookie is set to not care about subdomains (.example.com instead of example.com)
enterprises users areredirected using a 302 if they login to the wrong area (should we use 303?)
there was a 301 accidentally sent out, but users are able to replicate
all the affected users are behind a single router, sharing internet via Sprint MPLS
all the affected users may be using computers issued by the customer
their IT claim there is no proxy cache, and no remote VPN access, yet they claim to be able to replicate the issue from home computers and off the network.
Since we can not replicate the issue in any way, we can only assume that the issue is specific to their network.
How can we prove that their network/computers are causing the session swapping? Or, what configuration on our end could be causing this, when no other users experience this issue?
[edits/updates]
Responding to some direction provided by comment - our traffic is not large enough to send duplicate IDs. (the statistically probability is too low to see what we've seen the customer replicate ).
see also:
Zend Framework Session swapping issue
why is php generating the same session ids everytime in test environment (WAMP)?
Update:
We use FCGI, and apparrently mod_php is required to understand x_forwarded_for
What's wrong with this function call?
This may be a problem with improper session invalidation in the log out. please ensure that all the variables in the session are properly terminated or explicitly null terminate every object in the session and then invalidate the session.
The second reason may be the use of variables check for static variables in your code. improper use of static variables may also cause this intermittent issue.
Use logger to log session id mapped to the user ids that can narrow down your problem and help you understand what exactly happening.
Invalidating the existing session in login action and creating a new session and copying content to the new session will help a lot.
First, do not assume the customer is at fault. It may an issue on their side or yours. Do not make an assumption as to which before testing.
Regardless of who's fault it is, the burden is on you to fix or help fix it.
First, having one user become another is often the result of a Session ID problem. The security level you have set in Cake does not regenerate the Session ID for every request.
I would start by logging the $session->id() as a user both inside and outside your local network. Then compare to see if the session id is ever the same or ever an empty string. One fix for this is to generate a unique id for each user.
If the Session ID is unique for each instance, you may want to test it under load.
The point is to test first and make conclusions based upon findings, not speculation.