One application, different domains: how to preserve sessions on ASP.NET? - asp.net

I have an application with different sections. Each section is accessed through a domain. Example: www.section1.com, www.section2.com, www.section3.com. I need to preserve the session when the user navigates from one to another URL. The application is the same in IIS. How to accomplish that?

You will need to pass on the session-cookie, and re-set that cookie on the new domain. That will make the session live over several domains (assuming you use the same app).
Example:
Link from section1.com:
<a href="http://www.section2.com/?s=askdjh3k4jh234kjh">
then, OnSessionStart (or OnRequestStart) check for query-parameter s and attach session to it. Meaning, just manually set cookie ASP.NET_SESSIONID to the value you pass on.
This has severe security-implications, so don't allow this unless you know what you're doing. another solution might be to store something into a common backend (database?) and pass around the user with a token that represents the actual session (and set the cookie based on that token), that you generate on a middle-page when navigating away from section1.com -> transferusertonewdomain.aspx -> section2.com/?token=randomTokenThatMatchSessionInDatabase
That would prevent that anyone could hijack a session by jsut knowing the value of the cookie. However, that is possible never the less if you're somewhat familiar with a computer anyway.

If you have multiple domains (and not just subdomains, which are easier), you're going to have more complications doing this than you'd like, because you can't share cookies across different domains.
The usual workaround is to embed a link an image on the other domains that are served by an asp.net page (or HttpHandler if you like). That page should contain a querystring with a unique token and a hashed version of that data appended with some shared secret. Then, that page will set a cookie on the response appropriate to for that domain to associate itself with appropriate data. It will serve typically a 1x1 transparent image as the response. Usually you only want to do this upon login to one of the sites.

Unless you do some customizations, session is specific to an application regardless of session mode you are using. Here's an article that talks about how to customize SQL session so that you can use session across multiple applications.

You should start by change the sessionState from being "InProc" to either StateServer or SqlServer, ensure that the MachineKeys are identical across all sites (domains and servers), and then set up the relevant backend systems to capture the state information.
More information can be found on:
Session-State Modes
ASP.NET State Management Overview

You could use a cookie to pass it, still researching to find out how. I will repost.
** EDIT
There is another Stack Overflow question, see if it helps, 315132
It basically asks
I need to share SSO information
between two different domains with a
cookie, can this be done in PHP and
how?
the answer given was
On both domains, place an image or
other web element that is pulled from
the other domain. Use the URL to
notify the other domain that user X is
on domain A, and let domain B
associate that user ID with that user
on their system.
It's a little complex to carry out
correctly, but if you think it through
it'll work out very well.
Vinko points out in a comment
(thanks!) that I shouldn't take it for
granted that you understand the
security risks involved. If this
information is of any value to anyone,
then you should make sure you use
proper encryption, authentication, etc
to avoid releasing sensitive
information and to avoid various
attacks (replay, man in the middle,
etc). This shouldn't be too onerous
since you control both websites and
you can select a secure secret key for
both, since the communication is only
going between the two servers via this
special URL. Keep it in mind though.
The user is Adam Davis.

Related

Set domain of session cookie dynamically in ASP.NET

I use session objects in my web application which are traced by ASP.NET session cookie internally as we all know. So access to that cookie is essential to have access to session objects. I want my asp.net application work under http:// and http://www or any subdomain (domain is unknown to me at development time).
Can't be done. The session cookie only works for 1 domain and 1 domain only.
You could, however, write your own session management system and maybe accomplish shared session that way. I still don't think you'd be able re-use the cookie because the browser won't even send it in the first place.
After some more thought I've decided that I'm not sure. :) Perhaps if both subdomains map to the same ASP.NET application you could get share session to work. All you'd have to do is set your cookies as such:
<httpCookies domain=".maindomain.com">
If the different subdomians don't map to the same app, I think you'd definitely have to write your own session management.
Clearly, at this point you should take everything I've written with a grain of salt. I'm only leaving my answer up for you to get some ideas and so that people may comment on the correctness of it.
Why don't you leave domain field empty? That way you won't bind your cookies to some specific domain and will be able to play well whatever the domain of your site will be.

Is it possible to authenticate on another website?

If I am on a website#1, and I enter my username/pwd for website#2 on a login page that is on website#1, and website#1, behind the scenes, makes a httpwebrequest to website#2 and posts to the login page. If I then navigate to website#2, should I be logged in?
website#2 uses formsauthentication and I call a httpHandler that is on website#2 and pass it the username/password via the querystring.
Should this work?
What you're trying to do is called Single Signon. The way you're doing it, posting values from one site to another, probably won't work because you're using the same technique a hacker might use to trick user into sharing their login information. It's called a cross-site request forgery attack. IIS is configured not to allow that.
Generally, you need a central authentication system that both sites use to share login information. This can be done in several ways, including a shared database-based login system. Google "asp.net single sign on" for more ideas.
Do site #1 and #2 want their users to have single sign on?
If so, read up on single sign on. It's a bigger project than can be addressed here. There is a good book on it though from Wrox :
http://www.amazon.com/Professional-ASP-NET-Security-Membership-Management/dp/0764596985/ref=cm_lmf_tit_10
Or are we imagining something sinister?
If we are imagining something sinister, then evil site #1 would collect the credentials, then automate a browser on the server side to start checking to see if site #2 uses the same password and user combination. Then the server would have an authenticated session. This wouldn't give the user who accessed site #1 an auth cookie, the HttpWebRequest object on the server would get the auth cookie. Site #2 couldn't really do anything to prevent this because a browser request from one computer looks much alike a browser request from another. A well crafted attack would spoof all elements of the browser's request so that it looks like it came from a browser instead of a primitative HttpWebRequest object, which may not even set the user-agent.
Site #2 should stop using passwords and user Id or use 2 factor ID if they are concerned abut this, or do something that requires javascript for logon because spoofing a browser that is executing javascript is harder than spoofing a browser that just sends and receives http requests and responses.
There are too many security issues trying to auto-authenticate between sites. There needs to be a central security provider that both sites belong to so that hand off is completed securely.
We use CA's Siteminder for cross site authentication. Effectively, web 1 creates a unique session id on the siteminder server and passes any credentials and info to it. Siteminder invokes web2 and passes the information by means of session variables. Web 2 retrieves the data from the session and uses it. There's much more going on there but that's the just of it.
To do something like this, I would strongly consider using an out of the box solution as generally coding up custom security generally falls short.
While this can be done on some cases, in the form of an HTTP request with POST parameters, you will not be authenticated once you browse to site #2.
This is because, generally, these sites store a cookie on your end and these are domain-based, which means that even if you grabbed that and stored it yourself from site #1, the cookie name would not match site #2.
Additionally, site #2 may not be easy to authenticate against and this is usually a security concern that developers are aware of. This can be considered an attempt of XSS as well.
In case you're simply doing this for yourself, I'd recommend LastPass and save most of your info in it.
Please reconsider your goals and how to achieve them, this is not the way.
Edit: Link text.
This could work, depending on the security measures in place on website #2. For a secure website, this would fail.
I would recommend against this purely on the basis of good security and good coding/design practices.
If you are unclear what security measures stop this, you should probably educate yourself so you can prevent the same issues on your own site. See http://www.owasp.org/index.php/Top_10_2007
Since both your sites are using FormsAuthentication you can easily configure both of them to share FormsAuthentication encryption schemes.
This will allow you to do Cross Application Authentication automatically :)

How to tell where the user is coming from?

Is there a reliable way to determine where a user is coming from in an ASP.NET application? We have a web application that is linked to from two different locations. The two links are on separate domains, and they need to dictate certain user permissions within this app. Here's what I have tried so far...
Using Request.UrlReferrer (which is the Referer HTTP header). This always returned an empty string. I believe this is because the hyperlinks use Javascript to launch a popup window. Based on my research, the user agent provides this HTTP header on standard hyperlinks. Javascript popups are a different story (evidently).
A simple query string to indicate the referrer. This is not really an option because we need something that is not so easy to bypass (more secure).
Any ideas? I understand that in the grand scheme of things, this could have a better overall design/structure. Please don't post an answer suggesting I re-design everything, because that is not an option.
There's no a reliable way to tell where an user is coming from and this is not only an ASP.NET limitation, but all web applications in general. The url referrer can be easily spoofed so it is not reliable. I think the best option could be some encrypted url parameter, or cookie if you prefer.
So both pages should agree on common private keys.
Page1 will use the key to encrypt its address and pass it to Page2
Page2 will check for the presence of this parameter and try to decrypt it with the same private key used to encrypt
If this succeeds it means that Page2 will be capable to determine who called it, if not, the data has been tampered
Without the browser passing a referrer or using the querystring like you describe, there is no way to know.
Another option is to have two different landing pages on the ASP.NET application. The landing pages can set the security options and then redirect to a common homepage. This is a little more secure than the querystring option.
Or, you could place a 1x1 pixel image on the referring sites that is pulled from your ASP.NET application site. The referrer should be passed to the script and you could then set a cookie on the users machine that you can then reference when they hit the app homepage.

User roles - why not store in session?

I'm porting an ASP.NET application to MVC and need to store two items relating to an authenitcated user: a list of roles and a list of visible item IDs, to determine what the user can or cannot see.
We've used WSE with a web service in the past and this made things unbelievably complex and impossible to debug properly. Now we're ditching the web service I was looking foward to drastically simplifying the solution simply to store these things in the session. A colleague suggested using the roles and membership providers but on looking into this I've found a number of problems:
a) It suffers from similar but different problems to WSE in that it has to be used in a very constrained way maing it tricky even to write tests;
b) The only caching option for the RolesProvider is based on cookies which we've rejected on security grounds;
c) It introduces no end of complications and extra unwanted baggage;
All we want to do, in a nutshell, is store two string variables in a user's session or something equivalent in a secure way and refer to them when we need to. What seems to be a ten minute job has so far taken several days of investigation and to compound the problem we have now discovered that session IDs can apparently be faked, see
http://blogs.sans.org/appsecstreetfighter/2009/06/14/session-attacks-and-aspnet-part-1/
I'm left thinking there is no easy way to do this very simple job, but I find that impossible to believe.
Could anyone:
a) provide simple information on how to make ASP.NET MVC sessions secure as I always believed they were?
b) suggest another simple way to store these two string variables for a logged in user's roles etc. without having to replace one complex nightmare with another as described above?
Thank you.
Storing the user's role information in a server-side session is safe providing a session cannot be hijacked. Restating this more broadly, it does not matter where user role info is stored if an authenticated session is hijacked.
I advise not putting too much faith in the article you linked to, but the 2002 vintage report linked to from your link is of interest. Here are my take-aways:
Don't accept session IDs embedded in URLs.
Focus your time on eliminating cross site scripting dangers i.e. scan all user supplied data and parse out executable java script.
Issue cookies for complete domains (e.g. myapp.mydomain.com)
Host your domain at a high class DNS operator e.g. one that only allows DNS changes from a preset remote IP address.
Don't issue persistent session cookies.
Reissue a session cookie if someone arrives at a login page with a sessionID already associated with an authenticated session.
Better still, always issue a new session cookie on successful authentication and abandon the prior session. (Can this be configured in IIS?)
The only way to make a secure cinnection is to use SSL. Anything less than that, and you simply have to make the evaluation when it's "safe enough".
A session variable works fine for storing a value, with the exception that the web server may be recycled now and then, which will cause the session to be lost. When that happens you would have to re-authenticate the user and set the session variable again.
The session variable itself is completely safe in the sense that it never leaves the server unless you specifically copy it to a response.
Have you considered setting up a custom Authorize tag in MVC. I gave an example of this in another question.
On initial authorization (sign-in screen or session start) you could seed a session value with the IP address also. Then in your custom authorization, you could also verify that IP's still match up as well. This will help make sure that someone isn't 'stealing' the person's session. Everytime you access your session data just make sure to pass the requester's IP and have some check on it.
Are you trying to control the access to functions at the client level? That is the only reason I would expose the roles and items to control client side functions.
Alternatively, you could create a function to obtain the items that the roles of the user are allowed to use, and then even if the function is called outside of the items given back to the web application, you can prevent the user from accessing them.
4Guys seems to show how to control functions with the roles.
The approach I have used in the past is to use symmetric encryption of a cookie alongside SSL. Encrypt the user information in the reponse and decrypt it in the request. I'm not claiming this is foolproof or 100% secure and I wouldn't want to do this on a banking application, but it is good enough for many purposes.
The main issue with session variables is that if you store them inProc rather than persisting them, then you need to apply 'sticky' sessions to your load balancing in a web farm environment. Guffa is correct that without this persistence session variables will occasionally be lost causing a poor user experience.
Sticky sessions can lead to uneven load balancing, perhaps reducing the value of being able to scale out.
If you are going to be be persisting the sessions so they can be accessed by all servers in your web farm, you may be better off using a Guid to identify the user, encrypting this in a cookie and retrieving the user record from your data store each time.
My obvious question is that why do you want to store a users role in session ?
Here is my answer to your query, how this helps. I have attached a small demo application for you to take a look at and understand my points. When you open this project in visual studio, click on the project tab on the top and select asp.net configuration. From the page that will show up you can do the user administration stuff.
You need to store the roles of a user in some secure manner ? The answer to this question is that there is no need for you to worry about storing the role for any user, when we have the asp.net membership, profiles and roles framework to help us out on this. All you need to do is create a role in the aspnet database and assign that role to the user.
Next you want to store two string in some secure manner. I suggest you user profile for storing user specific information. This way you have the information available to you where ever you want from the profilecommon class.
Also please see the attached demo application placed at the end of my blog http://blogs.bootcampedu.com/blog/post/Reply-to-httpstackoverflowcomquestions1672007user-roles-why-not-store-in-session.aspx
Just a suggestion, you might consider using this little library:
http://www.codeproject.com/KB/aspnet/Univar.aspx
It has a server side implementation of the cookie whereby all cookies can be stored on the server while asp.net authentification is used to identify the user. It supports encryption and is also very flexible making it very easy to switch from one storage type to another.

efficient ways to anonymous personalization using ASP.NET + Cookie

I am trying to achieve anonymous personalization in a ASP.net environment. I know that ASP.NET 2.0 provide Profile. However, I want to avoid traffic to the database as much as possible since the site I am working on is a relatively high traffic site.
The other obvious solution is cookie, but given the limitation of cookie, I was wondering if anyone have any efficient method to store information into cookie. Does anyone know how amazon or yahoo deals anon. personalization?
Ultimately, We are trying to serve up different dynamic content to our user base on a set of business rules outline in a pre-defined campaign. The reason is to measure conversion rate in our site. The same campaign can be use on all different pages of the site. The reason I need to set this to a cookie is that the user is able to see the same content served up previously if we want it to be. So this is what I have in cookie right now.
campaign code:page id:result display
And you can see that this will build up if there is a lot of campaign and each campaign is used on many pages.
Thanks in advance!
If database load is an issue, you can retrieve the personalization when the user starts his session on the website, and then store it on the session state. This way, only the first page load will make a call to the database.
You can store the user ID in the cookie.
Just remember to persist the session in the db when the user updates his preferences, and deleting old db records after a while might be a good idea too if that many anonymous users will visit your website.
If you want to persist the changes, such as each campaign view, there really isn't any way around accessing to write those changes. ASP.NET Membership is not bad on a high-volume site (>1 mil a day), when used correctly. For instance, you should be wrapping calls to the membership provider in a cached object, and refresh often (short expiration). Also, make sure to set the cacheRefreshInterval on the RoleProvider. This will force asp.net to cache the Roles in a cookie, to cut down on DB activity.
Another way to look at this is to take Ady's advice and to seperate the Membership into a separate DB. Yet again, another great feature of the ASP.NET Membership provider - you can set a different SQL connection string, and load it up on a different DB and/or server.
There are several other techniques around the membership provider that can really increase performance. Some quick google searches comes up a number of them.
I'd create a database record for the visitor and only store the ID in the cookie, this way you can look up all the personalised details from the database, and keep the cookie size to a minimum.
If database speed is an issue, perhaps use a differrent database and server to store the personalisations.
Alternativly you could store personal data in the file system, and load into the session when the visitor returns matching the cookie ID.
If identifying the user and cookie clearing is an issue, you cold use and ActiveX control, but this requires installation on the client computer, which people could object to.

Resources