static void

ASP Security

ASP.Net Security

  1. IIS authentication:
    • Anonymous access= IUSER_machinename (ie same as ASP).
    • Windows login- Basic (clear text), Digest (encrypted) and Windows (NTLM)
  2. IIS passes to ISAPI filter- eg aspnet_wp.exe (or w3wp.exe on WServer2003).
  3. If system.web/identity/@impersonate='false' (default)
    • No impersonation= run as ASPNET (or see machine.config's processModel)
    • Impersonation= run as IIS user (IUSER_machine or windows login) or system.web/identity/@userName
  4. Use system.web/authentication/@mode (None, Windows, Forms, Passport).
    • If using Windows, set system.web/identity/@impersonate="true" otherwise it won't work.
    • If using forms
      • set system.web/authorization/deny/@users="?" otherwise it won't work
      • system.web/authentication/forms/@loginUrl
      • @timeout- default is 30mins, but it refreshes halfway- so 16mins inactivity may kill it...
      • @protection="All" (encrypted + validated) - in webfarms, set machine.config machineKey/@validationKey + @decryptionKey
      • In code if (FormsAuthentication.Authenticate(user, pass)) FormsAuthentication.RedirectFromLoginPage(user, isPermaCookie);
        (replace first method with database authentication)
        (if loginpage== default.aspx then redirect may be to login page... try .GetRedirectUrl instead)
        (asp.net 2.0 has new Membership class)
  5. Page.User returns an IPrincipal, with IsInRole and Identity (which is an IIdentity, with AuthenticationType, Name- cast as WindowsIdentity for IsAnonymous etc).

Rights needed for ASPNET process (KB)

IIS web.config mode WindowsIdentity Page.User
Anon forms no impersonate=IUSR_MACHINE
impersonate= ASPNET
formId
Anon windows ""
Windows forms no impersonate=ASPNET
impersonate= domain/user
formId
Windows windows domain/user

NB: HttpContext.Current.User != WindowsIdentity.GetCurrent() (unless windows impersonating)
!= COM+ Security Role (ContextUtil.IsCallerInRole() is a different set of roles!

Forms Authentication

In web.config

<authentication mode="Forms">

    <forms loginUrl="Login.aspx"/>

</authentication>

<authorization>

    <deny users="?" />

</authorization>

In your login page :

protected void btnLogin_Click(object sender, EventArgs e)

{

    string userName = txtUserName.Text.Trim();

    string password = txtPassword.Text.Trim();

    //if (Membership.ValidateUser(userName, password)) //membership provider

    if (ValidateUser(userName, password)) //local validation

    {

        //if using redirection

        FormsAuthentication.RedirectFromLoginPage(userName, false);

        //otherwise just set cookie

        //FormsAuthentication.SetAuthCookie(userName, false);

    }

    else

    {

        Page.Validators.Add(new BusinessValidationError("Invalid UserID and Password"));

    }

}

To implement a custom MembershipProvider see msdn sample (and here for web.config to set the membership defaultProvider)

To logout manually (you can also just use the asp:LoginStatus control):

FormsAuthentication.SignOut();

Response.Redirect(FormsAuthentication.GetLoginPage(null));

//if you did NOT specify forms/@cookieless=UseCookies (or are using cookieless) you are automatically redirected

Roles

To do role management (User.IsInRole(x), authorization/allow/@roles, sitemap roles) you have to manually create a FormsAuthenticationTicket and put it in a cookie (internally this is what FormsAuthentication.SetAuthCookie does). NB: you have about 1k of the 4k cookie size maximum for the role list- otherwise use Cache (you can't use Session, it isn't available early enough).

string userRoles = "Admin, PowerUser"; //from database?

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(

        1,                          // version

        userName,                   // user name

        DateTime.Now,               // issue time

        DateTime.Now.AddMinutes(30),// expires

        false,                      // persistent

        userRoles                   // user data

        );

 

HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));

cookie.Secure = FormsAuthentication.RequireSSL;

cookie.Domain = FormsAuthentication.CookieDomain;

cookie.HttpOnly = true; //a little extra security

Response.Cookies.Add(cookie);

Response.Redirect("Secure.aspx");

Now wire this in the global.asax (or use an HttpModule)

void Application_OnAuthenticateRequest(object sender, EventArgs e)

{

    HttpContext c = HttpContext.Current;

    if (c.Request.IsAuthenticated)

    {

        FormsIdentity id = (FormsIdentity)c.User.Identity;

        string[] roles = id.Ticket.UserData.Split(',');

        System.Security.Principal.GenericPrincipal p =

            new System.Security.Principal.GenericPrincipal(c.User.Identity, roles);

        Context.User = System.Threading.Thread.CurrentPrincipal = p;

    }

}

Simple Authentication

For quick and simple/dirty security, you can put users directly into the web.config.

Nested web.config: You must only set <authentication> on the top level. You can't set it on subfolder web.config or in <location>. You should instead use different <authorization> sections.

<authentication mode="Forms">

    <forms loginUrl="~/Admin/Login.aspx">

        <credentials passwordFormat="Clear">

            <user name="Martin" password="secret"/>

        </credentials>

    </forms>

</authentication>

Then just use the login control.

<asp:Login ID="Login1" runat="server" DisplayRememberMe="False" VisibleWhenLoggedIn="False"
    OnAuthenticate="Login1_Authenticate" />

<script runat="server">

    protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)

    {

        e.Authenticated = FormsAuthentication.Authenticate(Login1.UserName, Login1.Password);

    }

</script>

Saving new users into web.config. If you're doing this, you really should be using a database, but hey ho. Also you really should use SHA1 format.

if (!Page.IsValid) return;

string userName = Server.HtmlEncode(txtName.Text);

string pw = Server.HtmlEncode(txtPassword.Text);

Configuration config = WebConfigurationManager.OpenWebConfiguration("~/");

//also (AuthenticationSection)WebConfigurationManager.GetWebApplicationSection("system.web/authentication") but users is readonly;

AuthenticationSection auth = (AuthenticationSection)config.SectionGroups["system.web"].Sections["authentication"];

string passwordFormat = auth.Forms.Credentials.PasswordFormat.ToString();

if (passwordFormat != "Clear")

    pw = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, passwordFormat);

auth.Forms.Credentials.Users.Add(new FormsAuthenticationUser(userName, pw));

try

{

    config.Save();

    Response.Redirect(Request.CurrentExecutionFilePath);// Redirect to self.

}

catch (ConfigurationErrorsException ex)

{

    Label1.Text = "ASP.NET process account (ASPNET or Network Service) must have write permission granted for the Web.config file<br/>";

    Label1.Text += "Manually copy this xml into your web.config forms/credentials section:<br/>";

    Label1.Text += string.Format("&lt;user name=\"{0}\" password=\"{1}\" /&gt;", userName, pw);

}