Professional ASP.NET 2.0 Security, Membership, and Role Management

Stefan Schackow

Mentioned 5

Experienced developers who are looking to create reliably secure sites with ASP.NET 2.0 will find that Professional ASP.NET 2.0 Security, Membership, and Role Management covers a broad range of security features including developing in partial trust, forms authentication, and securing configuration. The book offers detailed information on every major area of ASP.NET security you ll encounter when developing Web applications. You ll see how ASP.NET 2.0 version contains many new built–in security functions compared to ASP.NET 1.x such as Membership and Role Manager, and you ll learn how you can extend or modify various features. The book begins with two chapters that walk you through the processing ASP.NET 2.0 performs during a web request and the security processing for each request, followed by a detailed explanation of ASP.NET Trust Levels. With this understanding of security in place, you can then begin working through the following chapters on configuring system security, forms authentication, and integrating ASP.NET security with classic ASP including integrating Membership and Role Manager with classic ASP. The chapter on session state looks at the limitations of cookieless session identifiers, methods for heading off session denial of service attacks, and how session state is affected by trust level. After the chapter explaining the provider model architecture in ASP.NET 2.0 and how it is useful for writing custom security providers you go to the MembershipProvider class and configuring the two default providers in the Membership feature, SqlMembershipProvider and ActiveDirectoryMembershipProvider. You′ll see how to use RoleManager to make it easy to associate users with roles and perform checks declaratively and in code and wrap up working with three providers for RoleProvider WindowsTokenRoleProvider, SqlRoleProvider, and AuthorizationStoreRoleProvider (to work with Authorization Manager or AzMan). This book is also available as part of the 5–book ASP.NET 2.0 Wrox Box (ISBN: 0–470–11757–5). This 5–book set includes: Professional ASP.NET 2.0 Special Edition (ISBN: 0–470–04178–1) ASP.NET 2.0 Website Programming: Problem – Design – Solution (ISBN: 0764584642 ) Professional ASP.NET 2.0 Security, Membership, and Role Management (ISBN: 0764596985) Professional ASP.NET 2.0 Server Control and Component Development (ISBN: 0471793507) ASP.NET 2.0 MVP Hacks and Tips (ISBN: 0764597663) CD–ROM with more than 1000 pages of bonus chapters from 15 other .NET 2.0 and SQL Server(TM) 2005 Wrox books DVD with 180–day trial version of Microsoft(r) Visual Studio(r) 2005 Professional Edition

More on Amazon.com

Mentioned in questions and answers.

I'm currently developing a MVC3 web application that needs to require extranet users to log in and be authenticated using Forms Authentication. Intranet users should be logged in automatically using Windows authentication.
I've found this article, http://aspalliance.com/553_Mixed_Mode_Authentication.all but it's dated Nov 2004 and like to find something written more recently than 7 years ago.

My plan is to have two applications in IIS, with virtual directories pointing at the same physical directory, but one will allow Anonymous Access and the other will not.

When a user is authenticated on the Windows/Intranet side of things, I hope to simply simulate the user logging in via forms authentication. Are there any pitfalls to this approach? Any better ideas?

EDIT: 7/22/2011

I'm using IIS7 which won't allow me to do many of the things suggested in the older articles. Due to authentication being integrated a bit tighter between IIS7 and the ASP.NET web sites, certain things aren't allowed. For example, I can't set Windows Auth on a single file while the rest of the application is using Forms Auth.

Wondering if the best approach here wouldn't be to have two applications where the first application uses windows authentication and consist solely of a hook to the PostAuthenticate event in the HTTP pipeline. If the user is authenticated, you give them a forms ticket and redirect to the target app, App2, which uses forms authentication. You have to be careful that the cookies are not path specific and also that the two apps reside on the same server (or that the encryption keys are synchronized in web.config). If the user is not authenticated, you simply redirect them without a an auth ticket and they login when the arrive at App2.

App1: www.myUrl.com\MyApp

This is the "public" url for the app and detects network users by hooking into the PostAuthenticate event (see Professional ASP.NET 2.0 Security, Membership, and Role Management):

//Hook PostAuthenticateRequest inside of global.asax
void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    IPrincipal p = HttpContext.Current.User;

    if (p.Identity.IsAuthenticated)
    {
      // to do: give them a non-path specific ticket and redirect to App2
    }
}

App2: www.myUrl.com\MyApp2

This is the actual application. When network users arrive from App1, they'll already have a forms ticket. When non-network users arrive, they'll be redirected to login.aspx.

Notes: One downside of this would be if network users bookmark App2. I'm not quite sure how I would get around this. If they have a non-expiring cookie, it wouldn't matter too much. One option would be to put a link on the login page that says something like "I'm already a network user - log me in automatically", which would link back to App1, where they would get logged in?

I have some code to assist with issuing a forms ticket. I'll update the answer as I have time.

Note that you're going to have to do some fancy role-management footwork in App2 to handle the disparate role providers. That Amazon reference above is old, but I find myself constantly referencing it when I run into these kinds of custom Authentication and Authorization problems.

I've seen multiple articles like this one that explain how to detect that a user's session has timed out. And for clarity's sake, these articles are referring to the timeout value defined by this web.config line:

<sessionState mode="InProc" cookieless="UseDeviceProfile" timeout="120" />

Not to get into that method too much, but this involves checking that Session.IsNewSession is true and that a session cookie already exists. But I haven't seen any articles on how to detect authentication timeout -- the one defined by this web.config line:

<authentication mode="Forms">
    <forms loginUrl="~/Home/Customer" timeout="60" name=".ASPXAUTH" requireSSL="false" slidingExpiration="true" defaultUrl="~/Home/Index" cookieless="UseDeviceProfile" enableCrossAppRedirects="false"/>
</authentication>

Multiple articles online, including this SO post, have said that your Session timeout value should generally be double your Authentication timeout value. So right now, as above, my Session is 120 and my Authentication is 60. This means that I'll never get in a situation where the Session has timed out, but the user is still Authenticated; if the user ever times out, it will be due to Authentication, not Session.

So, like everyone else, I'm interested in how to report to the user that their session has timed out (but really it'll be due to the Authentication timeout). Does anyone know of a way to accomplish this, or any resources online that can point me to a solution?

I would leverage the http pipeline early in the request and send an apporpriate response.
My source for answering such questions is:

Professional ASP.NET 2.0 Security, Membership, and Role Management

An HTTP module might do the trick:

Web.config:

<configuration>
  <system.web>
    <httpModules>
      <add name="MyAuthModule" type="MyAssembly.Security.MyAuthModule, MyAssembly"/>

...

The Actual HTTP Module:

/// <summary>
/// A module for detecting invalid authentication 
/// </summary>
/// <remarks>See "How To Implement IPrincipal" in MSDN</remarks>
public class MyAuthModule : IHttpModule
{
    #region IHttpModule Members
    void IHttpModule.Dispose() { }
    void IHttpModule.Init(HttpApplication context)
    {
        context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
    }
    #endregion


    /// <summary>
    /// Inspect the auth request...
    /// </summary>
    /// <remarks>See "How To Implement IPrincipal" in MSDN</remarks>
    private void context_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpApplication a = (HttpApplication)sender;
        HttpContext context = a.Context;

        // Extract the forms authentication cookie
        string cookieName = FormsAuthentication.FormsCookieName;
        HttpCookie authCookie = context.Request.Cookies[cookieName];

        if (authCookie != null)
        {
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            // check if previously authenticated session is now dead
            if (authTicket != null && authTicket.expired)
            {
               // send them a Response indicating that they've expired.
            }
        }
    }
}

Good luck!

I have two separate apps (one is classic asp, the other is asp.net) which, from the point of view of the user, should appear seamlessly as one "application". As others have pointed out, the two apps can't share session information, so I am planning to use windows authentication along these lines:-

In the ASP world:

Request.ServerVariables("AUTH_USER")

and in ASP.Net (.Net 2.0):

System.Threading.Thread.CurrentPrincipal.Identity.Name

which is called from my business logic layer (i.e.

HttpContext.Current.User.Identity.Name

is not available to me).

Is this considered good practice or is there a better way? What do I need to consider when setting up IIS?

I had to do this a couple of years ago and I remembered Scott Guthrie had a good post that got me started.

http://weblogs.asp.net/scottgu/archive/2007/03/04/tip-trick-integrating-asp-net-security-with-classic-asp-and-non-asp-net-urls.aspx

We ended up buying the book he talks about too. It's a good read.

I've created an web authentication app using c# & asp.net and want to bounce off how secure you think it is. All navigation is done by https.

User Registration

  1. User enters 3 datapoints (SSN,Lname and DOB). If that combination is found in our system, a session variable is set and navigates to next page.
  2. If session variable for #1 is set, proceed and ask for username, pwd, security q&A etc. Use Linq to save data and verify session variable before actual save event. PWD and security answer is hashed using salt and sha. (use validation controls and textbox limits to limit input)

Reset password

  1. Same as #1 in registration but includes username. If ok, set step 1 session variable.
  2. If step 1 session variable is set, ask security question up to 3x. Salt/hash and verify to database salt/hash. If match, set step 2 session variable.(use validation controls and textbox limits to limit input)
  3. Check for step 2 session variable. Ask for new pwd. Hash/salt and save using LINQ.

Login (use validation controls and textbox limits to limit input)

  1. Gather username and password. HASH/salt password that matches username and see if password matches hash. If okay, instatiate user objects and pass to default page.
  2. All pages inherit from masterpage. Masterpage has code to verify if user objects are set to a valid instance. If not valid user object, logoff is called which redirects to main login page.

Kind of wordy but wanted to be clear.

Am I missing anything here? I wanted to use MS's forms auth but decided to roll my own as I had some issues getting some of the custom stuff I wanted done using FBA. By using session variables as step completion markers, does that adequately prevent session stealing or bookmarking? Is there a better way to do this?

Thoughts please?

What aspect of either ASP.NET Forms Authentication or using the Membership Provider bits didn't fit with your needs? I've found both to be very flexible in many different scenarios?

Rolling your own is usually going to make life hard in the future, especially when you need to start making changes. Also your use of a master page to verify a users logon state etc might be fine for now, but when you require more master pages you then start needing to replicate the same blob of code in every masterpage and keep it all consistent. That can then become a maintenance nightmare somewhere down the road.

If you're not using the ready baked authentication tools in the framework you should be plumbing this kind of thing in somewhere else, such in an HttpModule.

I think you should revisit what you're doing. Take a look at implementing your own custom IIdentity objects if you need to hang user specific data/objects off of a user object. Then assign to a custom IPrincipal you can attach to Context.User in ASP.NET.

@asp316 and @Jack (comment) I would advise grabbing these two books:

Developing More-Secure Microsoft® ASP.NET 2.0 Applications by Dominick Baier

Professional ASP.NET 2.0 Security, Membership, and Role Management by Stefan Schackow

You'll be surprised how flexible the built in security infrastructure in .NET really is. There's a lot more to it than just adding a <authentication mode="Forms"> setting to your web.config and slapping a <asp:login runat="server"/> control on a page.

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?

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.