I'm writing a website where the user logs in through conventional means. The login creates session variables so the site knows if and who is logged in.
There are products on the site that sell through Stripe. For ease I'm using Stripe's payment links. So you click a link on my site, it then visits Stripe's site to enter card details, then back to mine on checkout success.
My question is this: Are the session variables guaranteed to stay through that diversion so the user is still logged in when their payment is successful and they've been to Stripe and back or should I pass the customer id, etc. through the payment process and recreate all the session variables again once they arrive on the success page?
Yes and no...
The important thing to remember is that HTTP is completely stateless - every request is completely independent of any previous ones. As far as the web server is concerned, every time the user loads a new page that's equivalent to them "going away and coming back". Sessions work by telling the browser to associate a cookie with a particular domain, and then using that cookie to recognise that two requests came from the same user. As long as that cookie is still there, it doesn't matter if the user has visited another site in between, or opened a new browser window, or whatever.
However, it's a good idea to plan for what will happen if the cookie isn't there when they come back: customers tend to get very annoyed if you take the payment but don't complete the order. Another scenario to consider is that the payment completes but for whatever reason the user doesn't get redirected back at the end of the payment process (I've had this happen with malfunctioning security software on the user's PC, for instance).
A good approach if you can manage it is therefore to create a "pending" order in your system, with all the details of who was logged in and what they were trying to buy. Then you have a single ID you can pass through Stripe and receive for a successful payment. If the session disappears, you still know which order to confirm; and if orders get stuck in "pending" status for a long time, you can check in Stripe if a payment was actually made, and sort the order out manually.
Related
I'm building an ecommerce website, and have had a problem with two different payment gateways. Visitors enter their card details and then leave to the 3D Secure step, which requires visiting their bank's website. When they return from that, they have no cookies on our website, and we cannot recognize them to link up the order.
With one payment gateway, this results in the order failing; with the other, the payment comes through, but is not linked to any specific account or products purchased. Clearly, both of these are problems.
I know that plenty of browsers clear cookies on closing the browser, but I'm not aware of any that clear cookies just because you've left the site for a moment. (Furthermore, on one of the two payment gateways, the 3D Secure step is done in an iframe, so the user hasn't even left the site.) It's the user's session which is disappearing.
Concrete questions:
Is it common for session cookies to be this volatile? This is behaviour I've been unable to replicate myself. Is there some common browser setting or addon which aggressively (and prematurely) deletes session cookies?
Might there be something else causing the effects I'm seeing?
Might there be something else causing the effects I'm seeing?
In this kind of scenario, these days it often has to do with the SameSite attribute of the session cookie.
The Strict value will prevent cookies from being send in any requests initiated by third party websites. When users are getting redirected back to your site from the payment gateway, that is “navigation” from a 3rd-party site then, and the cookies get not send; so your own session can not be picked up at that point.
I have an ecommerce shop online using php, sql, javascript,ajax and sessions.
I have both guest and members cart options at checkout.
Everything works fine.
I store my cart items in a session currently.
Users can log in or have a guest cart.
Guests cart userids are referenced by the current session id.
members can login and their carts are referenced by their usersids from the database.
The problem is, the session expires after a certain amount of time and so the cart items are lost and the user has to start again.
On doing some research I have found that after the user logs in, I can store his user id in a cookie and I can specify how long that cookie lasts for which is ideal!
I am thinking of changing the code so that I store the items added to the cart in my database tables and simply reference them with the user id ive stored in his cookie.
That way He can shop for ages and not lose his cart and I can send abandon cart emails etc...
I think this would work well as nearly every website uses cookies so people have to have them enabled in their browser these days. I could show a warning message if cookies arent enabled anyway..
What does everyone think about this?
Please note I am not seeking security advice here.
I havent implemented this as yet - Im really looking to see if I can set my session lifetime to last a few hours/days instead.
I see your problem with Guest checkout and normal checkout after login.
You can go and use cookies rather than using sessions for this.
Cookie have setcookie() function with time() method.
You can set an Expiry time for that.
Go and use, it can help you
i have a problem with what seems like session timing out and being destroyed, though i currently do not have it set to expire after a certain amount of time, nor do i have the session destroyed anywhere in the code.
Here's what happens in detail,
it's an e-comm site i have 90 % built which also has two payment gateways(PayPal and SecurePay).
first of all, i only have this problem when the website is uploaded to the web host(GoDaddy), i haven't experienced this issue using localhost.
The issue:
I can use my site, everything functioning normal, i can choose
products and checkout successfully through both payment gateways without issue.
When i am finished for the day i'll close the browser as per normal.
The next morning i will again open the browser and navigate to my
site. The website has still retained all the session information
and i can navigate to all my pages without issue, including my shopping cart(my shopping cart
especially relies on session data to work).
During the first time i go to check-out, with either payment gateway, everything functions fine until payment
gateway navigates back to my returnURL, where the session is somehow
destroyed, all the session data is gone and i am logged out.
This only occurs once, specifically the first time i test the
check-out process after a long period of inactivity. As i log
back in after the session is destroyed the issue is does not appear to
happen again, until the next morning.
I would also like to add that the return
urls are quite different for each payment gateway, the PayPal returnURL is a page where
the order is still being processed and the user can change shipping methods rates, SecurePay returns to a page where the
transaction is complete and an invoice is genrated, though the result is the same and the session is destroyed when returning from either payment gateway to the return url.
To fix this i was just going to expire the session after 1 hour of session inactivity. But i'm curios why the session would be destroyed only after returning from the payment gateway and not as soon as the page is opened after such period of inactivity?
I have a functioning authentication, ACL and session management system for my online software application. As this is a paid service on a per-user account basis, I need to ensure that a user account cannot be shared between employees in the same fashion that PayPal manages business accounts.
My struggle is finding a way to do achieve such functionality that a competent, technical user couldn't circumvent via modifying Javascript or using a client side proxy.
Currently, each company account has a database on my server with a "session" table that consists of session_id (PK), session_user, session_data, client_ip, timestamp_created and timestamp_updated columns. Whenever a user logs in, the session_user column is updated with their login name. Should another person log into that account on a different machine, the previously accessed account will have the session_user column set to NULL. The result is that no two rows should have the same value for session_user. Possibly worth noting is that customers do not have administrative access to their database.
The client-side application runs a Javascript function on a timer every 5 seconds which performs an AJAX call to a Zend Controller. This controller checks the session_user column for the active session via a DB query using Zend_Session::getId();. This method echo's a JSON encoded response with success set to TRUE if the session_id has an associated session_user in the database, or FALSE if there is no value in the session_user column. In the event that the method returns FALSE, the Javascript function proceeds to alert the user that another machine has logged into their account, and then redirects them to the login page.
The problem with this approach is that anyone with experience in Chrome's inspector or Mozilla's FireBug can remove the Javascript that performs the AJAX call and proceed to use the application on numerous machines. Worse yet, this easy method is only the beginning of vulnerabilities.
I have a feeling that I will need to look into Zend's plugin architecture, perhaps implementing a check during preDispatch() to ensure that the current session_id has value set in the corresponding session_user table. This check would be complimentary to my current structure, as I feel that the majority of my users will not be well versed in basic "hacking" per se, and will do just find to prevent account sharing. If this server-side check fails, as it occurs when a resource is requested, an error could be thrown and the requested data would not be pushed to the front end (e.g. the data for viewing products).
Does this approach seem like it will work, or is there a better way of achieving such functionality? I've read a bunch of SO posts that derail into arguments regarding whether or not it is a good idea to be so cumbersome on the end-user. We have already decided that since revenue is largely based around company accounts purchasing additional user accounts that there is a significant need to prevent any sort of account sharing. Preventing the user from logging into an account with an existing session is something I want to avoid. Believe it or not, I would rather have users be annoyed by being booted out of their active session by another device logging in, as I feel this will encourage additional user licenses to be purchased.
Please feel free to ask if you would like any additional information, or require clarification about anything I described in my post.
Store the user's IP every time an action is done on your website as a database entry using $_SERVER['REMOTE_ADDR'].
Check if the IP has changed alongside the session data from the previous entry - if so, have them log out and log back in.
This way, separate devices cannot concurrently act without having to relog as a result.
How should I design a login system so that each username can only be logged on in one place at a time? I want to keep users from giving their username to someone else to login so they can avoid paying for each user.
If a user is already logged in and tries to log in on another machine should I block the 2nd login (which could be a problem if the user was logged on at work and then tried to get on at home)? Or should I allow the 2nd login and end the 1st login? Or does anyone have a better suggestion?
Some Instant Messengers (that can work only with one logged in endpoint) have a nice way of sorting out such conflicts. They show a message like
You are already logged on from <COMPUTERNAME>
(in case of a web app, that would be <IP/Browser>)
and give you a choice between
either leaving that logon alive (and not log on from the machine you're on), or
ending the existing logon (and logging on on the current machine).
This is technically the most challenging, but definitely the most friendly way - it ensures a user has only one session running, without being too obvious about it. And there is no bad blood with users unable to log in because they forgot to log out at work, etc.
Blizzard's World of Warcraft I believe implements this beautifully.
Basically, if you try to sign into the game after already being signed in, the first connection is kicked off.
This basically just entails making the session stored on the database. When you store the session data, store a username too. When a user logs in, delete any session records with that users name, and then create a new one for the person logging in.
I wouldn't suggest blocking 'new' people trying to log in, because users don't want to have to go back to another computer they have (possibly miles away) just because they forgot to log out.
There are also some other things you might have to think of. Things like sessionid hijacking. If a user just puts a cookie on their system (which is always possible) with the right sessionid, it is possible that they could use the same session on multiple computers. In which case you'd probably want to keep an IP field where you keep the data on who is currently logged on.
A typical approach to this problem is to use an
inactivity time-out period.
This system enforces a maximum number of logins per account, while allowing for the situation mentioned: a user left the office without logging out, and attempts to login from his/her home workstation.
Here are the general lines of such a system
Each account is associated with a number of concurrent logins (aka "seats") allowed (it seems the OP wished one and only one, for every account, but this could be more, and vary on an account basis).
The license manager logic keeps a list of all accounts/users currently logged-in, along with a time stamp with their "last" activity.
Before serving any page, the web application, calls the license manager (LM). The purpose is to allow the LM to update the timestamp of "last" activity, but also to deny the call in case the license was taken (more on this below)
Upon each login, the license manager logic verifies that the number of seats taken doesn't exceed the amount specified for the account.
If that is not the case, the LM simply adds the current session to the list of active session
If that is the case, the LM check for sessions in the list which are older than the time-out period. If one is found, it disables it, and grants access to the new login. If none is found, the login is denied.
upon each [explicit] log-out, the LM removes the corresponding session from the lists of active session.
Note that the general principle outlined above can have some variations, in particular:
rather than silently and systematically invalidating the [typically oldest] timed-out session, one can inform the user currently attempting to logging about this situation and let him/her decide of the need to "kill" such a session.
To avoid burdening the LM with each and every new page request, the web application can keep track on a per-session basis of the time since the session was last "refreshed" in the LM, and only call the LM if such time exceed say 1/3 of the time-out period.
Independently from the LM logic per-se, remember to keep a log of all the LM-related events (logins, logouts, inactive session "kills", refused logins...). Such logs should include the date/time, the IP address and other relevant info, and are useful when resolving issues associated with stolen passwords and such. Such logs also contain invaluable marketing, for example to find all accounts which appear to have too few seats (and could therefore purchase some ugrade), or to find at-risk accounts etc.
A few more considerations
make it easy for users to log-out (log-out button/link on most every page, at a fixed location
make it easy for users to report conflict / stolen password situation
Block the first login. If you log in at home, then in work, you don't want to be blocked, since this is a legit method. Always allow the login in the present, and drop the old ones.
I would suggest keeping track of whether each user is logged in and allowing the second login to end the first login's session.
Then allow the user whose session has ended to report possible fraudulent activity if they were kicked off in error.
Don't try to do it by counting the number of IP addresses a user has an active session from - some users may be behind load balanced proxies.
The solution is to write your own session handler - probably easiest with a database back end - and only allow one user to have one open session.
You might want to tune the session garbage collection and inactivity. You should also ensure that your system is immune from session fixation attacks.
C.
In terms of security, and this is what you're getting at, it is always a good idea to store session data in a database anyhow. Particularly if you're on a shared server.
In terms of which user to allow and which to knock off that is a matter for you to judge. I suppose you could have some secondary form of identification to make sure they are the real owner of the account. The one who actually signed up to it.
I've done this before in a web application that had the same requirement. Here's what I did:
When someone logs in, you generate a GUID and store it in your database, attached to the user. You also store this same GUID in a session cookie.
Every time a logged in user hits any page on your site, you check their cookie GUID and compare it with the GUID that is assigned to them in your database. If these GUIDs don't match, they've logged in on another machine, and you log them out from that session.
This method works really well.