Sending browser cookies during a 302 redirect - http

Are there any issues with sending back a cookie during a 302 redirect? For example, if I create a return-to-url cookie and redirect the user in the same response will any (modern) browser ignore the cookie?

According to this blog post: http://blog.dubbelboer.com/2012/11/25/302-cookie.html all major browsers, IE (6, 7, 8, 9, 10), FF (17), Safari (6.0.2), Opera (12.11) both on Windows and Mac, set cookies on redirects. This is true for both 301 and 302 redirects.
As #Benni noted :
https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies
The SameSite attribute of a cookie specifies whether the cookie should be restricted to a first-party or same-site context. Several values of SameSite are allowed:
A cookie with "SameSite=Strict" will only be sent with a same-site request.
A cookie with "SameSite=Lax" will be sent with a same-site request, or a cross-site top-level navigation with a "safe" HTTP method.
A cookie with "SameSite=None" will be sent with both same-site and cross-site requests.

One notice (to save developer's life):
IE and Edge are ignoring Set-Cookie in redirect response when domain of the cookie is localhost.
Solution:
Use 127.0.0.1 instead of localhost.

Most browser are accepting cookies on 302 redirects. I was quite sure of that, but I made a little search. Not all modern browsers.
Internet archive Link from a now removed/dead/ microsoft connect Q/A on Silverlight Client HTTP Stack ignores Set-Cookie on 302 Redirect Responses (2010)
I think we now have a replacement for IE6 and it's Windows Mobile browsers...

Here is the Chromium bug for this issue (Set-cookie ignored for HTTP response with status 302).

I just ran into this problem with both Firefox and Safari, but not Chrome. From my testing, this only happens when the domain changes during the redirect. This is typical in an OAuth2 flow:
OAuth2 id provider (GitHub, Twitter, Google) redirects browser back to your app
Your app's callback URL verifies the authorization and sets login cookies, then redirects again to the destination URL
Your destination URL loads without any cookies set.
For reasons I haven't figured out yet, some cookies from request 2 are ignored while others are not. However, if request 2 returns a HTTP 200 with a Refresh header (the "meta refresh" redirect), cookies are set properly by request 3.

We hit this issue recently (Mar 2022) - both Firefox and Chrome didn't set the cookies immediately on HTTP 302 redirect.
Details:
We sent HTTP 302 redirect with Set-Cookie header with "SameSite=Strict" policy and Location pointing at a different path of the same domain.
However, the browser didn't send the Cookie in the subsequent GET request (the redirect's Location), even though it was indeed on the same domain (first-party request).
We could see the Cookie from the browser storage inspect tab, but not in the request immediately following the 302 response.
When we refreshed the page (or hit enter in the address bar), everything worked again, as the Cookie was sent properly in all following requests.
We think this might be a bug / undocumented behaviour. It's like the browser stored the cookie "a little too late".
We had to work around this by serving HTTP 200 with a client-side redirect instead:
<!DOCTYPE html>
<html>
<head><meta http-equiv="refresh" content="0; url='REDIRECT_URL'"></head>
<body></body>
</html>

This is a really frowned upon approach, but if you really want to not rely on 30x set-cookie browser behavior you could use an HTML meta http-equiv="refresh" "redirect" when setting the cookie. For example, in PHP:
<?php
...
setcookie("cookie", "value", ...);
url="page.php";
?>
<html>
<head><meta http-equiv="refresh" content=1;url="<?=$url?>"></head>
<body>Continue...</body>
</html>
Server will send Set-Cookie with a 200 instead of a proper 300x redirect, so browser will store the cookie, and then perform the "redirect". The <a> link is a fallback in case browser does not perform the meta refresh.

Encountered this issue while using OpenIdConnect / IdentityServer on .Net, where a separate API (different hostname) handles authentication and redirects back to the main site.
First (for development on localhost) you need to set CookieSecure option to SameAsRequest or Never to deal with http://localhost/ not being secure. See Michael Freidgeim's answer.
Second, you need to set the CookieSameSite attribute to Lax, otherwise the cookies do not get saved at all. Strict does not work here!

In my case I set CookieOptions.Secure=true, but tested it on http://localhost., and browser hide cookies according to the setting.
To avoid such problem, you can make cookie Secure option to match protocol Request.IsHttps,e.g.
new CookieOptions()
{
Path = "/",
HttpOnly = true,
Secure = Request.IsHttps,
Expires = expires
}

Related

Fiddler requests vs browser requests, identical but different answer from the server

I'm playing a bit with HTTP requests with fiddler.
Basically the site is my router interface which asks for a password.
The password is then encrypted (with a function i have, branded MD5 of some kind) and passed to the server in the body of the POST request.
Here what i've done:
With fiddler i sniffed the browser GET request (got a redirection 302)
With fiddler i sniffed the server response
With fiddler i sniffed the browser POST request (after typing the password)
Browser successfully logged in.
then:
With fiddler composer i performed a GET request equal to the one sniffed. (got a redirection 302)
With fiddler i sniffed the server response (each time the site provides to the client a different Set-Cookie value which is used in the brand MD5 function for antiXRSF attacks).
With fiddler composer i reproduced the sniffed POST request with a different body content due to the new Set-Cookie value.
The body of the post request is indeed correct because it is calculated by the very same function used by the browser.
What came to my mind now:
I'm using the wrong Set-Cookie value --> not possible since if i try to guess the body content of a browser request with the available parameters, the guess turns out to be correct.
The redirection performed by fiddler is done without the Set-Cookie or with a different one --> i saw i can decide not to follow a redirect, is there a way to decide what to pass in the header during a redirection? I'll test more directly on the redirected url.
Regards,
The redirection performed by fiddler is done without the Set-Cookie
Correct. Fiddler's Composer does not have a cookie jar. If a call returns a cookie via Set-Cookie on a redirect, that cookie is not added to a Cookie header when the redirected request is sent.

Are my cookies really HTTP only? Flag is absent in Cookie request header

Ive made some configurations to (finally) have my cookies set on HTTP only.
"Seem" to work.
Ive tried them with postman and I have the following:
When I hit the login page:
On the cookies section, my cookie with name JSESSIONID appears to be HTTP only (it has the check)
When I enter to the logged area , the same result...
The headers dont give me more details.
Then,
I check it with google chrome. I open the developers toolbar.
I load the login page.
At the headers on the response headers I get
Set-Cookie: JSESSIONID=434434..... HttpOnly
So, its fine (I guess).
Then I reload the page (or sign in).
Then the problem:
No response headers received.
The Request Headers brings my cookie (with the same ID at then the previous one) without the httponly, host info or any other cookie value I set before.
At the cookies tab I get Request Cookies only and no Response cookie.
And the request cookie is non http-only
At my resources tab, the Cookie is there, as HTTP only and with the previous values I set.
My question now is... Is it a really http-only cookie? Or my configuration is not properly set?
Should I always get the response cookie or the request cookie should be always http-only (In case I am trying to set it as http-only) or is this behavior normal (or at least accepted) ?
When I try to print my cookie with Javascript at both scenarios I get a null as response (what makes me think then it is correct).
Ideas?
Client doesn't send cookie attributes other than name and value back to server.
See also RFC6265 section 4.2.2 (emphasis mine).
4.2.2. Semantics
Each cookie-pair represents a cookie stored by the user agent. The
cookie-pair contains the cookie-name and cookie-value the user agent
received in the Set-Cookie header.
Notice that the cookie attributes are not returned. In particular,
the server cannot determine from the Cookie header alone when a
cookie will expire, for which hosts the cookie is valid, for which
paths the cookie is valid, or whether the cookie was set with the
Secure or HttpOnly attributes.
Everything's behaving as specified.

FormsAuthentication cookie not sent by browser when clicking external links

We've noticed that for some users of our website, they have a problem that if they following links to the website from external source (specifically Outlook and MS Word) that they arrive at the website in such a way that User.IsAuthenticated is false, even though they are still logged in in other tabs.
After hours of diagnosis, it appears to be because the FormsAuthentication cookie is not sent sometimes when the external link is clicked. If we examine in Fiddler, we see different headers for links clicked within the website, versus the headers which are as a result of clicking a link in a Word document or Email. There doesn't appear to be anything wrong with the cookie (has "/" as path, no domain, and a future expiration date).
Here is the cookie being set:
Set-Cookie: DRYXADMINAUTH2014=<hexdata>; expires=Wed, 01-Jul-2015 23:30:37 GMT; path=/
Here is a request sent from an internal link:
GET http://domain.com/searchresults/media/?sk=creative HTTP/1.1
Host: domain.com
Cookie: Diary_SessionID=r4krwqqhaoqvt1q0vcdzj5md; DRYXADMINAUTH2014=<hexdata>;
Here is a request sent from an external (Word) link:
GET http://domain.com/searchresults/media/?sk=creative HTTP/1.1
Host: domain.com
Cookie: Diary_SessionID=cpnriieepi4rzdbjtenfpvdb
Note that the .NET FormsAuthentication token is missing from the second request. The problem doesn't seem to be affected by which browser is set as default and happens in both Chrome and Firefox.
Is this normal/expected behaviour, or there a way we can fix this?
Turns out this a known issue with Microsoft Word, Outlook and other MS Office products: <sigh>
See: Why are cookies unrecognized when a link is clicked from an external source (i.e. Excel, Word, etc...)
Summary: Word tries to open the URL itself (in case it's an Office document) but gets redirected as it doesn't have the authentication cookie. Due to a bug in Word, it then incorrectly tries to open the redirected URL in the OS's default browser instead of the original URL. If you monitor the the "process" column in Fiddler it's easy to see the exact behaviour from the linked article occurring:

If I change the domain of my site, what happens with the cookies?

We have a site where we are using cookies for tracking purposes. Now we are thinking in changing the domain of our site but we will want to still recognise User's sessions from the old domain. Is this possible?
You can't retrieve cookies that belong to other domains. As a workaround (in case you can still use the old domain); by creating an iframe inside http://newdomain.com from http://olddomain.com, you can get cookies and send to parent via postMessage.
Cookies are affected by same origin policy but you can bypass it with CORS (Cross-origin resource sharing).
CORS is a play between browser and server.
Basic idea is allow ajax request to cross domains but you can use to share cookies(security measures should be taken).
Browser send a request with Origin header.
If the server allows the request then it reply with Access-Control-Allow-Origin header with the value of origin.
If the server doesn’t reply with the header or don’t match Origin with Access-Control-Allow-Origin browser disallow the request.
But it doesn’t send cookies or something like that by default(you have to add “allow-credentials” extra header).
With CORS you can share the session between domains adding to new domain server the following headers:
Access-Control-Allow-Origin: https://original-domain.com
Access-Control-Allow-Credentials: true
More info about CORS:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
http://quickleft.com/blog/cookies-with-my-cors

Cookies not sent after a 302 redirect to a page on the same domain

I'm very confused by this.. My web application uses Spring Security which relies upon a JSESSIONID cookie to maintain a users session.
One of my pages does a 302 redirect to another page on the same domain, still http, not switching to https or anything fancy. For some reason the browser (Chrome in this case) does not pass the cookie with the second request and the user looses his session.
Is this the expected http behavior? I'm probably missing something..
Just to be clear, the cookie is already set before the redirect, I'm not setting the cookie in the same response as the redirect.
It could be a bug in Chrome. See Chromium bug #696204. In my case the workaround was changing SameSite=Strict to Lax.
302 doesn't delete any cookie, so I think you are changing the host/port or the server expires the cookie. Look at this 3 requests (before 302, 302, after 302) and search something related to Set-Cookie header with a expires value.
It could be you have a problem with the cookie path, if you set the cookie path to a something different to '/', it will be not accessible to all paths.
Answering my own question. Turns out that one has to use a 303 (see other) response when redirecting from a post request.
From RFC 2616
10.3.4 303 See Other
The response to the request can be found under a different URI and
SHOULD be retrieved using a GET method on that resource. This method
exists primarily to allow the output of a POST-activated script to
redirect the user agent to a selected resource. The new URI is not a
substitute reference for the originally requested resource. The 303
response MUST NOT be cached, but the response to the second
(redirected) request might be cacheable.

Resources