views:

558

answers:

8

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.

A: 

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.

Guffa
I should have said, we do use SSL so no problems there. Also we've never had an issue with recylcing of sessions so I'm not worried about that.
Phil
As for session variables being completely safe: that's what I thought but the article I've linked to suggests that one can trick a user into joining an existing session, in various ways, and thus share it with the authenticated user who subsequently logs in and thus stores all their own roles in there to be used by the other person. The obvious solution to that was to store the IP address in the session and check it each time but apparently it's easy to fake that in the request as well. Whilst I have been unable to make any of the suggested ways of
Phil
joining an existing session work I'd prefer to know why they don't than just to rely on my obviously lacking skills as a hacker. If I was confident on that then I think we've solved the problem but so far I am not.
Phil
I should add that I can obvioulsy fix a session cookie manually but that relies on knowing the session ID to set and since we use SSL I don't think that's a problem. The hacking would rely on sending a link to a user which got them, not the hacker, to join an existing session (instantiated by the hacker) and then to login to it.
Phil
The SSL connection has it's own session id that is not stored in a cookie, so the article that is about spoofing the session id cookie does not apply. The SSL session id is not exposed, and even if you manage to get hold of it you can't reuse it in another SSL connection.
Guffa
A: 

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.

Kelsey
A: 

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.

CrazyEnigma
A: 

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.

Mike
A: 

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

Bootcamp
+1  A: 

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:

1 - Don't accept sessionIDs embedded in URLs.

2 - Focus your time on eliminating cross site scripting dangers i.e. scan all user supplied data and parse out executable java script.

3a - Issue cookies for complete domains e.g. myapp.mydomain.com

3b - Host your domain at a high class DNS operator e.g. one that only allows DNS changes from a preset remote IP address.

4 - Don't issue persistent session cookies.

5 - Reissue a session cookie if someone arrives at a login page with a sessionID already associated with an authenticated session.

6 - Better still, always issue a new session cookie on successful authentication and abandon the prior session. (Can this be configured in IIS?)

camelCase
A: 

I like Kelsey's idea of checking the IP, I even tried it, but then somebody pointed out that an IP address can be faked in a request. I've modified the idea to use a randomly generated string instead, since unlike the correct IP to fake, this could not be worked out by the hacker, and would be issued only once in the response to the request containing the valid password and then checked with every subsequent request once it was in the session. I believe that nails the issue of session security for good.

Whilst this seems now to be on a level with the caching option of the RolesProvider in terms of security, I feel that the approach of storing the roles in the session, now that it is secured, is much simpler than the one using the Membership and Roles Providers. Also there is only one thing to store and check for security (the random string) and thus unlike the RolesProvider caching, we are unlikely to overshoot the cookie data limit and silently stop working, and instead of all the intricacies of the Roles and Membership framework, we're back to one, or in our case two, string variables - nice and simple.

I've been over-ruled by my colleage, who also happens to be my boss! We're using the Roles and Membership providers and I've absolved myself of responsibility for this decision because even if it is as secure as my preferred option, in my opinion it is at the very least far more complicated and produces a lot of extra code to write, learn, maintain and test. That's life!

Thanks to Guffa and Mike for pointing out the session recycling. I've now checked and believe the reason we have not yet seen this is due to low usage. However, it seems to apply only to InProc sessions and there are thus ways to avoid it.

Kelsey - we are indeed using the authorise attributes in conjunction with whichever way this was going to go, it is they which will call into it. Using such attributes is nice and simple and separates the majority of concerns very well in that the code inside any method does not have to check for permissions unless it wants to decide whether or not to show a certain button or whatever.

CrazyEnigma - I totally understand why you thought I was trying to control access to things on the client - that's the bafffled response I'd have had myself and would expect from anyone who sees the frankly ludicrous way MS implement roles caching!

Thanks to camelCase - yes we already implement the majority of those measures and although I'm no security expert I personally believe that with the addition of the random number check we'd have been totally secure.

Bootcamp - at the end of the day it is your answer that my boss has accepted so this deserves pointing out - thank you.

Thanks to you all for your helpful replies.

Phil
A: 

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.

Ziad