FormsAuthentication.SignOut() does not expire the FormsAuthenticationTicket - asp.net

First off, this is not a problem with the ASP.NET session not expiring, we clear, abandon, and delete every cookie on logout.
This is about FormsAuthentication.SignOut() not expiring the ticket when called and allowing someone who copies the content of the cookie to manually create the cookie somewhere else and still be able to acces everything that is meant to now be blocked off after the logout.
Here is the gist of our logout method:
HttpContext.Current.User = null;
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Session.Clear();
HttpContext.Current.Session.Abandon();
HttpContext.Current.Session.RemoveAll();
HttpContext.Current.Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
We also let ASP manage the creation of the ticket and the authentication via our Web.config and whatever else manages FormsAuthentication. Here is what is in the config:
<authentication mode="Forms">
<forms name="COOKIENAME" loginUrl="~/PAGE_THAT_REDIRECTS_TO_LOGIN.aspx" defaultUrl="~/PAGE_THAT_REDIRECTS_TO_LOGIN_OR_PROPER_PAGE_IF_LOGGED_IN.aspx" cookieless="UseCookies" timeout="60" />
</authentication>
Now, why is this an issue? simple, it's a security concern as if someone gets the cookie and keeps it alive, they can access whatever the user matching the cookie can, even though the user has been disconnected.
Is there is a proper way to force the FormsAuthenticationTicket to expire?
I tried decrypting it, but everything is readonly, and I also tried to create a new expired ticket and encrypting it, but it doesn't overwrite the old one.
Thanks
Versions: .NET 4.5.1, ASP.NET (not Core)

The basic problem is with Microsoft .net Core cookie Managemnt, it does not handle the lifetime of cookies correctly.
I had face this issue several times, and mostly with .Net core now.
To solve this issue we need to override their cookie management class, and implement ITicketStore interface.
https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs#L136
Below article can help you with detail implementation.
https://mikerussellnz.github.io/.NET-Core-Auth-Ticket-Redis/
I hope it helps.

Related

SetAuthCookie Setting Cookie, but not IsAuthenticated on Subsequent Requests

I have some code where we create an authentication ticket. After creating the ticket, we call SetAuthCookie to set the cookie such as:
FormsAuthentication.SetAuthCookie(username, true);
Response.Redirect("/", true);
If I check on the root page to see if the user is authenticated, it returns false. However, if I hard code the username in and do:
FormsAuthentication.GetAuthCookie("jason", true).value);
I get the appropriate cookie value. So, the cookie exists. But the name and the flag are not modified. Any ideas as to what my issue could be? I'm using ASP.NET 4 and MVC.
Solved
I was missing the forms section in the web.config. It was removed for local testing as the login form resides on another server. So, adding the following to web.config solved my issue:
<authentication mode="Forms" />

Session hijacking and Session fixation

We have Session hijacking and Session fixation problem with our asp.net application.
We have implemented SSL also.
1.. I have added below code in web.config file.
<----
<httpCookies httpOnlyCookies="true" requireSSL="true" />
<forms loginUrl="Homepage.aspx"
protection="All"
timeout="20"
name=".ASPXAUTH"
path="/"
requireSSL="true"
slidingExpiration="true"
/>
--->
2... Encrypting formsathuntication ticket and adding to the cookie after user is athunticated.
<---
FormsAuthenticationTicket tkt;
string cookiestr;
HttpCookie ck;
tkt = new FormsAuthenticationTicket(1, uname, DateTime.Now, DateTime.Now.AddMinutes(20),false, "your custom data");
cookiestr = FormsAuthentication.Encrypt(tkt);
ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
ck.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(ck);
-->
3.. I'm removing session variables and passing null value to ASP.NET_SessionID on logout page and Error page.
SessionHandler.EndSession();
Session.RemoveAll();
Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
if (Request.Cookies["ASP.NET_SessionId"] != null)
{
Response.Cookies["ASP.NET_SessionId"].Value = string.Empty;
Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.Now.AddMonths(-20);
}
if (Request.Cookies["AuthToken"] != null)
{
Response.Cookies["AuthToken"].Value = string.Empty;
Response.Cookies["AuthToken"].Expires = DateTime.Now.AddMonths(-20);
}
HttpCookie authcookie = Request.Cookies[FormsAuthentication.FormsCookieName];
authcookie.Expires = DateTime.Now.AddDays(-1D);
Response.Cookies.Add(authcookie);
FormsAuthentication.SignOut();
still problem is not solved...
Is your problem session hijacking, or authentication hijacking?
Are you trusting session values without validating identity? (Note that session and authentication are not intrinsically linked in ASP.NET).
If you've implemented SSL, why is your session cookie still set to requireSSL="false"?
Research best-practice, and see for yourself where you've gone wrong. For example - http://www.troyhunt.com/2010/07/owasp-top-10-for-net-developers-part-3.html
To elaborate on point 2.
There are two cookies in use here, one is for Session, the other for FormsAuthentication.
The FormsAuth cookie identifies the user, and all reasonable steps need to be taken to keep this one secure. Typically, requiring SSL is a good step (as you've applied in the edit of your example). The Session cookie though, often doesn't come under as close scrutiny for developers, but depending on how you're using it can be just as sensitive. A session fixation steals the session, not the authentication.
An example:
UserA logs in, they are an admin user. They receive a FormsAuth cookie stating "This is UserA", they might also get a session cookie stating "This User Is Admin".
UserB gets a copy of the session cookie belonging to UserA (they might do this via interception, or even just by being on the same machine after UserA logs out if the session cookie isn't cleared).
UserB logs in, they are a "read-only" user (not admin). They receive a FormsAuth cookie stating "This is UserB", they then inject the session cookie stolen at step 2. Meaning they have a FormsAuth cookie stating "This is UserB", and a Session cookie stating "This User Is Admin".
Presto, UserB is now admin.
The problem here (as it relates to point 2 of my original list of concerns), is that the server didn't verify the identity of the user in relation to its session. You can do your best to try and link the Session and Forms authentication tickets together somehow, and definitely make certain you're encrypting (SSL). OR, you can stop storing sensitive data in the session (or at least reduce it). When it comes to my "This User Is Admin" example above, the better implementation is to use the ASP.NET Role and Profile providers in conjunction with the Membership provider. The three of them go hand in hand, and there's a lot of examples out there on how to use them to your advantage.
This is only one possible line of investigation though and as #JohnFx rightly pointed out, you really need a focused question here before you can expect a good answer. When it comes to security implementation, it's important to understand the concepts involved, instead of just throwing example code at the issue. Your example code provided thus far looks suspiciously similar to a CodeProject article discussing session fixation, but do you understand what it's trying to accomplish? Do you know if it even applies to the problem you're experiencing?

How to properly handle Forms Authentication Ticket when using a Cookie-less Session

I am pretty sure I do not have a unique problem, but I have searched all over google and this site and I haven't found a solid answer for what I am looking for. So I wanted to explain myself to see if I could get any help on this issue:
We (my co-workers and I) determined that we need have cookie-less Sessions because our users require multiple sessions to get their work done in a more productive fashion.
Example
Bob the user could have initiated a long running process in window A and in order to continue working Bob will open window B which spawns a new session. This is necessary in order to not disturb what is going on in window A. Every time Bob opens a new window, he has to log in again.
The Problem
I am not really sure if this is a real problem or not, hence my reason for asking. The problem I think I have discovered is that each time Bob logs in, the current Forms Authentication Ticket (and Cookie) are over-written. Now I do not understand how this is okay or why the previous Session/Window combo is still valid after Bob logs in a second time. Since the ticket was over-written doesn't that mean the first Session/Window combo should end because the ticket is no longer valid? This is with respect to:
Request.IsAuthenticated //Making sure the supplied ticket is valid
Questions
So since the Forms Authentication Ticket (and Cookie) are being over written, what does this mean?
Should I be concerned that the ticket (and Cookie) are being over written?
During login, should I be intercepting the ticket (if any) and checking for its expiration? If it is not expired should I try to renew the ticket or just make a new one?
FormsAuthentication.RenewTicketIfOld(ticket) //Just an example
If I am using a cookie-less session should I just use cookie-less Forms Authentication too? The point of doing this would be to make each Session/Window 100% independent of each other. No over-writing would occur anymore. Is there a draw back to this? I can't think of any.
PS: I know the cookie is just a container for what ever is being stored in it, like a Key Value pair.
Additonal Info...
Forms Authentication Ticket:
IsPersistent set to true
Ticket Version 2
Forms Cookie:
Key = FormsCookieName (from web.config tag)
Value = Hashed Ticket
Web.Config:
<sessionState
cookieless="true"
mode="SQLServer"
sqlConnectionString="..."
timeout="300"
regenerateExpiredSessionId="true" />
<forms name="FormsCookieName"
path="../"
loginUrl="Login.aspx"
protection="All"
timeout="300"
slidingExpiration="true" >
</forms>

ASP.NET: Authenticating user in code

I'm playing around with authentication and authorization to prepare for some task. I've created two pages: Login.aspx and Default.aspx. In config file i've set authentication to forms and denied unauthenticated users access:
<authentication mode="Forms">
<forms name="aaa" defaultUrl="~/Login.aspx" />
</authentication>
<authorization>
<deny users="?"/>
</authorization>
Then I've written some simple code to authenticate my user in Login.aspx:
protected void Page_Load(object sender, EventArgs e)
{
GenericIdentity identity = new GenericIdentity("aga", "bbb");
Context.User = new GenericPrincipal(identity, new String[] { "User" }); ;
Response.Redirect("~/Default.aspx");
}
When i run it, the redirection doesn't take place. Instead Login.aspx is called over and over because the user is not authenticated (Context.User.Identity.IsAuthenticated is false at every load). What am i doing wrong?
Context.User only sets the principal for the current request. Once the redirect takes place, the current request ends and a new one begins with the non-overridden principal again (which is apparently not authenticated). So, setting Context.User doesn't actually authenticate anything.
Using FormsAuthentication.SetAuthCookie() will set the user's cookie to a valid value accepted by the FormsAuthentication provider, or put the token in the URL. You can redirect to your heart's content because the cookie obviously sticks with the user for future requests.
From MSDN (em added):
With forms authentication, you can use the SetAuthCookie method when you want to authenticate a user but still retain control of the navigation with redirects.
As stated, this does not necessarily require cookies - the name is a little misleading, because it will still work via the URL if FormsAuthentication is in cookieless mode:
The SetAuthCookie method adds a forms-authentication ticket to either the cookies collection, or to the URL if CookiesSupported is false.
Use FormsAuthentication.SetAuthCookie(..). Or FormsAuthentication.RedirectFromLoginPage(..).
You need to actually set the user as authenticated. All of the following methods will work and let you actually get away from your login screen.
FormsAuthentication.Authenticate()
FormsAuthentication.RedirectFromLoginPage()
FormsAuthentication.SetAuthCookie()
Lots of ways to get to the same result.
You need to actually make a call to the formsAuthentication provider to set the login.
FormsAuthentication.RedirectFromLoginPage(txtUser.Text, chkPersistLogin.Checked)
is a simple example
After creating the dummy Context.User, you need to perform a FormsAuthentication.SetAuthCookie or RedirectFromLoginPage method.

How do I logout of multiple asp.net applications?

I have a main asp.net app, which is written in asp.net 1.1. Runnning underneath the application are several 2.0 apps. To completely logout a user can I just logout of the 1.1 app with FormsAuthentication.SignOut or is it more complicated than that?
What you are looking to do is called Single Sign On and Single Sign Off. There are differences based on how you have the applications set up. I will try to clarify where those differences come into play.
To implement single sign on and single sign off you need to make the cookie name, protection, and path attributes the same between all the applications.
<authentication mode="Forms">
<forms name=".cookiename"
loginUrl="~/Login.aspx"
timeout="30"
path="/" />
</authentication>
Next you need to add the machine keys and they need to be the same between all your applications.
<machineKey validationKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902"
encryptionKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902F8D923AC"
validation="SHA1" />
Are you using second or third level domains for the applications? If so you will need to do a little bit more by adding the domain to the cookie:
protected void Login(string userName, string password)
{
System.Web.HttpCookie cookie = FormsAuthentication.GetAuthCookie(userName, False);
cookie.Domain = "domain1.com";
cookie.Expires = DateTime.Now.AddDays(30);
Response.AppendCookie(cookie);
}
Now to do single sign off, calling FormsAuthentication.SignOut may not be enough. The next best thing is to set the cookie expiration to a past date. This will ensure that the cookie will not be used again for authentication.
protected void Logout(string userName)
{
System.Web.HttpCookie cookie = FormsAuthentication.GetAuthCookie(userName, False);
cookie.Domain = "domain1.com";
cookie.Expires = DateTime.Now.AddDays(-1);
Response.AppendCookie(cookie);
}
I am taking into consideration you are using the same database for all the applications. If the applications use a separate database for registration and authentication, then we will need to do some more. Just let me know if this is the case. Otherwise this should work for you.
It could be easier if you are having a central session store for all your applications. You can then set the session to null in one place.
This worked for me:
In the Logout event, instead of FormsAuthentication.GetAuthCookie method use Cookies collection in Request object as below:
HttpCookie cookie = Request.Cookies.Get(otherSiteCookieName);
cookie.Expires = DateTime.Now.AddDays(-1);
HttpContext.Current.Response.Cookies.Add(cookie);
Ofcourse, this requires u know the Cookie name of the site(s) you want the user to be logged out - which however won't be a problem if you are using the same cookie across all the web apps.
I prefer to use web.config
<authentication mode="Forms">
<forms domain=".tv.loc" loginUrl="~/signin" timeout="2880" name="auth" />
</authentication>

Resources