how to change session id after login in asp.net - asp.net

I have a website that's using forms authentication and membership. A user must have cookies enabled to use the site. I've been asked to change the code so that the session id is changed as soon as a user logs in. Aparently this will protect against a Session Fixation attack (http://en.wikipedia.org/wiki/Session_fixation). Does anyone know how I can change the session id without losing the whole session ? PHP has a specific method for doing this but I can't find a .NET equivalent.

Here's a blog post that talks about this:
ASP.NET does not directly support
functionality to regenerate a session
ID. See the documentation regarding
the issue here. There is a not-so
quick and dirty way to do it by
setting the ASPNET_SessionID value to
the empty string and redirecting so
that the value is regenerated.

I have answered a similar question at Generating a new ASP.NET session in the current HTTPContext. Basically we must change some of the SessionStateModule internal state to be able to regenerate session ID without losing objects in the Session. I used reflection to set the _rqId field to the new ID and _rqSessionStateNotFound to true. The downside is we must grant "Full Trust" to the Application.

This is a really old question I'm resurrecting, but here's the solution:
var manager = new SessionIDManager();
bool redirected, isAdded;
manager.SaveSessionID(System.Web.HttpContext.Current,
"5vonjb4mtb1of2fxvhjvkh5d", out redirected, out isAdded);
// sessionId now equals "5vonjb4mtb1of2fxvhjvkh5d"
var sessionId = Session.SessionID;

The method suggested in Microsoft's obsolete KB article 899918 works well even for .NET framework 4.5 Web Forms applications. Here is the archive of the article: https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/899918
How and why session IDs are reused in ASP.NET
Article ID: 899918
Article Last Modified on 9/8/2006
APPLIES TO
Microsoft .NET Framework 1.1
INTRODUCTION
This article describes how and why Microsoft ASP.NET session IDs are used.
MORE INFORMATION
The ASP.NET session state is a technology that lets you store server-side, user-specific data. Web applications can use this data to process requests from the user for which the session state was instantiated. A session state user is identified by a session ID. The session ID is delivered by using one of the following methods:
The session ID is part of a cookie that is sent to the browser of the user.
The session ID is embedded in the URL. This technique is also known as a cookie-less session.
Session IDs are a 120-bit random number that is represented by a 20-character string. The string is formatted so that it can be included in a URL and it does not have to undergo URL encoding. For example, the string may be used in cookie-less sessions. The most commonly used method of delivering session IDs is by using cookies to store the session IDs.
When a user first opens their Web browser and then goes to a Web site that implements ASP.NET session state, a cookie is sent to the browser with the name "ASP.NET_SessionId" and a 20-character value.
When the user browses within the same DNS domain, the Web browser continues to send this cookie to the domain for which it was sourced.
For example, app1.tailspintoys.com and app2.tailspintoys.com are both ASP.NET applications. If the user goes to app1.tailspintoys.com and then goes to app2.tailspintoys.com, both applications would use the same cookie and the same session ID to track the session state of the user within each application. The applications do not share the same session state. The applications only share the session ID.
Therefore, you can reuse session IDs for several reasons. For example, if you reuse session IDs, you do not have to do the following:
Create a new cryptographically unique session ID when you are presented with a valid session ID.
Create a new session ID for every ASP.NET application that is in a single domain.
When the Web application requires a logon and offers a log off page or option, we recommend that you clear the session state when the user has logged off the Web site. To clear the session state, call the Session.Abandon method. The Session.Abandon method lets you flush the session state without waiting for the session state time-out. By default, this time-out is a 20-minute sliding expiration. This expiration is refreshed every time that the user makes a request to the Web site and presents the session ID cookie. The Abandon method sets a flag in the session state object that indicates that the session state should be abandoned. The flag is examined and then acted upon at the end of the page request. Therefore, the user can use session objects within the page after you call the Abandon method. As soon as the page processing is completed, the session is removed.
When you use the in-process session state mode, these session state objects are stored in the HttpCache. The HttpCache supports a callback method when the following conditions are true:
A cache entry is removed.
The Session State Manager registers the Session_OnEnd event handler to be called when the cache entry is removed.
When the Session State Manager removes a session state object that resides in the cache, the HttpCache manager will call any registered callbacks. In effect, this behavior raises the Session_OnEnd event handler.
When you abandon a session, the session ID cookie is not removed from the browser of the user. Therefore, as soon as the session has been abandoned, any new requests to the same application will use the same session ID but will have a new session state instance. At the same time, if the user opens another application within the same DNS domain, the user will not lose their session state after the Abandon method is called from one application.
Sometimes, you may not want to reuse the session ID. If you do and if you understand the ramifications of not reusing the session ID, use the following code example to abandon a session and to clear the session ID cookie:
Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
This code example clears the session state from the server and sets the session state cookie to null. The null value effectively clears the cookie from the browser.
When a user does not log off from the application and the session state time-out occurs, the application may still use the same session state cookie if the browser is not closed. This behavior causes the user to be directed to the logon page and the session state cookie of the user to be presented. To guarantee that a new session ID is used when you open the logon page (login.aspx), send a null cookie back to the client. To do this, add a cookie to the response collection. Then, send the response collection back to the client. The easiest way to send a null cookie is by using the Response.Redirect method. Because the cookies collection always has a value for the ASP.NET_SessionId, you cannot just test if this cookie exists because you will create a Response.Redirect loop. You can set a query string on the redirect to the logon page.
Or, as illustrated in the following code example, you can use a different cookie to tell if you are already redirected to the logon page. To help enhance security and to make sure that no one tries to open the logon page by using a second cookie together with the ASP.NET cookie, the following code example uses the FormsAuthentication class to encrypt and decrypt the cookie data. Then, the code example sets a 5-second time-out.
private void Page_Load(object sender, System.EventArgs e)
{
if( !IsPostBack && ( Request.Cookies["__LOGINCOOKIE__"] == null || Request.Cookies["__LOGINCOOKIE__"].Value == "" ) )
{
//At this point, we do not know if the session ID that we have is a new
//session ID or if the session ID was passed by the client.
//Update the session ID.
Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
//To make sure that the client clears the session ID cookie, respond to the client to tell
//it that we have responded. To do this, set another cookie.
AddRedirCookie();
Response.Redirect( Request.Path );
}
//Make sure that someone is not trying to spoof.
try
{
FormsAuthenticationTicket ticket =
FormsAuthentication.Decrypt( Request.Cookies["__LOGINCOOKIE__"].Value );
if( ticket == null || ticket.Expired == true )
throw new Exception();
RemoveRedirCookie();
}
catch
{
//If someone is trying to spoof, do it again.
AddRedirCookie();
Response.Redirect( Request.Path );
}
Response.Write("Session.SessionID="+Session.SessionID+"<br/>");
Response.Write("Cookie ASP.NET_SessionId="+Request.Cookies["ASP.NET_SessionId"].Value+"<br/>");
}
private void RemoveRedirCookie()
{
Response.Cookies.Add(new HttpCookie("__LOGINCOOKIE__", ""));
}
private void AddRedirCookie()
{
FormsAuthenticationTicket ticket =
new FormsAuthenticationTicket(1,"Test",DateTime.Now,DateTime.Now.AddSeconds(5), false,"");
string encryptedText = FormsAuthentication.Encrypt( ticket );
Response.Cookies.Add( new HttpCookie( "__LOGINCOOKIE__", encryptedText ) );
}

Related

when does a session get created in any asp.net web application?

Does a session get created for every page request ? even though we don't have any forms authentication enables or any session objects created in the application ?
From Microsoft Docs:
The SessionID property is used to uniquely identify a browser with session data on the server. The SessionID value is randomly generated by ASP.NET and stored in a non-expiring session cookie in the browser. The SessionID value is then sent in a cookie with each request to the ASP.NET application.
So, when a browser requests a resource which requires session state, if the Session State Module cannot find an existing session ID (either in the ASP.NET session cookie, or in the URL in the case of cookieless sessions), then a new session ID is created and returned in the session ID cookie.
The session ID is used to retrieve a set of session state values (commonly known as "session variables"). Data stored in such a "variable" will remain available as long as the session exists. If the session times out, or if the AppDomain restarts, or if the cookie becomes unavailable, then the session "variable" will contain null. Code using session state must be prepared for this:
bad code:
string user = Session["User"];
int length = user.Length; // NullReferenceException if session was expired
better code:
string user = Session["User"];
if (user == null) {
// Do without the user information
} else {
int length = user.Length; // User information is available
}
Session state data is shared across all the data forms but for the sing user global data.
Declaration For the session :
Session["Key"] = "value";
Session data are stored on the server side.
Session state variables are declared when session times out.
By default time out for session is 20 minutes.
For Example :
**If you are using session & you are executing the first session web form & suppose you have navigated your page from web-form 1 to web-form 2.
Then Session output will be the same.
If suppose your o/p for web-form 1 is "2".
Then if you have closed the browser & copy and paste the same URL to another browser.
then you will notice that o/p will be the same Because In your URL session ID is present.
there for it will have the same o/p.
This is very Important to understand about session if you want to use the session in your application.**
ie session data session state data shared across all the web-form but only fr single user.
For every session Unique session ID is generated.
But is you have changed your session then new session ID is generated meaning it is only for single user.

Asp.Net: Retaining the old browser session after closing and reopening browser instance

Is there a way I can retain the browser session after the user has closed his browser and then reopens.
The default behavior in asp.Net is that it keeps the Asp.Net SessionId in the browser cookie which expires when we close the browser. On reopen the browser asp.net generates a new SessionId and even if the old session is not expired on the server side we can not retain it.
Can we control the expiration behavior of the session cookie in Asp.Net?
You cannot reclaim the session-id as such, but you can certainly restore some of the predictable part of the session state. If you are using forms authentication, then just read the forms-auth cookie in global.asax session start and re-populate the session objects.
You can control the expiration of forms-authentication cookie manually by creating a persistent cookie by using:
FormsAuthentication.SetAuthCookie(userName, true)
Alternatively, you can fine-tune the expiration by manually changing the cookie:
Dim authCookie As HttpCookie = FormsAuthentication.GetAuthCookie(userName)
Dim authTicket As FormsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value)
Dim newAuthTicket As New FormsAuthenticationTicket(authTicket.Version, authTicket.Name, authTicket.IssueDate, expireDate, authTicket.IsPersistent, userData)
authCookie.Value = FormsAuthentication.Encrypt(newAuthTicket)
authCookie.Expires = newAuthTicket.Expiration
HttpContext.Current.Response.Cookies.Set(authCookie)
Where expireDate specifies when the cookie should expire.
Now in global.asax session start you can check if the returning user is still authenticated (by virtue of persistent cookie previously set):
If HttpContext.Current.User.Identity.IsAuthenticated Then
' Here re-populate the predictable part of session state
' Like user profile etc.
End If
Added after Op insights:
Forms authentication is not being used, and the aim is to be able to just restore the previous session.
In such a case the only option is to persist the existing session by way of a persistent cookie, so that you can retrieve it later. There are some workarounds to achieve this. One of the workarounds is explained here by this blog writer:
http://weblogs.asp.net/imranbaloch/archive/2010/06/09/persisting-session-between-different-browser-instances.aspx
What is happening here is that we intercept two events in the global.asax:
PostRequestHandlerExecute: (Occurs when the ASP.NET event handler finishes execution) In this handler, we create a new cookie (say temp), value of which is assigned the value of current SessionId. We make it a persistent cookie by setting the expires property to the session timeout.
PostMapRequestHandler: (Occurs when ASP.NET has mapped the current request to the appropriate event handler) In this handler, we check the returning user by checking the existence of the "temp" cookie. If found, we update the actual session cookie (ASP.NET_SessionId) with the value of our "temp" cookie; thereby effectively restoring the previous session.
Please note that this is just a workaround. The system is designed to create a new session. All we are doing is to use a few hooks to workaround this by persisting an existing session to retrieve it later. All security implications stand.
At the Least you can retrieve Session information. This can be done easily when you set the 'Mode' to "SqlServer".
You can Query the Database (ASPState) & hence the table (ASPStateTempSessions) where you are storing your Sessions.[ I used persistent storage: -sstype p ]
SELECT TOP 5 [SessionId]
,[Created]
,[Expires]
,[LockDate]
,[LockDateLocal]
,[LockCookie]
,[Timeout]
,[Locked]
,[SessionItemShort]
,[SessionItemLong]
,[Flags]
FROM [ASPState].[dbo].[ASPStateTempSessions]
Even if you know your sessionID, you may use it to restore your previous session. Asp.Net will generate a new SessionID when you do a new request.

HttpCookie is not deleted when session changes or is invalid

I'm creating an HttpCookie, setting only the name and value and not the expires property, then adding it to the response. Simple enough. The cookie is created (but not persisted) as expected. The problem is when the session changes for some reason (like the website was rebuilt, or I rebuilt my app when debugging) then the cookie stays around. I want the cookie to be valid for only the original session it was created on.
According to MSDN it says: "If you do not specify an expiration limit for the cookie, the cookie is not persisted to the client computer and it expires when the user session expires."
I guess I don't know exactly what "session expires" encompasses. I figure the cookie gets deleted after 20 min when the session expires. But should the cookie get deleted if the session it was created on doesn't exist anymore for any number of reasons? The only time I've seen the cookie get deleted is when the user closes all browser windows and opens a new one.
If this is all true, I may have to store the original session id ("ASP.NET_SessionId") in the cookie, then check it against the current session id, if they're different, then delete the cookie or create a new one.
Here's the code (the only difference between my cookie and the one in the MSDN examples is I'm storing multiple values in the cookie):
private void SaveValuesToCookie(string[] names, string[] values)
{
HttpCookie cookie = new HttpCookie("MyCookie");
for (int i = 0; i < names.Length; i++)
{
string name = names[i];
cookie.Values[name] = values[i];
}
Response.Cookies.Add(cookie);
}
private string GetValueFromCookie(string name)
{
HttpCookie cookie = Request.Cookies["MyCookie"];
if (cookie == null)
return null;
return cookie.Values[name];
}
The only time I've seen the cookie get
deleted is when the user closes all
browser windows and opens a new one.
And that is exactly what MSDN means when it says the cookie will be deleted when the session expires. Unfortunately, I believe this isn't consistant across browsers anyway, so it's not much use to anyone.
You should always set an expiry date on Cookies.
If this is all true, I may have to
store the original session id
("ASP.NET_SessionId") in the cookie,
then check it against the current
session id, if they're different, then
delete the cookie or create a new one.
I hate to say it but this isn't going to help you either. The .NET Framework likes to recycle session IDs, so you can't guarantee it will be different.
Bad news out of the way, I would advise you to reconsider what you're trying to do from an architectural standpoint.
Restarting the app is something that happens entirely on the server; cookies are something that happen entirely on the client. While the client will talk to the server, it is purely a Request/Response relationship, the server cannot communicate events such as an application restart to the browser.
If you want to store a value somewhere which is only valid for the lifespan of a server session, why not store it in Session rather than in a Cookie?
I'm aware of all that, but it's not secure enough for our clients needs. The session can still get spoofed or injected. See: http://msdn.microsoft.com/en-us/magazine/cc163730.aspx#S9
Looks like I'm left to creating an expired secure cookie separate of the session, and refreshing the expiration date when I can (ie when the user accesses certain pages).

Session Fixation in ASP.NET

I'm wondering how to prevent Session fixation attacks in ASP.NET (see http://en.wikipedia.org/wiki/Session_fixation)
My approach would to this would normally be to generate and issue a new session id whenever someone logs in. But is this level of control possible in ASP.NET land?
Have been doing more digging on this. The best way to prevent session fixation attacks in any web application is to issue a new session identifier when a user logs in.
In ASP.NET Session.Abandon() is not sufficient for this task. Microsoft state in http://support.microsoft.com/kb/899918 that: ""When you abandon a session, the session ID cookie is not removed from the browser of the user. Therefore, as soon as the session has been abandoned, any new requests to the same application will use the same session ID but will have a new session state instance.""
A bug fix has been requested for this at https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=143361&wa=wsignin1.0&siteid=210#details
There is a workaround to ensure new session ids' are generated detailed at http://support.microsoft.com/kb/899918 this involves calling Session.Abandon and then clearing the session id cookie.
Would be better if ASP.NET didn't rely on developers to do this.
Basically just do this in your Login GET method and your Logout method:
Session.Clear();
Session.Abandon();
Session.RemoveAll();
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 I am assuming right, you are talking about... http://en.wikipedia.org/wiki/Session_fixation. The short answer is yes, you have a lot of ways in which you can secure your cookie as well. You shouldn't be using cookieless session, and while you are using sessions, ensure that you have secured the cookie as well explicitly.
Check this article out... http://blogs.msdn.com/rahulso/archive/2007/06/19/cookies-case-study-with-ssl-and-frames-classic-asp.aspx
It does generate a new session ID when the user logs in, and kills a session when the timeout occurs, or the user navigates away/close the browser. And you can programmably kill it via Abandon() or remove entries via Remove().
So I'm not sure what the issue is?

Can I abandon an InProc ASP.NET session from a session different than one making the request?

We have an application that does single sign-on using a centralized authentication server (CAS). We'd like to do single sign-out, such that if the user logs out of one application (say a front-end portal), the user is automatically signed out of all applications using the same single sign-on ticket.
The expectation would be that each application would register a sign-out hook (URL) with the CAS at the time of logon to that application. When the CAS receives the sign out request from one of the applications, it invokes the sign-out hook for all the application sharing the SSO ticket.
My question is this: is there a way to abandon an InProc session from a different session? I presume, since the HTTP request will be coming from the CAS server, that it will get its own session, but it is the session of the user that I want to terminate. I have pretty good idea of how to do this using a separate session state server, but I'd like to know if it is possible using InProc session state.
Haha, well... It looks like you can. I was wondering myself if there was any way to do this, turns out, there is.
When you use InProc, the InProcSessionStateStore (internal class) persist the session state in an internal (non public) cache. You can access this cache through reflection and remove the session state manually.
using System;
using System.Reflection;
using System.Web;
object obj = typeof(HttpRuntime).GetProperty("CacheInternal",
BindingFlags.NonPublic | BindingFlags.Static)
.GetValue(null, null);
if (obj != null)
{
MethodInfo remove = obj.GetType()
.GetMethod("Remove", BindingFlags.NonPublic | BindingFlags.Instance,
Type.DefaultBinder, new Type[] { typeof(string) }, null);
object proc = remove.Invoke(obj, new object[] { "j" + state.SessionID });
}
The end result is, that the next request will take on the same SessionID, but the HttpSessionState will be empty. You'll still get the Session_Start and Session_End events.
After doing a bit of digging around and considering the answers provided so far I've come up with an alternative that lets me continue to use InProc session. Basically, it consists of extending the HttpModule that already handles single sign-on to detected CAS sign outs and redirect the browser to the application sign out page.
Outline:
Sign-On:
For each new single sign-on request, create a new SSO cookie and encode a unique value in it to identify the session (not the session id, so it isn't leaked).
Construct the the sign-out callback url, encoded with the identifier, and register it with the CAS server.
Sign-Out:
When a sign-out request is received from the CAS server, decode the identifier and store it in an application-wide cache. This needs to be pinned in the cache at least long enough for the session to expire naturally.
For each request, look for the SSO cookie and check its value against the cached, signed-out session identifiers. If there is a hit, remove the SSO cookie and redirect the browser to the application's sign-out url.
For each sign-out, check to see if there is an SSO cookie, if so, forward the sign-out request to the CAS. In any event, abandon the user's session, and sign them out of the application.
Page_Load:
Check for the presence of the SSO cookie. If there isn't one, redirect to the sign out page.
No can do.
http://forums.asp.net/p/416094/416094.aspx#416094
With InProc SessionState, you won't be able to access the data... With StateServer, you still will have a sticky scenario trying to access the correct API to remove the session.
You will most likely want to use a database backed state solution like the pre-packaged SqlServer state provider or a third party solution like DOTSS: http://codeplex.com/dotss
With the database backed solution, you will be able to lookup the state record in a table by session id and mark it as completed. These techniques will vary based on the provider you choose.

Resources