Session based CSRF tokens when linking from external links - php

I'm having an issue with CSRF tokens on externally linked pages.
I have a chat bot in whatsapp that sends a user a one-time link to the site. They click the link and need to enter a PIN on the site in order to confirm a request (we do this so the user's PIN is never saved in plain text on whatsapp).
Like all forms on the site, the PIN page has a hidden CSRF token that gets submitted too. The CSRF token is generated in part with the session id, and on submission part of the validation is checking its for the current session.
I am seeing an issue where on some submissions of the PIN page that the CSRF validation is failing due to the session id being different from the initial page load request.
My guess on what is happening is that the user has an active session with the site already (lets call that session 001). They later get sent the whatsapp link which they click on. It looks like sometimes the browser does not send the existing session cookie (I assume due to some tightening on the SameSite policy stuff), so when the user lands on the PIN page the site sees it as a new visit and creates a new session 002. Then on submit of the form the browser sends the original "session 001" cookie. So the token CSRF token was generated with "session 002", but validated against session 002.
(It's probably worth noting this is a legacy system and no SameSite policy is being explicity set)
I don't want to be logging session ids in production so I can't think of a way to verify this is actually what is happening. I haven't been able replicate this behaviour in my dev environment yet.
Does this sound like a known thing that I am just not understanding well? Any ideas on ways to work around this issue?

Sessions don't work between browser tab reloads as a conceptual model (IMO) https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage. In your use-case, a session is between browser tab reloads (both by refresh, hard refresh or navigation by external link) barring reloads by 'back' button presses. So in short, you need your own session UUID generator and management. Try using UUID classes implemented in most web-server platforms.
localhost may work differently due to http stipulations, although I can't figure out why this wouldn't be reproducible in localhost.

Related

Using stolen cookie in cURL to bypass CSRF

I have to process a web page. This web page is based on YII framework, and the login page is protected by CSRF tokens. When I pass the login credentials by POST method. I get the error 400 and The CSRF token could not be verified message.
I don't know how to by pass this protection. I don't understand the mechanism. When I login by the Chrome browser, I see what the POST message look like. It has 4 parameters: CSRF key, login, password, an one empty variable. How the browser gets the proper CSRF key to be sanded back?
I have a login and password for this web page, and I can login as normal user. Only the login page is protected against CSRF. Can I use the cookie (how to do that) created by browser on normal login, give this cookie to cURL and start processing URLs behind login page?
MrMgr Answer in his comments. I've put it here to help other people easily identify the answer.
The CSRF key is generated for session and it is inside LOGIN page as plain text. I can copy it from the source code, of the login page, and provide to cURL script to be past as POST variable. The CSRF Key doesn't change after every page refresh, a KEY is valid until logout. On logout the CSRF key is sanded to server for termination.
Source
CSRF tokens are in place to make this precise action difficult. You need a better way to spoof being a browser with PHP. To do that, store all cookies in what is generally called a "cookie jar." PHP's implementation of curl has that capability. All curl requests routed to this site should use this cookie jar from now on.
Next you need to parse the login page to grab all fields that are submitted. This includes the username, password, CSRF, and other hidden fields. Make sure you have values for each one. If it's not supposed to be entered by you (e.g. hidden inputs), scrape the login page's HTML and put those fields into variables you can pass along in the login POST. Also be sure to send the url of the login page you scraped as the referrer in the login POST.
Parsing html can be tedious, but libraries like SimpleHTMLDOM should make it simple if you're familiar with CSS selectors.

User doesn't accept Cookies - login PHP

In my login code on my website, if the password & username are correct, I set a cookie to keep the user logged in.
I just heard from a user that he doesn't accept cookies automatically through his browser, and that that prevents him from logging in. That rhe cookie is not set.
Is there an easy way to counter that?
Tell me if you need the code I use.
It is possible to get this to work but often a real pain if you're using complex javascript/ajax.
In short, instead of storing the session id in a cookie, you embed it at the end of every link.
so
http://example.com/somepage.php
becomes
http://example.com/somepage.php?SessionId=ABC123
Unfortunately, while PHP can do this for you in some cases, it doesn't help with links you build yourself in javascript - and it only takes clicking a single link without the id to effectively log the user out
See this page for more information
As mentioned by Quentin in the comments, if you're not using a cookie to identify the browser which created the session, it's possible that sharing a link would share the session. This could be mitigated but not prevented by checking IP address/user agent but this would likely fail in large corporate environments with NAT and standard browsers

How do Session variables set before a redirect in OAuth flow remain to compare after the user returns?

I'm in the process of setting up various authentication methods on a project I'm working on, and the common OAuth 2.0 framework that Google and Facebook use seems pretty awesome. Reading the example Facebook gave though, I stumbled across something that seemed strange to me.
If you look at the bottom of that facebook page, you can see an example in PHP. In their process, they first set a random string to $_SESSION['state'], then redirect the user to the facebook authentication page, which then sends the user back to the original page, where they compare the state string to what's supposedly stored in the session variable. Maybe I'm missing something here, but don't you lose all session data if the user leaves your site? How does this work? How is your session data maintained even though you leave the site?
The session data stays until you close the browser or logout from your app. The session state could be getting saved on the server or on the browser in a cookie. Either way, the session data is available to you once facebook redirects back to your site.
You don't lose your session data, when user leaves your site.
So, we check state value after user is redirected back to our website from facebook.

Why do PHP logins scripts use GET ID to logout?

I'm currently building my own login script and have noticed that most append the session ID or similar to the logout page as a get variable.
Why do they do this?
Is it not just safe/easier to just the destroy the session on logout.php and not pass in any ID?
I cannot think of any reason why they would need to add a get param only when logging out.
Adding some token to an URL can be used to prevent abuse or when the session id is added to the url to also make session work when cookies are disbled on the client side.
Update
From the linked article:
However, a quick view of the file shows a fairly interesting issue. It requires the signature computed by logging in to be presented to the user to submit to the login page. Presumably this was done as a form of CSRF protection. However, it also leaks the data necessary to take over a session to the user. So we come to our 11th vulnerability so far:
UPDATE2
I've asked ircmaxell in chat. And yup it is because of CSRF protection.

Same sessionid across all open windows?

Is it possible to have the same session be active across multiple open windows in a php app?
I want to have SOME of the convenience of the dreaded "remember me" checkbox type system without the same amount of risk to the user's data.
The specific use case I have run into is this: When a user receives a "friend request", an e-mail is sent to them with a link that contains a random hash and their username in the url. Say the person is already logged in to my service in one window and is checking their mail for the confirmation e-mail in another. They click the link in the confirmation e-mail and it launches a third window which initiates a GET request to the relevant confirmation page. I'd like to make it so that if the user is already logged in to the service in another window and the hash and username match those stored in the "requests" table of my database, clicking the link instantly confirms the friend. However, if they are not already logged in in another window, they are then forced to log in to confirm the friend request.
Currently if a person is logged in in another window, clicking the link launches a third window and the person must log in again regardless of whether they have another open session.
Is this functionality possible without using cookies to maintain a persistent login?
Update: This question demonstrates my own lack of understanding regarding how sessions work. The user's session IS normally preserved across concurrently open browser windows by default. The issue, as was addressed in the answer I accepted was that I had one window open with www.example.com as the URL and one with example.com as the URL, in which case a different session is created in the second window rather than continuing the session started in the first window.
If you use cookie-based sessions, the session is already maintained between windows (of the same browser executable).
The session ID is the only client-side stored token in this case, and browsers don't generally segregate cookies between different windows.
You may have an issue in that they're visiting your web site via two different domain names (www.example.com vs example.com vs www.example.org, or the like), but fundamentally there is no problem unless you try to use GET-passed session IDs.
You will technically "use cookies" - but the cookies only hold the session ID, not the session contents. If that is anathema to you, you could store the session ID using the HTML5 LocalData API, or with a Flash object, or a Java applet, or whatever...
I strongly advise against attempting to identify the clients a posteriori via their IP address or browser characteristics. Just have them store a token, and use that to determine who they are.
A typical login system has sessions and cookies . Cookies are only set if the users wants to be remembered to avoid input hes data again from that spesific browser and nothing else.
Session live while you are loggen but the will be destroyde after you close the window thus prompting for a login again.
While saving cookies to a users browser it is vital that you encrypte their data .also instead of the password save a cookie with a refrensnumber (ID) and not their password.

Categories