Saturday, July 21, 2007

Using Dynamic Impersonation Safely

Impersonation refers to the capability of code to run with the identity of a specific user. Typically, this is the logged on user, but it can also be a designated user (see the userName and password attributes of the identity element in web.config). You would use impersonation so that a user can access a Windows operating system resource with specific permissions. This could be a file on the file system. This is one way to access that resource that would be impossible to access otherwise. Alternatively, you could expand the permissions on the resource, but that may not be good for security.
The identity element in web.config enables you to perform impersonation. When it is turned on, the application runs with the credentials of the currently logged on user. This setting applies to all files in the same directory as the web.config file. Because you don't want every logged on user to have access to protected resources, it is common to put the page that accesses the resource in a separate directory and add a web.config to that directory with impersonation turned on. Then configure security so only a certain user or role can access anything in that directory. After accessing a page in the subdirectory where impersonation is enabled, the user will run with impersonation and be able to access the resource.
When setting the identity element in web.config, a security hazard could exist whereby we can turn on impersonation for all files within the scope of that web.config file. This is convenient, as are many other things in ASP.NET. However, if you are following the security principle of least privilege, it may not be the most secure solution. In fact, it may open a security hole either now or in the future when more pages are added or when maintaining the site. Because the logged on user is impersonating during the entire time they have access to any pages in the same directory, they also have access to everything else to which the impersonated user has access. The most secure solution is to allow access to a resource for only the briefest amount of time possible and only when necessary.
I'm not advocating that you not use impersonation through web.config because if you need it you should use it. Conversely, if you want to restrict access to resources to only those who need it and only when they need it, then dynamic impersonation could be a good choice for you. Listing 14-8 shows how to do this.
Listing 14-8: Dynamic impersonation in code
protected void btnViewGrades_Click(object sender, EventArgs e)
{
Response.Write(WindowsIdentity.GetCurrent().Name + "
");
// impersonate current user
WindowsImpersonationContext ctx =
((WindowsIdentity)User.Identity).Impersonate();
Response.Write(WindowsIdentity.GetCurrent().Name + "
");
try
{
DataSet ds = new DataSet();
// throws exception when user doesn't
ds.ReadXml(Server.MapPath("Grades.xml"));
GridView1.DataSource = ds.Tables[0];
GridView1.DataBind();
}
catch (UnauthorizedAccessException)
{
lblResult.Text = "Not Authorized!";
}
// turn impersonation off
ctx.Undo();
Response.Write(WindowsIdentity.GetCurrent().Name + "
");
}
Calling the Impersonate method of the current user's WindowsIdentity makes the program run with the permissions of the current user. The impersonation context is closed when calling Undo on the WindowsImpersonationContext object that was returned by the call to Impersonate. Therefore, all code between the call to Impersonate and the call to Undo in Listing 14-8 runs with the permissions of the caller. All code outside these bounds runs as the NETWORK SERVICE account (on Windows Server 2003) or the ASPNET account (all other OSs).
Listing 14-8 puts access to a file named Grades.xml within the block of code where we are impersonating. To demonstrate how this works, set ACLs to deny access to this file to everyone but a single person. Then log on with an account that doesn't have access to demonstrate that an UnauthorizedAccess Exception will be raised when you run the program. You can also prove that it works by logging on as the person who does have access and then running the program. Dynamic impersonation allows you to follow the principle of least privilege by limiting impersonation to a single block of code, only when necessary

No comments: