Im working on a .NetCore MVC project.
As the title suggests my goal is to store a cookie that will eventually be accessible through an iframe.
In order to achieve that this is what I did -
Startup.cs -
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.None
});
Using the actual CookieOption class -
public void SetCookie(string key, string value, int? expireTime, HttpResponse Response)
{
CookieOptions option = new CookieOptions();
//allow cross-site cookies for iframes
option.SameSite = SameSiteMode.None;
if (expireTime.HasValue)
option.Expires = DateTime.Now.AddMinutes(expireTime.Value);
else
option.Expires = DateTime.Now.AddMilliseconds(10);
Response.Cookies.Append(key, value, option);
}
Doing the above It seems like it doesn't always work as intended.
Iv'e tested lots of browsers both desktop and mobile.
Just found out that sometimes the cookie is stored successfully like so -
Send for:
Any kind of connection
Accessible to script:
Yes
And sometimes on the same exact chrome version just a different computer its stored like so -
Send for:
Same-site connections only
Accessible to script:
Yes
Which basically means it won't be accessible using iframes.
The problem isn't a specific computer issue as I was managed to duplicate the problem on 3 different computers running the same chrome version which works fine on other computers.
The example above was produced using this chrome version (last version):
Version 80.0.3987.149 (Official Build) (64-bit)
Anyone have an idea how can I overcome that ? gotta make sure cookies will always be accessible using an iframe.
Thanks!
Edit - Attempt with Secure and HttpOnly flag
So iv'e adjusted my code to set the HttpOnly and the Secure flags to true.
The computers that usually worked fine had this cookie settings -
Send for
Secure connections only
Accessible to script
No (HttpOnly)
And it works fine with iframe.
The computer which didn't work before had this cookie settings -
Send for
Secure same-site connections only
Accessible to script
No (HttpOnly)
Which obviously didn't work with an iframe...
Just updating of another approach that didn't work.
Edit 2 - Using fiddler to intercept the cookies response:
So using fiddler to read the cookie this is what it looks like -
Set-Cookie: __cfduid={randomvaluehere}; expires=Fri, 24-Apr-20 17:37:48 GMT; path=/; domain=.domain.com; HttpOnly; SameSite=Lax
Set-Cookie: mycookie=mycookievalue; expires=Fri, 24 Apr 2020 17:37:49 GMT; path=/; secure; httponly
So seems like the response is storing a cookie with is SameSite=Lax on the apex of the domain, which I don't care about.
I work on a sub-domain which is the second set-cookie that is shown above.
Looks like SameSite=None isn't explicitly presented, should it? if so why wouldn't it seeing the code above?
Also reminding you that exactly that works fine for other browsers or other computers with the same chrome version.
The sample above is exactly the same on computer where it worked and in one that it wasn't.
Related
I have one strange issue, one of the site I have developed returns Anti-Forgery cookie while requesting login page. When I check response in chrome network tab it contains header
Set-Cookie: .AspNetCore.Antiforgery.w5W7x28NAIs=xxx; path=/; samesite=strict; httponly
But when I check cookie value in Application tab (Under cookie section), I cant find any cookie set in browser. I have also checked cookies with chrome extensions like EditThisCookie but it is also not displaying there.
Network Tab:
Application Tab:
Am I missing some simple thing, or this is some kind of chrome (Version 66.0.3359.181 (Official Build) (64-bit)) bug?
I've got similar issue, solved it by setting withCredentials = true for every requests.
For angular, this basically means:
this.http.get(url, { withCredentials: true });
If I understand correctly, the flow for using ETags works as described now:
Browser sends the request to the server. Server sends back the image with an ETag
Browser saves the ressource along with the ETag
On the next request, the browser sends the request with the header If-None-Match containing the saved ETag.
When returning a response, chrome dev tools tells me these are my headers
Cache-Control:max-age=7200
Connection:keep-alive
Content-Type:image/png
Date:Thu, 27 Apr 2017 13:42:57 GMT
ETag:"b36f59c868d4678033d318a182658e18371df8f5"
Expires:Thu, 27 Apr 2017 15:42:57 GMT
Server:nginx
Transfer-Encoding:chunked
X-Debug-Token:873c8f
X-Debug-Token-Link:http://localhost:8081/_profiler/873c8f
Now, when I reload the page, the new image isn't gathered, though. It's saved through Chrome's in-memory cache or disk cache as you can see here
But why is this happening? I sent an ETag so why does the browser not make another request to the server but instead uses it's own cache?
The reason I'm asking is, that we want to cache our images, but as soon as they change, they should be updated immedietely. Why does Chrome do that?
Update
I just noticed that it works as intendent on Firefox, so this seems to be a chrome "feature" and not a configuration one.
Update 2
After setting my new headers for image like this
Cache-Control:max-age=0, private
Connection:keep-alive
Content-Type:image/png
Date:Thu, 27 Apr 2017 14:44:57 GMT
ETag:"e5b18bdebe44ed4bba3acb6584d9e6a81692ee27"
Expires:Fri, 27 Oct 2017 14:44:57 GMT
Server:nginx
Transfer-Encoding:chunked
X-Debug-Token:3447a6
X-Debug-Token-Link:http://localhost:8081/_profiler/3447a6
Chrome still uses the disk cache to laod the data. This is my nginx now
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
access_log off;
add_header Cache-Control "max-age: 0, must-revalidate";
}
Update 3
I just did some further research. As soon as the Expires tag is set, Chrome uses the in-memory or disk-cache. Same with max-age. Which I don't understand, even when must-revalidate is set, as soon as Expires or max-age=>0 is set, Chrome doesn't reload the ressource.
The server is telling chrome that the resource is good for the next 2 hours (7200 seconds). Presumably your second request was sooner than that.
You would be better served with max-age: 0 or perhaps max-age: 0, must-revalidate. Then while you'll never get a fully-cached operation (not even bothering to hit the server) you can still have the server send 304 Not Modified responses to tell the browser that it can use the cached entity (and update any metadata based on headers if applicable) so while you still have a request-response happening only around 300bytes will be sent rather than however many kilobytes or more the entity is.
For anyone else who might land here, note that Chrome does not cache anything if there are any SSL errors (such as if you're using a self-signed certificate).
Original post that clued me in: https://stackoverflow.com/a/55101722/9536265
Chrome bug: https://bugs.chromium.org/p/chromium/issues/detail?id=110649 (and it appears they will never fix it, which seems ridiculous since almost all developers will be developing in that very situation)
I have not been able to confirm with documentation, but the behavior appears to be the same with Edge Chromium. Firefox, on the other hand, will happily follow standard cache practices for sites using "Not secure" certificates such as those with imperfectly-matching site names or self-signed certificates. I have not tested Safari.
For ETags to be used and the browser to send the If-Modified-Since and If-None-Match headers, the cache control must be set to no-cache.
Either by the server using the Cache-Control: no-cache header or by the browser through the Request.cache = 'no-cache' option.
Read more about the cache options here: https://developer.mozilla.org/en-US/docs/Web/API/Request/cache.
This is an old post but this is how we solved it.
#Musterknabe Comment on your update 3:
The same thing happened with us, even after setting
must-revalidate chrome was not reloading fresh resources. I found out that since resources were already present in clients/browser cache memory they were being served from memory cache and the new request(to get static resources) was not firing resulting. So response headers were not updated with must-revalidate
To fix this problem we used two steps:
1. Changed resource file names - To make sure new request will be fired
2. Added cache-control headers to static files(In startup.cs) - To take care of future static resource file changes. So that going forward we don't have to change the resource file names.
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
const int durationInSeconds = 0;
ctx.Context.Response.Headers[HeaderNames.CacheControl] =
"must-revalidate,max-age=" + durationInSeconds;
}
});
}
Hope it helps.
I noticed recently, that when I reboot my Tomcat web server, that the Chrome browser can no longer store cookies. i.e. tomcat uses cookies for http sessions, and the browser can no longer get its http session, also the cookie we use to store the logged in user fails, and the user does not remain logged in.
This seems to be a new issue with Chrome, perhaps from a recent update, I do not remember seeing it before. If I close the Chrome browser, then reopen it, it is fine again (until the server is rebooted again).
The issue does not happen on Firefox, seems like a bug in Chrome.
Has anyone else noticed this issue, or know of a solution?
I found some posts about Chrome/tomcat cookie issues and the suggestion to set,
sessionCookiePathUsesTrailingSlash=false in the context.xml
but this does not fix the issue.
It seems it might be related to the website supporting both https and http, and switching between the two (although it did occur on a website that did not support https as well...)
Okay, I can now recreate the issue, steps are.
connect to website via https
logout / login
connect to website via http
Tomcat JSESSIONID cookie can no longer be stored (oddly user/password cookies are stored)
This only happens on Chrome, and only since the Chrome update that add the "insecure" flag on login pages that use http
Okay I added this to my web.xml
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
This did not fix the issue, but made the issue always occur through http, i.e. make http no longer able to store the JSESSIONID cookie.
I tried <secure>false</secure> but still get the old issue.
So, it is related to this setting at least. Anyone have any ideas?
Logged bug on Chrome,
https://bugs.chromium.org/p/chromium/issues/detail?id=698741
I was able to reproduce your problem with Chrome: Just it is needed to create HttpSession from HTTPS zone. Any subsequent HTTP request will not send the session cookie and any attempt to Set-Cookie:JSESSIONID= through HTTP is ignored by chrome.
The problem is localized when the user switch from HTTPS to HTTP. The HTTPS session cookie is maintained even if server is restarted and is working properly. (I tested with Tomcat6, Tomcat 9, and using an apache proxy for SSL)
This is response header sent by Tomcat when session is created from HTTPS
Set-Cookie: JSESSIONID=CD93A1038E89DFD39F420CE0DD460C72;path=/cookietest;Secure;HttpOnly
and this one for HTTP (note Secure is missing)
Set-Cookie:SESSIONID=F909DBEEA37960ECDEA9829D336FD239;path=/cookietest;HttpOnly
Chrome ignores the second set-Cookie. On the other hand Firefox and Edge replace the Secure cookie with the not-secured. To determine what the correct behaviour should be I have reviewed RFC2109
4.3.3 Cookie Management
If a user agent receives a Set-Cookie response header whose NAME is
the same as a pre-existing cookie, and whose Domain and Path
attribute values exactly (string) match those of a pre-existing
cookie, the new cookie supersedes the old.
So, It is clear is a chrome bug, as you supposed in the question: The HTTP cookie should replace the one setted by HTTPS
Removing cookie manually from Chrome or invalidating the session at server side makes it work again (if after these actions the session is created using HTTP)
By default the JSESSIONID cookie is created with Secure when is requested from HTTPS. I guess this is the reason that Chrome do not allow to overwrite the cookie. But if you try to set <secure>false</secure> in web.xml Tomcat ignores it and the Set-Cookie header is sent with Secure
<session-config>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
Changing cookie name, setting sessionCookiePathUsesTrailingSlash or removing HttpOnly has had no effect
I could not find a workaround for this issue except invalidating server session when logged user switch from HTTPS to HTTP.
Finally I opened a bug in chromium: https://bugs.chromium.org/p/chromium/issues/detail?id=698839
UPDATED
The issue is finally marked as Won't Fix because it is an intentional change. See https://www.chromestatus.com/feature/4506322921848832
Strict Secure Cookies
This adds restrictions on cookies marked with the 'Secure' attribute. Currently, Secure cookies cannot be accessed by insecure (e.g. HTTP) origins. However, insecure origins can still add Secure cookies, delete them, or indirectly evict them. This feature modifies the cookie jar so that insecure origins cannot in any way touch Secure cookies. This does leave a carve out for cookie eviction, which still may cause the deletion of Secure cookies, but only after all non-Secure cookies are evicted.
I remember seeing this a couple of times and as far as I can remember this was the only recommendation on the matter, as you mentioned:
A possible solution to this might be adding sessionCookiePathUsesTrailingSlash=false in the context.xml and see how that goes.
Some info on the matter from here
A discussion here (same solution)
Hope I didn't confuse the issues and this helps you, let me know with a comment if I need to edit/if worked/if I should delete, thanks!
There is a draft document to deprecate the modification of 'secure' cookies from non-secure origins (submitted by Google). It specifies the recommendations to amend the HTTP State Management Mechanism document.
Abstract of the document:
This document updates RFC6265 by removing the ability for a non-
secure origin to set cookies with a 'secure' flag, and to overwrite
cookies whose 'secure' flag is set. This deprecation improves the
isolation between HTTP and HTTPS origins, and reduces the risk of
malicious interference.
Chrome already implemented this feature in v 52 and same feature is also implemented in Mozilla few days back.
To solve this issue, I think you should connect to website via https only.
The bad way I think is to set sessionCookieName = "JSESSIONIDForHttp" in context.xml
Let Browser's cookie know:
If secure https condition use default "JSESSIONID".
If not secure http condition use "JSESSIONIDForHttp".
I have three applications in my solution, all built in asp.net core 1 MVC 6.
App 1 is an MVC app used for authenticating a user.
App 2 is an Angular SPA app and is the main app in the solution.
App 3 is an MVC web api application.
In app 3, I have the usual asp.net core SignInManager and UserManager code (the same code as you get by default when you start a new MVC 6 template - only different is, it exists in my web api here). And the login/logout/register etc is exposed via web api methods in my AccountController. This allows me to lock down the web api, so only authenticated requests get processed (using the [Authorize] attribute).
When I call the "Login" method in my AccountController, if login is successful - it returns a Set-Cookie directive with the following name: ".AspNet.Microsoft.AspNet.Identity.Application" (this is used for authentication)
The login app then forwards the user from App1 to App2. All subsequent requests to the web api (App3) are then Authenticated and allowed to be executed. NOTE: By subsequent requests - specifically I mean, within App2, angular calling to ask for data from the web service.
All of this works fine - well, it works in IE fine. Which brings my to my question, why would this not be working in Chrome? I see the "Set-Cookie" directive coming back from the response of the web api Login in chrome, but subsequent requests do not have this cookie attached.
What am I doing wrong?
NOTE:
My Http Response from the login method looks like this:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Kestrel
Set-Cookie: .AspNet.Microsoft.AspNet.Identity.Application=CfDJ8FWIuvXs-TxKoIYE8259iAY52B_VZDPTTvYwZ-WAo8hhPCdLhmUfxNZD1wjxEt0sqqnZl6NomwHPNTNFkBxsq4cw_WkQYklnj_dK79wodIguLdPXAbKu6UbS6HKRBxFxjOKVAfIdyxZJ6xA2CtnR9nJC_CSg7v1vFSzgDEiSBso8D3aDNjzFk8
7oIJodC7WLVxWUqdUpjaGRCXqHTYjTwgL9DCihnajAlB921_oEPinUwIPP8g_ugCQmqbFq6kgQ-GwPTifBKRlbtwNsDwbetynl1gIqzELyjgEUAKgtpD9SX7FSjl1grxoGRjbPiXJe-k1SSdnUIHR7wYPkFpiis_c_P1pGkmSyeiDG-lf0xftTlXlnC3BWMbgXeWZn_hsDzbW_Tek3qiq_NB-T0IMGaJgjRnr5DARNcOACWbzwGvHFjsn7n0u7-UZOfzgQJ76d3ra-hjra
-aNcHLgbfDef3TK6z_CKt2iIlnTkyEJXC-3OSGnfWDRvofvQ216UApEPiKoJxiCjWSvGAQCzvf9P1TtKuwAQVxfWz8pL077E-Wfc-4ybtrT6Ivz2VbdFng5Ze5IQ5YWfYYTpDhLSHGKnpFgxVf96f7JwoXlgRq0gs7yEWdWFZs6d18pw-El5sLJr7g; path=/; secure; httponly
Access-Control-Allow-Origin: *
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcUm9iZXJ0XERlc2t0b3BcSEJFIE1hbmFnZXJcTUFJTlxCbHVlem9uZSBXZWJBcGlcc3JjXEJ6LkFwcGxpY2F0aW9uXEJ6LkFwcGxpY2F0aW9uLkFwaVx3d3dyb290XGFwaVxhY2NvdW50XExvZ2lu?=
X-Powered-By: ASP.NET
Date: Wed, 04 May 2016 10:39:57 GMT
Content-Length: 16
Hi I had this problem too.
While my localhost environment in VS worked fine and my user could be logged in this didn't worked in the published environment for chrome.
This began when I was trying some self-signed-certificate stuff in IIS on my pre-production-environment by turining on https with configured bindings. And after that I went back to http.
What you could try in Chrome is this: Open the developer-tools goto tab Application and in the left pane choose Clear storage. Under the diagram on the right click Clear site data even if the usage shows 0 Bytes used. Do it anyway.
Finally I got my application with login features back.
Hope that this will help someone, too.
In my case, we had a C# ASP.NET Core 2.1 MVC application which was working fine when I launch in Google Chrome. But one fine day it stopped working.
In Google Chrome Developer Tools I saw below
First, I noticed that Application -> Cookies .AspNetCore.Session was missing.
Second, in Console I noticed below warning.
A cookie associated with a resource at
http://myapplication.company.net/ was set with SameSite=None but
without Secure. It has been blocked, as Chrome now only delivers
cookies marked SameSite=None if they are also marked Secure. You can
review cookies in developer tools under Application>Storage>Cookies
and see more details at
https://www.chromestatus.com/feature/5633521622188032.
I did below to fix it.
In our application, in Startup.cs I had like below
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.None;
});
}
We changed like below
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.Strict;
});
}
It solved the issue. I also noticed that in Developer Tools now I can see Application -> Cookies .AspNetCore.Session
I had the same problem, it worked in IE, Edge but not in Chrome, Firefox and Opera.
It seem a cookie size problem, and I solved reducing the data in the cookie.
See this for size limits: chrome cookie size limit
I try to play some mp3 files via the html5 audio-tag. For the desktop this works great (with Chrome), but when it comes to the mobile browsers (also Chrome (for Android)), there seem to be some difficulties:
I protected the stream with some password an therefore the streaming server needs to find a special authentification cookie (spring security remember-me). But somehow the mobile browser doesn't send this cookie when it accesses the mp3-stream via the audio tag. When I enter the stream URL directly to the address bar everything works just fine.
While I searched for the lost cookie I found out, that the mobile browser still sends some cookies (e.g. the JSESSIONID) but not all. Further investigations (quick PoC with PHP) revealed that the mobile browsern seems to refuse to send cookies via the audio-tag which have the HttpOnly Flag set. So my question is:
Is this a specified behaviour, why are there differences between the mobile and the desktop versions (of Chrome) and is there a way control the behaviour from the client side?
By looking more deeply into the HTTP packages I found out, that the Android browser doesn't request the mp3-stream itself, but delegates this to stagefright (some android multimedia client). A quick search revealed, that for the old Android versions (before 4.0) stagefright cannot handle cookies:
https://code.google.com/p/android/issues/detail?id=17553 <-- (Status: spam) WTF...
https://code.google.com/p/android/issues/detail?id=17281
https://code.google.com/p/android/issues/detail?id=10567
https://code.google.com/p/android/issues/detail?id=19958
My own tests confirmed this. The old stagefright (Android 2.3.x) doesn't send any cookies at all, the stagefright from a european S3 (android 4.1.2, stagefright 1.2) sends only the the cookies which do NOT have the httpOnly flag.
So I think that everybody has to decide himself which solution he wants to use:
enable httpOnly: android has no access at all but its secure
disable httpOnly: less secure against XSS, but works for Android >4.0
disable cookie authentication at all: insecure but works for all
Note: The problem with simply disabling httpOnly is that you make your whole application vulnerable to cookie hijackers. Another possible solution would be to have a special rememberme cookie for the stream (without httpOnly) and another rememberme cookie with httpOnly enabled.
I had the same problem and disabling HttpOnly or Secure flags on cookies didn't solve the problem on Android 4.2 and 4.4 chrome browser.
Finally I figured the cause. I had a cookie with its value containing special characters colon ( : ) and pipe ( | ), etc. After disabling that cookie with special characters the videos play fine in Android 4.2 and 4.4.
Hope this helps someone.