Rails session expires when app is closed in iOS Chrome and Safari - ruby-on-rails

Session doesn't get saved and expires when app or tab is closed using mobile Safari or Chrome. On the other hand, It works just fine on desktop browsers.
Below is the only session configuration.
config/initializers/session_store.rb
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, {
key: '_myapp_session',
domain: :all
}
Ruby: v2.3.0
Rails v4.2.8
Thank you for all your help.

A couple things to try:
Check that you don't have "Private browsing mode" set on your mobile devices
Make sure your key is something unique and isn't literally '_myapp_session'
Make sure secret_token/secret_key_base (depending on rails version) is set to a unique value
Experiment with specifying the exact domains you want instead of using :all (This is just something to test I don't know if mobile browsers would cause a poor interaction in this case.)

Are you not using standalone applications (webapp, but with a home screen icon)? Standalone apps don't retain even persistent cookies, so anytime you close a standalone app, all session info is lost.
Also session cookies are not supposed to be persistent (should not have an expiry date, and by default they don't). A non-persistent cookie is supposed to be removed when the browser (or tab) is closed. So in fact iOS works correctly.
I think if you want to make it persistent, you can by adding expire_after: 14.days or similar. Be aware what this means though! It is considered a security risk, because such cookies will be written to disk, reopening a browser will grant access to an application if the user did not actually log out, etc.

Related

Django session cookie forgotten on every browser reopen - mobile Safari (iphone,ipad)

I wonder if anybody encountered with this problem. I am storing some data about visitor in django session. It works as expected but only mobile safari (iphone and ipad) have strange behaviour.
When I visit my site from iphone or ipad(Safari ver. 14.3) session cookie is normally set. But when I close the browser then reopen, new session cookie is generated.
This behaviour can be seen only on mobile safari version. I was not able to reproduce it on macOS desktop safari.
To solve this problem I had to change setup for session cookie in django settings.py:
SESSION_COOKIE_SAMESITE = ‘None’
According to django doc. cookie is normally set as ‘lax’ and this introduce security risk in my app.
SESSION_COOKIE_SAMESITE
Default: 'Lax' The value of the SameSite flag on the session cookie.
This flag prevents the cookie from being sent in cross-site requests
thus preventing CSRF attacks and making some methods of stealing
session cookie impossible. Possible values for the setting are:
'Strict': prevents the cookie from being sent by the browser to the target site in all cross-site browsing context, even when following a
regular link.

For example, for a GitHub-like website this would mean that if a
logged-in user follows a link to a private GitHub project posted on a
corporate discussion forum or email, GitHub will not receive the
session cookie and the user won’t be able to access the project. A
bank website, however, most likely doesn’t want to allow any
transactional pages to be linked from external sites so the 'Strict'
flag would be appropriate.
'Lax' (default): provides a balance between security and usability for websites that want to maintain user’s logged-in session after the
user arrives from an external link.

In the GitHub scenario, the session cookie would be allowed when
following a regular link from an external website and be blocked in
CSRF-prone request methods (e.g. POST).
'None' (string): the session cookie will be sent with all same-site and cross-site requests.
False: disables the flag.
I guess that I had to cause security hole in my django app intentionally. I don’t like it but I am not sure how serious risk it is. I would love to know why only mobile safari behave like that.

Cross-origin Cookies on Safari

While investigating the (just released) Chrome 80 cookie changes (required SameSite=None for cross-domain cookies), I noticed some strange behavior in one of my applications. The particular application is embedded in another site - the the content is located in www.domain1.com, but the embedded application authenticated and loads from www.domain2.com. We use cookie-based authentication at the moment.
Because of the Chrome 80 cookie changes, we ended up adding SameSite=None to our cookies so that they could be used to authenticate and transfer to www.domain2.com when we made requests via our API. This fixed the Chrome 80 bug we were anticipating, but we discovered that Safari would not work in either iOS (versions 12 and 13 were tested) or Mac OS (versions 10.15 and 10.15). We narrowed the issue down to a default setting in iOS and Mac OS - the "Prevent cross-site tracking" checkbox in Safari preferences. Whenever that box is checked, our cookies do not transfer from domain1 to domain to, even when SameSite=None is set. This seems like it could potentially cause issues for a lot of different platforms, as prior to recently most sites expected cookies to be able to transfer this way.
Is this intentional behavior, or do we have something set up wrong? I've read about other applications having this problem, but have not found any solutions other than hacks like redirecting to a page on domain2 prior to loading the content on domain1, which isn't really an option for us. Is there some way to get around this, or a way to correct our setup so that we can actually pass cookies as we need?
Here's an example cookie that we receive back from our API during authentication:
"thirdPartyBlocked=1; expires=Tue, 09-Feb-2020 01:59:04 GMT; path=/{our app path}/; Secure; HttpOnly; SameSite=none"
This cookie works and transfers as expected in every browser other than Safari. Any ways to fix this issue?

Chrome and Safari on iOS 12.4 doesn't set cookies timeously

In a web page I set a cookie when the page loads then check a condition and immediately redirect to a second page on the same site where I read the cookie. The cookie is not set when I arrive at the second page. The above functionality works on desktop browsers and it worked in iOS 12.3.1 without any changes to the site. After upgrade to 12.4 it stopped working, but still worked on a 12.3.1 device.
Any thoughts?
This is not a comprehensive answer since there are missing pieces in the question.
#1, the issue often appears when the user serves a page from a local file.
Ex: file:///C:/project/index.html.
Cookies require a web server to be running to be set. Meaning at the very least you need to serve it from http://localhost/index.html.
#2, You are setting the path in the cookie. Meaning the cookie is limited to only one path.
// Example:
document.cookie = "key=value; expires=; path=/my/path/"
Here the cookie will only be valid in the declared url path.

iOS sporadically sends old cookies

I have an application that rotates an auth token cookie values regularly.
Each time the server rotates the token, it will not mark it as "good" until it sees the client has the token (cause the client includes it in the request headers for a resource).
I have a very specific situation ONLY on iOS (10.3) where sporadically it will send a very old cookie when network conditions change (eg: get off the subway). When this condition hits it "forgets" about the most recent cookie value and "starts living in the past" and sends and old value.
** Security note: IP addresses are publicly allocated t-mobile in NYC and token has long been deleted from our DB
Is this a known issue?
Are there any workarounds for cookie handling that is more robust on iOS? localstorage is not ideal cause these cookies are http only.
To clarify ... this is the flow:
Client (iOS Safari) has a cookie called _t with the value old
Client (iOS Safari) makes a request to the server
We issue Set-Cookie and set _t cookie to a new value new (http only, secure cookie)
Client makes another request with the new cookie value new. We flag that the cookie value is good and client has it.
Time passes
Client makes a request with the _t cookie with the value old
Here is my theory of what happened:
From the cookies lifecycle, whenever user authentication state change (login user -> logout user || logout user -> login user), the old cookie would be invalidated and replaced with a new cookie.
But why that happened in the subway and not other places?
1. These days most subways provide free unsecured WiFi to supplement the bad wireless network connectivity while underground.
2. There were some reports on network connectivity issue in 10.3, and
this one in particular is interesting, as the issue was location dependent.
3. I think the combination of (1) and (2) above was causing the app to reauthenticate to the server. Maybe you could pull the logs to check if that is indeed the case?
Possible workaround?
Maybe none. We can't prevent iPhone user from doing iOS upgrade. And most already did.
Also, the security repercussion of not changing cookies after reauthentication is worse.
Update based on the comment as of 05/31/2017:
Given the details as in the comment. We could have better explanation.
In cookie life cycle, when user logout, server-side-invalidation should take place.
The work flow:
1. When the user logout, the authenticated sessionID is deleted from the browser.
2. But that's not enough. The server needs to invalidate that sessionID too. Else there could be security repercussion.
3. It could be that in your case the server didn't invalidate. Thus it still expecting a SessionID which has been deleted from the browser.
This is just one possible explanation. To be exact, more details log file analysis and more experiment would be required.
For example, during that period, at the server log were there any reauthentication took place? Could we test in a controlled environment, if the server-side-invalidation has been implemented properly?
My experience
I also use authentication via IDs that change with each request and are stored in cookies.
I can confirm this behavior and it is still present in iOS 11 (and iOS 11.1 beta 3). In my log files, I can see that sometimes old cookies are randomly stored in Safari. This happens in a standalone webapp when it is closed and reopened.
My Fallback method
I built a fallback method over localStorage. A request with an old cookie will normally mark all data in my database as invalid. If the user agent points to a device with iOS, I do not mark the data as invalid and give the client a second attempt to authenticate itself.
On the client side I check the localStorage and create new cookies with this data. Subsequently, a new authentication takes place. The localStorage is rewritten like the cookies with each request. If authentication fails again, I mark the data as invalid.
Safari View Controller no longer shares cookies with Safari in iOS 11 and up, this change resolved the cookie store corruption issues that plagued iOS. We have not experienced this issue ever since iOS 11 was released.
Maybe that's caused by automatic retries?
Those posts mention that can happen under bad network conditions (like you said, subway):
https://medium.com/#fagnerbrack/the-day-a-bug-was-fixed-only-because-the-ceo-called-in-f653a34079eb
https://blogs.oracle.com/ravello/beware-http-requests-automatic-retries
SQLite database, if you're willing to sacrifice a little security.

Heroku/Rails/Devise/Refinery CMS: IE requires that I have "Accept All Cookies" setting to work

I'm running a Refinery CMS application that uses Devise as the plugin for logging in/authentication. The problem I am having is that Chrome/FF are working fine but IE is not logging the user in. At first, I believed it was that the SSL Certificate wasn't set up yet. After I fixed the SSL issue with Heroku, the problem remained.
Changing the privacy setting for cookies to "Accept all Cookies" is the only workaround I've found to fix this problem. This is problematic because I have to explain to my clients why their IE browser isn't working and at the same time they have to expose themselves to 3rd party cookies if they use this browser for other internet applications.
Is there a configuration that I can set in Rails 3/Refinery/Devise that will remedy this issue?
Thanks!
I had a similar problem - fixed it by using a different session_store in config/initializers/session_store.rb
The :cookie_store default session store tries to store all session information on the browser (which is why you had to set the "Accept all Cookies" in IE). As an example I set my session store to :active_record_store and it solved the login issues.
Coincidentally, I had this problem with IE8, but IE9 and IE10 didn't seem to have the same problem.

Resources