Problem with Sessions in ASP .NET - asp.net

I have a weird issue with session variables. I'm storing some credentials in sessions variables like this:
Session["login"] = "foo";
Session["password"] = "oof";
The page is deployed on a certain server. After I logged in on the page, I noticed that other users (who are in the same network area) calling the page were logged in as well! I thought those data would be stored only for me (I suppose the server sends me back some cookies to ensure that) but that's not the case?
I certainly have a lack of knowledge somewhere. What's going on?
Thanks

I wouldn't recommend storing a password in a session variable for security purposes. If you must use a session variable, do not store the password in clear text. Use some encryption method instead.

Check your web.config
http://msdn.microsoft.com/en-us/library/h6bb9cz9.aspx

Related

ASP.NET MVC4 Session state store username

I have created my first uber small webapp with MVC4. So far I used the layout stuff to layout the webapp and added some views controllers and a model to register and allow users to log in.
Once a user logged in / registered, I store its username in the session. I read this property from the session to determine if a user has been logged in or not.
Is that a bad practice? I read a lot about RESTful and stateless webapps. I kinda get the feeling that I should not save anything in my session.
e.g.
#if (string.IsNullOrEmpty(Session["User"] as string))
{
<dl>
<dt>Register</dt>
<dt>Login</dt>
</dl>
}
else
{
<dl>
<dt>#Session["User"]</dt>
<dt>Log out</dt>
</dl>
}
Q1: is this a bad practice?
Q2: is this "hack safe"? As is, is it easy to hack the current session and store a value in Session["User"] to bypass logging in?
To answer your questions:
1) In general, using session state is not bad practice, as long as you need it for your applications and you understand its implications on performance and scalability. However, in your case, if all you need to store is the user's name, then you really don't need it, if your application is using an ASP.Net membership provider, then this information is available in the User property in the MVCController base class:
var username = User.Identity.Name
There are three ways that session data can be stored: "InProc", where it is stored in the app process, "StateServer", where it is stored output process on a separate server, and "SQLServer", where it is stored in a SQL Server DB. Which one you should use depends upon if you are using a server farm, if your session needs to be durable (i.e. survive a machine reboot), and what the performance requirements are for your app (StateServer and SQLServer are less performant that InProc). More information can be found here
2) You should use SSL to protect your session data. The data sent over SSL (HTTPS) is fully encrypted, headers included (hence cookies). A good discussion on how to prevent session hijacking attacks is found here.

ASP.NET Session Management With Variables

Ran into a stupid problem...
So right now I implement Application_Start to load up the hash tables, which works fine. Next in Session_Start I parse a user's cookie to retrieve his name, which, again, works fine. The problem happens when I store his username in a variable in Global.asax.cs. I didn't really realize that this is a variable shared among all processes/threads. So I guess my question is how do you parse a user's cookie one time and then save the data for sure elsewhere in the process/thread.
You can store cookies in session and use it later. You can store any object in session collection and retrieve it later before it expires. You can read more over here
Assigning to session
Session["anyName"] = "value";
Retrieving from session object
string str = Session["anyName"].ToString();
That's exactly what the ASP.NET session is meant for. Store this information there. It will be only specific to the current user and not shared among all users.
By the way you might also want to checkout Forms Authentication in ASP.NET, just to make sure that you don't reinvent some wheels.
Can't you just use Session?
Session["username"] = username;
var username = Session["username"];
Session is definitely the way I would go. Having HUGE amounts of data in Session could potentially lead to performance problems, but only storing small strings for each user shouldn't matter at all.

Do session variables work differently during development?

I'm building a website with ASP.NET MVC3. When a user signs in, I pull their display name from the database and store it to a session variable:
Session["DisplayName"] = user.Display;
Then in _Layout.cshtml I use it to display at the top of each page:
<span class="user">#(Session["DisplayName"] as string)</span>
This works fine when I start debugging the website then log in, but if I then rebuild my server and begin debugging again, my browser remains logged in but the Session variables are cleared. This leads to a bunch of empty spaces where my display name should be.
Is this a side-effect of rebuilding the server, and not something I need to worry about in deployment? Is there a way to invalidate logins every time I rebuild, so that I avoid this issue? Or is there a better way to store this user data, other than a Session variable?
Is this a side-effect of rebuilding the server, and not something I
need to worry about in deployment?
Oh no, that's something that you absolutely should worry about. As you know ASP.NET session is by default stored in server memory. And when the AppDomain is recycled (which could happen at absolutely any time) by IIS all your session is gone. For example IIS could bring down the AppDomain after a certain inactivity on the application. Or after certain CPU or memory usage thresholds are reached. If you want to be able to reliable store something in the ASP.NET session you could offload the storage off-proc and store this session either in a dedicated session server or SQL. But honestly, I have seen many people moving ASP.NET Session to SQL Server and regretting it. What's the point? You already have this information in SQL Server :-) I once used this and regretted it so much.
Personally I never use ASP.NET Session in my applications. If you need to persist such information as the display name and avoid hitting the database at each request you could store it in the User Data section of the Forms Authentication cookie. So here's the idea: when the user successfully inputs correct credentials, you manually create a FormsAuthenticationTicket and populate its UserData property with whatever information you want to be available about this use on each request and then emit the authentication cookie. Then you write a custom Authorize attribute in which you decrypt the cookie, fetch the User Data and store it as a custom IIdentity making it available on each request.
Store usernames in cache (Cache[string.Format("DisplayName_{0}", User.Id)] = User.Username), cookies or move session to SQL Server instead of InProc
I would create a static helper method that gets username by user id. If it finds cached value, it will use that, if not, get value from db, store it in cache and return.
public static string GetUsername(int UserID)
{
string cacheKey=string.Format("DisplayName_{0}", UserID);
if (HttpContext.Current.Cache[cacheKey]==null)
{
// Retrieve user name from DB
string Username=Repository.GetUserName(UserID);
HttpContext.Current.Cache[cacheKey]=Username;
}
return HttpContext.Current.Cache[cacheKey].ToString();
}
There are better ways, but to address your specific issue your auth timeout and session timeout are not the same, you need to handle the case specifically when one will timeout before the other. See my post here:
How can I handle forms authentication timeout exceptions in ASP.NET?

How do I send a user ID between different application in ASP.Net?

I have two web applications and both are developed in ASP.NET. Now I want to provide a feature which enables the user to click from one URL in application site (one virtual directory of IIS) A to the other URL in application site B (another virtual directory of IIS).
I have two ideas to implement them, but both of them have issues. I want to know what solution should be optimum solution?
Solution 1: using cookie, so from both application sites, we could retrieve user ID information from reading cookie, but I am afraid if cookie is disabled in browser, this "jump" feature never works.
Solution 2: When the user redirects to an URL in another site, I could append user ID after the URL, I could redirect to this URL in another site http://www.anotherapplicationsite.com/somesuburl?userID=foo, but I am afraird that in this way userID will be exposed easily which raise security issues.
I work with this sort of thing a lot. What you're looking for sounds like a candidate Single Sign-on solution or Federated Security.
You might try doing something similar to the following:
Create a simple db or other sort of table storage with two columns "nonce" and "username"
When you build the link to the other site create a GUID or other unique identifier to use as a one-time nonce, passing it as a querystring ?id=. Insert an entry into the table with the current authenticated username and the unique identifier you created.
When you reach the destination of your link, pass the unique identifier to call a webservice that will will match up the identifier with the username in the database you inserted before jumping to the second site (secure this with ssl).
If the nonce checks out with a valid username, you're all set. The webservice should remove the used entry and the table should stay more or less empty any time you are not in the middle of a transaction.
It is also good to include a datetime in your nonce/username table and expire it in 60 seconds or less to minimize the risk of replay attacks. We also require client certificates for external applications to call the webservice in order to verify the identity of the caller. Internal applications don't really necessitate using client certificates.
A nice thing about this is that it scales fairly well to as many sites as you would like to use
Not perfect security, but we've never had a significant compromise with a such as system.
As long as you have a good authentication system in place on the second website I think solution 2 is the one for you, taking into account the remark Andrew made about the sensitive ID's of course.
For more information on encryption: check the documentation of the FormsAuthentication.Encrypt Method . I think they even do something with writing a value in a cookie in that example.
If you put the userid in a query string and that's all the 2nd app uses to allow login, what's to keep me from manually typing in other users id's? You'd still have to prompt for password on the new site.
I'd use a database to hold login information, and have both sites reference that same db. Use it like you'd use a session.
D
I don't think 1) will work due to browser security (cookies from one domain cannot be read by another domain). I would go with 2), except I would encrypt the querystring value.
EDIT: For more info on cookie privacy/security issues, check out the "Privacy and third-party cookies" section here.
What are you using as the user's id? If you are using their social security number or email (something sensitive) then you are going to want to encrypt the value before you put it on the query string. Otherwise (if the user's id is something ambiguous like an integer or a GUID) it should be fine to put the id on the query string.
using cross domain, you can not SHARE the session, so I was thinking about POST
idea 1
if afraid of "showing" the username in the address, why not sending a POST?
<form name="myForm" action="http://www.mydomain.com/myLandingPage.aspx">
<input type="hidden" id="userid" value="myUsername" />
click here
</form>
but then... off course, "View Source Code" will show it
idea 2
then.. I remembered that I do the same, but sending a Encrypted string like:
http://www.anotherapplicationsite.com/somesuburl?userID=HhN01vcEEtMmwdNFliM8QYg+Y89xzBOJJG+BH/ARC7g=
you can use Rijndael algorithm to perform this, link below has VB and C# code:
http://www.obviex.com/samples/EncryptionWithSalt.aspx
then in site 2, just Decrypt and check if the user exists... if it does, continue, if not saying that the user tried to temper the query string :)

How do I prevent replay attacks?

This is related to another question I asked. In summary, I have a special case of a URL where, when a form is POSTed to it, I can't rely on cookies for authentication or to maintain the user's session, but I somehow need to know who they are, and I need to know they're logged in!
I think I came up with a solution to my problem, but it needs fleshing out. Here's what I'm thinking. I create a hidden form field called "username", and place within it the user's username, encrypted. Then, when the form POSTs, even though I don't receive any cookies from the browser, I know they're logged in because I can decrypt the hidden form field and get the username.
The major security flaw I can see is replay attacks. How do I prevent someone from getting ahold of that encrypted string, and POSTing as that user? I know I can use SSL to make it harder to steal that string, and maybe I can rotate the encryption key on a regular basis to limit the amount of time that the string is good for, but I'd really like to find a bulletproof solution. Anybody have any ideas? Does the ASP.Net ViewState prevent replay? If so, how do they do it?
Edit: I'm hoping for a solution that doesn't require anything stored in a database. Application state would be okay, except that it won't survive an IIS restart or work at all in a web farm or garden scenario. I'm accepting Chris's answer, for now, because I'm not convinced it's even possible to secure this without a database. But if someone comes up with an answer that does not involve the database, I'll accept it!
If you hash in a time-stamp along with the user name and password, you can close the window for replay attacks to within a couple of seconds. I don't know if this meets your needs, but it is at least a partial solution.
There are several good answers here and putting them all together is where the answer ultimately lies:
Block-cipher encrypt (with AES-256+) and hash (with SHA-2+) all state/nonce related information that is sent to a client. Hackers with otherwise just manipulate the data, view it to learn the patterns and circumvent everything else. Remember ... it only takes one open window.
Generate a one-time random and unique nonce per request that is sent back with the POST request. This does two things: It ensures that the POST response goes with THAT request. It also allows tracking of one-time use of a given set of get/POST pairs (preventing replay).
Use timestamps to make the nonce pool manageable. Store the time-stamp in an encrypted cookie per #1 above. Throw out any requests older than the maximum response time or session for the application (e.g., an hour).
Store a "reasonably unique" digital fingerprint of the machine making the request with the encrypted time-stamp data. This will prevent another trick wherein the attacker steals the clients cookies to perform session-hijacking. This will ensure that the request is coming back not only once but from the machine (or close enough proximity to make it virtually impossible for the attacker to copy) the form was sent to.
There are ASPNET and Java/J2EE security filter based applications that do all of the above with zero coding. Managing the nonce pool for large systems (like a stock trading company, bank or high volume secure site) is not a trivial undertaking if performance is critical. Would recommend looking at those products versus trying to program this for each web-application.
If you really don't want to store any state, I think the best you can do is limit replay attacks by using timestamps and a short expiration time. For example, server sends:
{Ts, U, HMAC({Ts, U}, Ks)}
Where Ts is the timestamp, U is the username, and Ks is the server's secret key. The user sends this back to the server, and the server validates it by recomputing the HMAC on the supplied values. If it's valid, you know when it was issued, and can choose to ignore it if it's older than, say, 5 minutes.
A good resource for this type of development is The Do's and Don'ts of Client Authentication on the Web
You could use some kind of random challenge string that's used along with the username to create the hash. If you store the challenge string on the server in a database you can then ensure that it's only used once, and only for one particular user.
In one of my apps to stop 'replay' attacks I have inserted IP information into my session object. Everytime I access the session object in code I make sure to pass the Request.UserHostAddress with it and then I compare to make sure the IPs match up. If they don't, then obviously someone other than the person made this request, so I return null. It's not the best solution but it is at least one more barrier to stop replay attacks.
Can you use memory or a database to maintain any information about the user or request at all?
If so, then on request for the form, I would include a hidden form field whose contents are a randomly generated number. Save this token to in application context or some sort of store (a database, flat file, etc.) when the request is rendered. When the form is submitted, check the application context or database to see if that randomly generated number is still valid (however you define valid - maybe it can expire after X minutes). If so, remove this token from the list of "allowed tokens".
Thus any replayed requests would include this same token which is no longer considered valid on the server.
I am new to some aspects of web programming but I was reading up on this the other day. I believe you need to use a Nonce.
(Replay attacks can easily be all about an IP/MAC spoofing, plus you're challenged on dynamic IPs )
It is not just replay you are after here, in isolation it is meaningless. Just use SSL and avoid handcrafting anything..
ASP.Net ViewState is a mess, avoid it. While PKI is heavyweight and bloated, at least it works without inventing your own security 'schemes'. So if I could, I'd use it and always go for mutual authent. Server-only authentification is quite useless.
The ViewState includes security functionality. See this article about some of the build-in security features in ASP.NET . It does validation against the server machineKey in the machine.config on the server, which ensures that each postback is valid.
Further down in the article, you also see that if you want to store values in your own hidden fields, you can use the LosFormatter class to encode the value in the same way that the ViewState uses for encryption.
private string EncodeText(string text) {
StringWriter writer = new StringWriter();
LosFormatter formatter = new LosFormatter();
formatter.Serialize(writer, text);
return writer.ToString();
}
Use https... it has replay protection built in.
If you only accept each key once (say, make the key a GUID, and then check when it comes back), that would prevent replays. Of course, if the attacker responds first, then you have a new problem...
Is this WebForms or MVC? If it's MVC you could utilize the AntiForgery token. This seems like it's similar to the approach you mention except it uses basically a GUID and sets a cookie with the guid value for that post. For more on that see Steve Sanderson's blog: http://blog.codeville.net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/
Another thing, have you considered checking the referrer on the postback? This is not bulletproof but it may help.

Resources