1

My goal is to issue a GET request, including a cookie, from javascript which will be hosted on multiple domains, to an API on a common domain. If the cookie is missing, I create one and return it for use in subsequent requests.

Initially I encountered an issue with the browser refusing to allow a jQuery get to a domain different to the page's domain, which I know is to do with CSRF protection.

I tried dozens of different ways to setup CORS with my DotNet Core 2.1 API project, such as described in this question: How to enable CORS in ASP.NET Core, and on numerous blogs like this one: https://weblog.west-wind.com/posts/2016/Sep/26/ASPNET-Core-and-CORS-Gotchas

Although I was able to get rid of the CSRF problem, cookies were never being delivered in the request, so every time the server would create a new one and send it back, the browser would either not retain it or not send it with subsequent requests to the server.

Then I discovered that if I add the SameSite = SameSiteMode.None line to my cookie creation, it works:

[HttpGet("[action]")]
public async Task<IActionResult> Track()
{
    const string cookieName = "TrackingCookie";
    string uniqueId = Request.Cookies[cookieName];

    if (string.IsNullOrWhiteSpace(uniqueId))
    {
        uniqueId = "123"; // debug - this would be generated

        Response.Cookies.Append(cookieName, uniqueId, new CookieOptions
        {
            SameSite = SameSiteMode.None,
            Expires = DateTimeOffset.UtcNow.AddSeconds(30) // debug - short duration for testing only
        });

        logger.LogWarning($"Cookie missing, so created it with unique id '{uniqueId}'.");
        return Created(Url.Action(), $"Created unique id '{uniqueId}'.");
    }

    logger.LogWarning($"Cookie found, unique id '{uniqueId}' present.");
}

However, I also discovered that it still works if I remove literally every CORS-related declaration from my Startup.cs file. It still works if I completely remove:

services.AddCors(options => options.AddPolicy("MyPolicy", builder =>
{
    builder.WithOrigins("http://markscoolsite.com:5000")
           .AllowAnyMethod()
           .AllowAnyHeader();
}));

and:

app.UseCors("MyPolicy");

Furthermore, the cookie works regardless of what domain I put it on, so it is clearly not acknowledging the WithOrigins(...) directive.

For reference, this is my javascript code:

$(function () {
    $.ajaxSetup({ xhrFields: { withCredentials: true } });

    $.get('http://localhost:5000/api/tracking/track')
        .done(console.log);
});
  1. Why does this cookie work for any origin without needing any of the CORS additions to Startup.cs that are described in the linked question and countless others? Have I completely misunderstood what CORS is for in MVC6?
  2. How can I limit my cookie to only work from the sites I specify? I'm concerned the way I've got it working is probably not very secure.
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Alec
  • 946
  • 1
  • 11
  • 22

1 Answers1

0

Ok I figured this out.

CORS has basically nothing to do with what the server will receive, but rather what the browser will accept in response. Without the following code, the browser rejects the response from the server owing to anti-CSRF protection:

app.UseCors(configurePolicy =>
{
    configurePolicy.WithOrigins("http://markscoolsite.com:5000")
                   .AllowCredentials();
});

So this code is required if I want the browser to receive anything. I was focused only on the server's receipt of the cookie.

Alec
  • 946
  • 1
  • 11
  • 22