[Updated - see comment at end]
Google will be changing the behaviour of its Chrome browser so that cookies will no longer work when hosted in another domain's IFRAME unless the cookies are explicityly set to SameSite = None, and Secure.
To this end, we made this change in our ASP.NET MVC code. We have some logic around when to set this (only for partners that we've agreed to work with), so we have this conditional logic:
if (isSameSiteCookieEnforced)
{
cookie.SameSite = SameSiteMode.None;
cookie.Secure = true;
}
We tested this in our DEV, QA, STAGE environments and it works perfectly. In Chrome's developer tools (Application > Cookies), you can inspect the cookies and see that they are all marked as Secure, and have None in the SameSite column.
However, when we rolled this to our PROD environment, we get different results using the same browser: the cookies are marked as Secure, but the SameSite value is empty.
What we checked:
Load Balancer: we isolated this and navigated direct to a single web server, same result
Installed .NET frameworks: in all environments, we've installed 4.7.2 and 4.8
Addressed .NET framework: in all environments, the web.config stipulates 4.7.2
Code: we retrieved the relevant DLL from PROD and inspected with ILSPY. It contains the above code
Currently at a bit of a loss to explain how the cookies could lose the "SameSite" property. Navigating to chrome://flags and filtering on SameSite we're showing the three settings to be "default", so Chrome shouldn't be affecting anything differently from one environment to another.
Update
Our ASP.NET MVC application uses an IHttpModule and as one of the last steps in the EndRequest method we trace out the cookies. You can clearly see that they are set with SameSite=None and Secure=true. But, when they arrive at the browser, the SameSite property has been stripped.
If you are conditioning on whether the new SameSite behavior is enforced, you will want to test the behavior with the chrome://flags entries same-site-by-default-cookies and cookies-without-same-site-must-be-secure set to both "Enabled" and "Disabled". If they are set to "Default", there is no way to tell what the behavior is. It could be on or off, depending on the random seed determined on startup, since the features are currently in a fieldtrial (A/B testing) on Beta. See the second bullet list in "Launch Timeline" here: https://www.chromium.org/updates/same-site
Found the issue - turned out that we were missing a Windows patch.
Related
I have a Rails 6.1 app that uses sessions to store some data.
When I open the app in an iFrame the sessions do not work (I cannot get their value when navigating to another page of the app, still inside the same iFrame)
I read a lot about this and played around with the cookies same_site configurations etc.
I also read about Chrome being the reason but I tried it in Safari with the same issue.
But I do not want to share sessions between the rails app and the page that contains the iFrame. I just want that the app works normally inside the iFrame.
Any ideas what could be the reason?
In order for your session cookie to work inside of an iframe, you need to explicitly set its SameSite setting to None.
Rails version ≥ 6.1
Rails 6.1 introduced a new configuration option, which you can set e.g. in your config/application.rb:
config.action_dispatch.cookies_same_site_protection = :none
The relevant section on the guides is here.
Rails version < 6.1
Your best bet is most likely to use the rails_same_site_cookie gem.
Secure setting
When setting SameSite to None, you must also ensure that your cookies are sent with the Secure setting set to true. This happens when you uncomment the following line in config/environments/production.rb:
config.force_ssl = true
Where is this change from?
The relevant commit for Rails 6.1 is here. It boils down to Rails now explicitly setting SameSite=Lax on every cookie it sends.
Testing
I have found that the best way to locally test a setup such as this one is to run a separate server (e.g. a Middleman instance) to simulate the third party page which embeds your Rails app in an iframe.
Then you can point one browser tab to localhost:3000/my/iframed/page, and the other to lvh.me:4567/my/embedding/page. You should be able to sign in one tab and act as the signed in user in the other.
It is crucial to also test this in a production-like environment.
None vs Lax vs Strict
If you were to set SameSite=Lax, this setup would only work when both tabs are pointing to the same domain, e.g. localhost. With SameSite=Strict, it would not work at all.
When you are testing this, if you switch from e.g. :lax back to :none, you will be logged out from both tabs.
Response headers
Note that changing SameSite's value is not enough to set up your Rails app to work inside of an iframe. You also need to set the right headers in the relevant controller action, like so:
response.set_header("X-Frame-Options", "ALLOW-FROM #{embedding_url}")
response.set_header("Content-Security-Policy", "frame-ancestors 'self' #{embedding_url}")
Where embedding_url can be *, if you'd like anyone to be able to embed your Rails app via an iframe.
For further reading, the nice people over at makandra have compiled a card specifically about the SameSite setting.
Safari support
There is nothing you can do to fix the problem in Safari—besides asking your users to uncheck the Prevent cross-site tracking checkbox in their preferences. In the future, the same is likely to apply to all major browsers (see here for the relevant Chrome blog post).
I have an existing website and suddenly some days ago I can't use Google Chrome anymore for developing. When I use a standard edit and create page, I get the above error. But i'm not getting it in Internet Explorer. I use Windows 10 (all updates installed) and VS2013 with Update 4. The project is the latest MVC version. I even checked the web.config but nothing is changed. I deleted all history, cookies, passwords etc.
Anyone any idea?
I had the same problem. For me the solution was to both clear my browser cookies and to disable Adblock. Other addons may have the same effect. I believe the problem is limited to the Visual Studio / Chrome development environment and will not occur in production regardless of whether the end user has Adblock enabled or not.
Do you have a
<httpCookies requireSSL="true" />
in your Web.config? Change that to false. Then in your transforms files (Web.Prod.config, and other environments that have SSL):
<httpCookies requireSSL="true" xdt:Transform="SetAttributes" />
I'm also having the same issue in recent weeks, but it's also extending cross-browser after originating from Chrome. What's even stranger is that it still works flawlessly with the identical project on a different machine using all browsers.
I have gone so far as to uninstall all extensions, delete all cookies / data, sign out of Chrome completely and re-install it. Problem still persists.
On deployment to Azure websites the problem isn't present on any platform. My current work-around is to Ctrl-F [ValidateAntiForgeryToken] and comment out every occurrence, and re-enable it upon deployment. Annoying, but it works.
This was happening to me in Chrome, and seemed related to using the 'remember me' checkbox on login forms, and closing then re-opening the browser. The token was present on inspecting page source, but was reported as being not present during debugging sessions in visual studio. By clearing the browser cache and not checking the 'remember me' box I did not get the problem - but I don't fully understand why!!
My steps to reproduce the bug in Chrome:
Sign in to your MVC web application, clicking on 'remember me' to make it checked
Close browser
Open browser to your current retained session
Try to sign out - error happens here.
Anyway, the following solution worked for me. Inside your MVC view form, try replacing this:
#Html.AntiForgeryToken()
with:
ViewContext.Writer.Write(Html.AntiForgeryToken().ToHtmlString());
Are you on cloud platform ? chrome emits cookies from cloud domains hence the only way to do it is to map another named domain to your cloud web site
This is probably because browsers like Chrome use the Public Suffix List(https://publicsuffix.org/list/effective_tld_names.dat) to restrict certain cookies. If the domain suffix set on the cookie is shared publicly then the browser may block such a cookie in order to prevent itself from sending "unauthorized" data to other servers running on the same domain.
I was changing OAuth/Owin settings and Azure publish settings in a Web Application project this morning, but soon after we decided deployment will be to a specific IIS Azure VM (now visible across our local domain). All code/setting changes have been reverted.
At one point I also changed the drivers\etc\hosts file to allow a dummy name for Microsoft OAuth, but that has been reverted.
Notes:
My startup URL is http://localhost:22222/
I am running under IIS Express (as my local Dev VM will not allow me to install full IIS)
When I start the Web Application with IE I simply get "This page can't be displayed"
If I start it with Chrome I get "This webpage is not available", but it also changes the browser URL to https://localhost (note the s, i.e. using SSL).
I have pulled the project down fresh from source control. No change.
The project is under TFS source control.
Another developer on the same project has the latest files and it works fine.
If I run any other Web Application project, they work just fine.
All OWIN registration of providers has been commented out. No change.
Deleted the entire project folder and pulled fresh from TFS. No change. This probably means a local machine setting somewhere is the cause?
What could I have damaged in my Web Application to cause this problem? I have been scratching my head for hours now and nothing we try is working. The application simply will not start in any browser.
Project Web Settings tab:
Answer at bottom, given to this chromium issue [issue 444479] helped me:
Same here - I also believe caused by HSTS - see
http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
If you have (developed) any other localhost sites which send a HSTS
header...
eg. Strict-Transport-Security: max-age=31536000; includeSubDomains;
preload
...then depending on the value of max-age, future requests to
localhost will be required to be served over HTTPS.
To get around this, I did the following.
In the Chrome address bar type "chrome://net-internals/#hsts"
At the very bottom of a page is QUERY domain textbox - verify that localhost is known to the browser
If it is, DELETE the localhost domain using the textbox above
Your site should now work using plain old HTTP
HTH,
Jay
ps. This is not a permanent solution, but will at least get it working
between projects. If anyone knows how to permanently exclude localhost
from the HSTS list please let me know :)
Give it a try.
I have an ASP.NET MVC4 application running on Windows Azure and it uses Azure ACS for Federated Authentication.
When we first started testing the application, it was working in all the browsers except Safari and Opera because of the size of cookie.
I've read several articles online that asked me to use FederatedAuthentication.SessionAuthenticationModule.IsSessionMode = true;
The above statement will store the data in the cookie on the server side. That fixed the problem because only a session identifier is stored on the client(browser).
However, that attribue appears to be removed from the WIF 4.5 api.
Do you know if there is a work around?
Do you save the original token? Do you have something like this in your web.config, or do you set the saveBootstrapTokens config setting to true:
<securityTokenHandlers>
<securityTokenHandlerConfiguration saveBootstrapTokens="true" />
</securityTokenHandlers>
If you do, or if you don't, try setting the saveBootstrapTokens to false! This is will save you a lot of "space".
I had this issue only when I had saveBootstraptokens set to true.
Yes - #astaykov is correct - that's part of it.
As per #Dominick, it's called "IsReferenceMode" in .NET 4.5.
I am trying to deploy a .NET MVC application to GoDaddy servers. I have an Html.AntiForgeryToken on one of my pages that is causing it throw an exception every time I hit it.
Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.
I have generated a machine key using the following URL
http://aspnetresources.com/tools/machineKey
and have set the pages viewStateEncryptionMode to "Always"
<pages viewStateEncryptionMode="Always">
I am still receiving the error however and am at a lost as to what to do next. Any suggestions would be greatly appreciated.
I finally figured it out. I did a little bit more google searching and found that if I don't clear the cache on the browser it will retain the invalid viewstate. Apparently chrome holds onto some semblance of the viewstate in each consecutive browser unless all of the chrome browser windows are closed down (I use alot of chrome browsers), even when the cache has been cleared.
I found that the code worked by trying it in Firefox and IE which was successful. I then closed down all of the chrome windows (after clearing cache) and restarted. I was then able to navigate successfully to the page with the AntiForgeryToken on it.