we are experiencing an odd situation when validating CSRF tokens. Here is the sequence of events with the tokens replaced by letters:
User logs out. Gets redirected to home page.
Session.Abandon(); FormsAuthentication.SignOut();
A new session is created with a new session id (S1) and a new CSRF token (T1).
protected void Session_Start(object sender, EventArgs e) { Response.Cookies["ASP.NET_SessionId"].Secure = true; Token = NewToken(); }
The home page loads and fires a JS Ajax request which carries token (T1) for validation. From inspection, we know that for some reason this request carries a blank ASP.NET_SessionId cookie (
ASP.NET_SessionId=;
) when it should have session id (S1). Hence, it is treated as a new session on the backend and step 2 is repeated for this request. Backend now has new session id (S2) and new token (T2).- The backend continues servicing the Ajax request. It compares token (T1) to token (T2) and it fails.
- Subsequent calls on the site after either refreshing the page or navigating to another page succeed without issue. Ajax requests carry the ASP.NET_SessionId cookie and everything works as expected. They execute under session id (S1) and Token (T1).
We have managed to partially track down the issue to the ASP.NET_SessionId
cookie being set to HTTP Only
:
Response.Cookies["ASP.NET_SessionId"].Secure = true;
If we remove this, it works on both, the first request after log out as well as subsequent requests. The ASP.NET_SessionId
cookie is sent on all Ajax calls.
We [obviously] want to keep the cookies secure, so removing Secure = true
is not an option.
Why do Ajax requests on the first page load after logout not pass a value for the ASP.NET_SessionId
cookie but subsequent requests do? It's almost like the ASP.NET_SessionId
cookie is not ready or available in JS for the initial request after load, but can be read in subsequent requests (navigation/reload).