I am setting cookies as part of my mvc application:
var cookie = new HttpCookie(CookieName, encryptedData)
{
Path = FormsAuthentication.FormsCookiePath,
Domain = CookieDomain,
Expires = authenticationTicket.Expiration,
HttpOnly = true,
Secure = IsSecure // true
};
response.Cookies.Add(cookie);
Now if I debug I see that its all working fine, no problems and its added and thats fine too. However for some reason when it actually reaches the browser there is no HttpOnly flag or Secure flag set. So im a bit baffled...
I have tried setting the HttpOnly and Secure flags in the cookie web.config entry under System.Web:
<httpCookies httpOnlyCookies="true" requireSSL="true" />
Now here is how the response looks when the browser receives it:
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Max-Age: 10000
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type, x-requested-with, *
Access-Control-Allow-Origin: http://localhost:34567
X-AspNetMvc-Version: 3.0
X-AspNet-Version: 4.0.30319
Set-Cookie: myCookie=53BA8AF84835A81E014B9174329D8543FBB6029B71C463C6FC1305D9F966F28EAA058FE103325C0F10A3012480FB0EF3F6C0BAC4703A6A6B725F383ADA35A5C125A0438FC42CADCB0DAB77953C967E6660E51C4113C6545220A0C2F86230F446D159D523BBE9CA4D9419A67BC44D23B9C4D0974DF2ED66C47EA7308D8E42E1C2280EA6059A23303E3BCBDF28F6BD4A3DFA92FFAB33DDAC8EC05D99310D26FBD6310252156CD28B89386B0D483D6D2E295EF33487E64468655371CC446E0B5DDBF12B3AA8218AF1FA929A98638A1AC729BA60815B86EAD9624ED1787172B585BE4E457C3568AB6EAAF4865E8468D04336FA7340AAC1BA75162FB322D436DC9BF50466F2F0FB3464ECF41C6C1F7001639DFE2AB2AD9CBFB65A292FE5FA42783DF331AA4641432647BA9672FE6D4C15F830E4DF8B38605852BCB15E5B01B862D966E2FD1D620730312982DB8AB4CE5EE0D0E40E6C3F5234DE5EBFA594036D912F07C3798ED429A2552AD6C4B9EC10B90749850CBDEC97F0BF7E2E43CB3991608C5D533B6EA9F8D0A7AD949B42CD3BAA13DEE99C330121B3D868B412A3435FA01C7F223641CFE441A2E07F5DFB8B23F053CBA13F5E1262A07FBFD4EC4BADF9BD5898; expires=Wed, 27-Feb-2013 19:15:24 GMT; path=/
Date: Wed, 27 Feb 2013 18:45:24 GMT
Content-Length: 2
So am I missing something here? or is there something that I am not setting somewhere that I should be? I am also using CORS because this cookie is issued from a webserver as an authentication mechanism. SSL is enabled and is also being used via https for calls. Even if I turn secure cookies off and use http, the HTTPOnly flag is not being set either, so I am baffled.
=== Update ===
Having double checked it appears I misinformed you, the HttpOnly response is sent down from the server correctly on the first time you receive the cookie, HOWEVER! when an ajax call then sends the cookie to the server it seems to not add the httponly flag, which then means the cookie being thrown around is no longer as secure. The secure part of the cookie is not sent down on the first response, but at least this adds a bit more context to it all.
Try this, looks like a similar issue. (How can I set the Secure flag on an ASP.NET Session Cookie?)
In the <system.web> element, add the following element:
<httpCookies requireSSL="true" />
However, if you have a <forms> element in your system.web\authentication block, then this will override the setting in httpCookies, setting it back to the default false.
In that case, you need to add the requireSSL="true" attribute to the forms element as well.
So you will end up with:
<system.web>
<authentication mode="Forms">
<forms requireSSL="true">
/* forms content */
</forms>
</authentication>
</system.web>
It seems like this is all correct behaviour, I wrote another question specifically about the httponly client cookie behaviour, and that led to another post... what a rabbit hole.
What should be the correct behaviour of browser when sending and receiving httponly cookie via ajax?
Anyway that seems to indicate the server needs to keep tampering with the cookie to add the HttpOnly behaviour.
I have made a custom httpmodule which will check for the cookie in question and re-apply the desired behaviour to the cookie (based on configurations from the web.config)
Related
I have two DotNet MVC sites. One accesses a Web API from the other with an AJAX GET call.
This all worked, but has stopped functioning now. I've hardly made any changes on my side, so I'm wondering if my host might have made changes (in IIS, for example) that would stop this from working?
Here's how I initially got it working...
I installed the Microsoft.Aspnet.Cors and Microsoft.Aspnet.WebApi.Cors packages.
I added the following code...
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.EnableCors();
And in the controller for my API I added...
namespace Webscope.Controllers
{
[EnableCors(origins: "[URL of my other website]", headers: "*", methods: "*")]
public class EventAPIController : ApiController
This used to work, but now get the following error in the console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https:[my website URL]/EventRead/1-1-2015/12-12-2099. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
In response to #FoggyDay's answer below, I've called the API from Fiddler and got the following headers...
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Frame-Options: AllowAll
X-Powered-By: ASP.NET
Date: Fri, 13 Mar 2020 03:56:39 GMT
Content-Length: 198
So it looks as if CORS headers have not been included in the response. Can anyone tell me why this would be?
UPDATE
I found some extraneous code from a previous attempt to get CORS working. Now that I've removed this code, I am seeing the CORS headers in Fiddler.
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Origin: https://[ calling website's URL ]/
However I'm still getting the following error in my calling site's console...
Access to XMLHttpRequest at
'https://[ destination site URL ]/api/EventRead/1-1-2015/12-12-2099' from
origin '[ calling website's URL ]' has been blocked by CORS
policy: Response to preflight request doesn't pass access control
check: No 'Access-Control-Allow-Origin' header is present on the
requested resource.
SUGGESTIONS:
Back out your "new" changes. It sounds like you've inadvertantly introduced a second header.
Read this: Reason: CORS header 'Access-Control-Allow-Origin' missing
Look at your HTTP traffic, for example in Fiddler. Verify that you're sending the header ... and verify that you're allowing the correct combination of host and port.
If you're still having problems, post back with the exact error message and relevant HTTP headers.
I have an Angular(4) client (localhost:4200) which calls across to an ASP MVC CORE 2 WebApi. One of the calls http://localhost:5000/api/session/resume returns a cookie along with the response.
In the action method I have returned 3 cookies for testing purposes.
[AllowAnonymous, HttpPost, Route("api/session/resume")]
public async Task<AccountSignInResponse> Resume([FromBody]SessionResumeCommand command)
{
AccountSignInResponse apiResponse = await Mediator.Send(command);
if (!apiResponse.HasErrors) {
Response.Cookies.Append("TestCookie", ..., new CookieOptions
{
Domain = "localhost",
Expires = DateTimeOffset.Now.AddDays(100),
HttpOnly = false
});
Response.Cookies.Append("TestCookie4200", ..., new CookieOptions
{
Domain = "localhost:4200",
Expires = DateTimeOffset.Now.AddDays(100),
HttpOnly = false
});
Response.Cookies.Append("TestCookie5000", ..., new CookieOptions
{
Domain = "localhost:5000",
Expires = DateTimeOffset.Now.AddDays(100),
HttpOnly = false
}); }
return apiResponse;
}
The header for this request is
Request URL:http://localhost:5000/api/session/resume
Request Method:POST
Status Code:200 OK
Remote Address:[::1]:5000
Referrer Policy:no-referrer-when-downgrade
And the response headers are
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Vary: Origin
Server: Kestrel
Set-Cookie: TestCookie=XXVtPqCdZ%2BBt9IbhP5Bi7sOLZ%2F%2BELB4fZ0rFArkM%2Be4%3D; expires=Fri, 03 Nov 2017 09:47:28 GMT; domain=localhost; path=/
Set-Cookie: TestCookie4200=XXVtPqCdZ%2BBt9IbhP5Bi7sOLZ%2F%2BELB4fZ0rFArkM%2Be4%3D; expires=Fri, 03 Nov 2017 09:47:28 GMT; domain=localhost:4200; path=/
Set-Cookie: TestCookie5000=XXVtPqCdZ%2BBt9IbhP5Bi7sOLZ%2F%2BELB4fZ0rFArkM%2Be4%3D; expires=Fri, 03 Nov 2017 09:47:28 GMT; domain=localhost:5000; path=/
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:4200
X-SourceFiles: =?UTF-8?B?QzpcZGV2XFhlcnhlc1xYZXJ4ZXMtU2VydmVyXFNlcnZlclxhcGlcc2Vzc2lvblxyZXN1bWU=?=
X-Powered-By: ASP.NET
Date: Wed, 26 Jul 2017 09:47:28 GMT
As you can see, the cookies are being returned from the http://localhost:5000/api/session/resume call, but they are not being stored in my local cookies in either Chrome, Edge, or Firefox. So when further requests are made for images and other resources I am only seeing another cookie (cookieLawSeen), and not this cooked.
When I browse the cookies for localhost in all of these browsers I don't see any SessionTokens in the storage. However, if I look at the request in the F12 developer tools I can click the [Cookies] tab and see ResponseCookies contains all three cookies.
You need to use withCredentials property. It is needed for both sending and receiving cookies:
indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates.
Set it to true each time when you do api call from Angular. Something like the following:
this.http.get('http://...', { withCredentials: true })
I had the same problem and i found out that in .net core 2 the default of session cookie was changed from "Send for: Any kind of connection" to send only to same origin. In my case the server was at a different domain from local host and there for the cookie was not sent to the server.
In order to allow it you need to change the property of the session cookie called SameSite to SameSiteMode.None.
In addition to the above I haven't been able to access a localhost server from the local postman (even-though they have the same origin). the above solved it as well.
I'm trying to set a cookie in my application.
Here's the code that sets the cookie:
public HttpResponseMessage LogIn(UserLoginVM user)
{
// Do login stuff
var cookie = new CookieHeaderValue("STUPID-COOKIE", "12345");
cookie.Domain = Request.RequestUri.Host;
cookie.Path = "/";
cookie.HttpOnly = true;
// Get user's profile
HttpResponseMessage res = Request.CreateResponse<UserProfileVM>(HttpStatusCode.OK, profile);
res.Headers.AddCookies(new CookieHeaderValue[] { cookie });
return res;
}
The response from the server is the following:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
Set-Cookie: STUPID-COOKIE=12345; domain=localhost; path=/; httponly
Access-Control-Allow-Origin: *
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcUFJPSkVDVFNcU2Ftc2tpcC5TZXJ2aWNlV2ViTmV3XFNhbXNraXAuQXV0aEFQSVxTYW1za2lwLkF1dGhBUElcbG9naW4=?=
X-Powered-By: ASP.NET
Date: Wed, 18 Feb 2015 11:58:07 GMT
Content-Length: 8019
Notice the following header:
Set-Cookie: STUPID-COOKIE=12345; domain=localhost; path=/; httponly
However, when I go under "Cookies" in "Resources" tab in Chrome, nothing is set. Also when I send a request to the server no cookie is in the headers.
Here's the code that reads the cookie:
CookieHeaderValue cookie = Request.Headers.GetCookies("STUPID-COOKIE").FirstOrDefault();
cookie variable is always null.
My application is running on http://localhost:53998 and the authentication service is running on http://localhost:60858
My Chrome version is 40.0.2214.111.
Here's a GIF demonstrating the problem:
http://i.imgur.com/q7lkXBz.gif
Edit: This seems to be non-specific to Chrome. This doesn't work on FireFox (v35) either. GIF: http://i.imgur.com/ZewnEtc.gif
I ran into this issue today and Gaui's answer was quite useful to me, bearing in mind ideally you do not want to open up your server to CORS requests from any site. I'm in my dev environment and my server and client are on different origins since they are on different ports on localhost. Also I'm using .net core 3.0
My issue was caused by my server not sending cookies to my client side as my CORS settings were blocking the sending of cookie to my domain this was evident by the server not using the header Access-Control-Allow-Credentials: true. To resolve this I configured my server in Startup.cs to allow requests from my client side to allow credentials (A credential is a cookie's authorization headers or TLS client certificates).
var allowedOrigins = new[] {"localhost:3000"}; // Ideally comes from appsettings
app.UseCors(builder =>
builder.WithOrigins(allowedOrigins).AllowCredentials().AllowAnyMethod().AllowAnyHeader().Build());
For the cookie options; I found that the you do not have to set Domain if you do not want to, Secure works even when the site is not using https.
Google chrome now supports cookies on localhost, I believe it didn't used to as a lot of older SO posts have users who faced that issue.
On the client side, you need to configure it to accept cookies as well, as in Gaui's answer above. I was using fetch, and so had to add the option:
credentials: 'include'
Which tells fetch to retrieve cookies across domains. See the docs here
I highly suspect that localhost is not a valid domain name so Chrome rejects it. If you simply remove 'domain=localhost' from the Set-Cookie then it will work and Chrome will assign the domain to localhost for you.
I would personally create a local domain name like "test.dev" and add it to your Windows hosts file, 127.0.0.1 test.dev
I finally managed to solve this.
In the response from the API I had to add Access-Control-Allow-Credentials: true headers, or by adding the following in the WebApiConfig class:
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
}
Then I had to enable it on the client-side, by setting the withCredentials property in the XMLHTTPRequest object to true. In AngularJS app config function you can do the following:
$httpProvider.defaults.withCredentials = true;
Also, for Chrome, I had to omit the Domain (or set it as null).
Hope this helps others struggling with this.
I have a rails 4 application withs subdomains.
Each user that is registered has a subdomain which he uses to use the whole system.
Here is the issue I am running into
The user logs in using a url like sub.lvh.me/login, once logged in I redirect the user to a url on his subdomain something like sub.lvh.me/home, but he is logged out as soon as he gets there. The session information is wiped out.
Here is what I have in my session_store intializer
Repvista::Application.config.session_store :cookie_store, key: '_repvista_session', domain: :all
shouldn't this work ?
Update:
I noticed that If I login using the main domain lvh.me and then go to sub.lvh.me I am logged in I want to be able to login via the sub domain url.
Thanks
This is from the Wikipedia Page
The cookie domain and path define the scope of the cookie—they tell the browser that cookies should only be sent back to the server for the given domain and path. If not specified, they default to the domain and path of the object that was requested. An example of Set-Cookie directives from a website after a user logged in:
Set-Cookie: LSID=DQAAAK…Eaem_vYg; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
Set-Cookie: HSID=AYQEVn….DKrdst; Domain=.foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly
Set-Cookie: SSID=Ap4P….GTEq; Domain=.foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
......
The first cookie LSID has default domain docs.foo.com and Path /accounts, which tells the browser to use the cookie only when requesting pages contained in docs.foo.com/accounts. The other 2 cookies HSID and SSID would be sent back by the browser while requesting any subdomain in .foo.com on any path, for example www.foo.com/.
Cookies can only be set on the top domain and its sub domains. Setting cookies on www.foo.com from www.bar.com will not work for security reasons.
Hope this helps you understand how session cookie scope works.
I put code from end of this article to my MVC controller method:
http://msdn.microsoft.com/en-us/library/windowsazure/gg680299.aspx
I configured cname for cdn and all working fine except I feel that cdn not caching :)
There is CDN url
http://cdn.services.idemkvrachu.ru/services/BranchLogo/82f204fe-bb1d-4204-b817-d424e1284b17/E0F4F2AE-B6C2-4516-BE7C-59B649E2C5AC?lastUpdated=635169430040919922&width=499
And this is original url
http://prm.idemkvrachu.ru/cdn/services/BranchLogo/82f204fe-bb1d-4204-b817-d424e1284b17/E0F4F2AE-B6C2-4516-BE7C-59B649E2C5AC?lastUpdated=635169430040919922&width=499
This is my code:
Response.Cache.SetExpires(DateTime.Now.AddDays(14));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetLastModified(blob.ChangDateOfs.DateTime);
return File(bytes, format);
When I checked timings receiving picture from original link and cdn - I found that timings higher on cdn.
Also I was trying change blob.ChangDateOfs and comparing Last-Modified header from cdn response: it immediately changes.
What's wrong with my code? Maybe this header breaks cdn cache Cache-Control public, no-cache="Set-Cookie" ?
To troubleshoot caching issues the first thing you want to do is validate if your content is actually getting cached or not.o
To do this you can add the X-LDebug header with a value of 2. An example of doing this against your endpoint with the relevant portions of output included:
C:\Azure\Tools\wget\bin>wget -S --header "X-LDebug:2" http://cdn.services.idemkvrachu.ru/services/BranchLogo/82f204fe-bb1d-4204-b817-d424e1284b17/E0F4F2AE-B6C2-4516-BE7C-59B649E2C5AC?lastUpdated=635169430040919922&width=499
Cache-Control: public, no-cache="Set-Cookie"
Set-Cookie: ASP.NET_SessionId=nnxb3xqdqetj0uhlffdmtf03; path=/; HttpOnly
Set-Cookie: idCity=31ed5892-d3cb-45eb-bd4f-526cd65f5302; domain=idemkvrachu.cloudapp.net;
X-Cache: MISS from cds173.sat9.msecn.net
As you can see, you are setting the Cache-Control header to no-cache="Set-Cookie", and then are setting a cookie. This is telling the CDN to not cache the content. Since your code is only setting the cache control to Public I assume that you have a setting in your web.config or aspx page that is modifying the cache control header to add the no-cache="Set-Cookie".