ne of the most important security principles for software development is least privilege.
Simply put, least privilege means that an application, process, or user should have the least access to resources required to accomplish a task and no more. By following this principle, even if your application is attacked or a user goes on the payroll of your nastiest competitor, you'll have limited the potential damage. Bottom line: implementing partial trust in ASP.NET is the single biggest thing you can do to make your applications secure.
ASP.NET has some powerful tools for implementing the principle of least privilege in your applications. But developers often do not use partial trust techniques, which never ceases to surprise me. Sure, the techniques require understanding security and how ASP.NET implements code access security, but isn't that pretty much a prerequisite these days for secure ASP.NET development? (The answer is Yes! in case you weren't sure.) Sure, partial trust techniques take a little more work, but by the end of this article you'll understand that it isn't all that much more work.
Even though the default trust level in ASP.NET is Full trust (an evil choice of Microsoft's in my opinion), you should never deploy a real, non-trivial application that way. But what are the other options? What do you have to give up to become more secure?
This article looks at how to create partially trusted web applications, but not by using any of the poorly fitting standard trust levels included with .NET out of the box. Instead I'll show you two easy techniques to make your ASP.NET applications substantially more secure. The first technique demonstrates how to create a custom trust level, tailored to the needs of a specific application to offer maximum protection. The second technique shows you how to segregate dangerous code—code that needs a higher privilege level to perform some specific action—into a protected sandbox. You'll commonly use a combination of these techniques for the highest level of security.
Along the way I'll explore permissions and how ASP.NET implements the Common Language Runtime's (CLR) code access security (CAS) to implement its trust levels. I assume that you know at least the basics of code access security and .NET permissions, as well as how to put together and run ASP.NET applications. You should also be familiar with how .NET configuration files work, understand the roles of machine.config and the machine-wide root web.config file, and application configuration files.
I'll begin with a short overview about partial trust, code access security, and why they are so critical to secure ASP.NET applications. Bear with me through this next section: I'll cover some important points for understanding partial trust, and then I'll dive deep into configurations and code.
Partial Trust and Code Access Security
I've spoken a lot at user groups and conferences about security in ASP.NET applications. Usually I'll ask whether anyone has ever developed a partial trust .NET application of any project type. No matter how packed the room, rarely more than two hands go up. And as often as not, at least one of those two had just played around with it rather than deployed a production application using partial trust. The other person had to do it because their hosting company only supports medium trust applications on shared servers. Good for the hosting companies!
In one way, this does not surprise me. Despite Microsoft's best efforts to make Windows more secure and provide developers with the tools they need to write secure apps, it is still just too damn hard. You can implement all the best practices you want, but all it takes is one junior developer downstairs (it's always the junior developers, eh?) to make one mistake to open a gaping vulnerability. But to be fair to the junior developers, in this age of "deploy it yesterday" mania, few developers have the luxury of building features that seem to have so nebulous a benefit as security. This is the reason why every week seems to bring news of another site hacked.
In another way, I'm shocked that only two people out of dozens or hundreds have experience with partial trust. Writing partial trust applications takes some knowledge, but not that much nor is it that hard to learn. Given the immense benefits that partial trust brings to web applications, developers really don't have an excuse for taking security shortcuts like Full trust. This nasty shortcut is fraught with peril and gaping vulnerabilities.
So what is the real difference between full and partial trust applications that make Full trust so terrifyingly horrible? In essence, when you use Full trust you tell the CLR to ignore code access security: "Don't check permissions, just run the code so that what the application can do is limited only by Windows security." This reduces any .NET application to the level of security supported by ActiveX/COM components—a very unsafe level indeed!
When you use partial trust, your application gets some subset of all of the available .NET and custom permissions, meaning that your application can't do anything and everything. It may not be able to run unmanaged code—such as COM components—or access the network, for example. It may not be able to open an Access database or write to anywhere on the local drive. It no longer has unfettered access to every resource on the local machine or network that Windows allows even to members of the Everyone Windows group.
It may sound undesirable to limit your application like this. But think of it in these terms: If an attacker gets control of your application—and they will, or at least try very hard—what will he or she be able to do? With Full trust, they'll be able to open any Access database, write to non-protected file locations, and do a lot of other nasty stuff. Are you so confident in your perimeter security that you know that no attacker will ever breach it, even with attacks that are unknown today? No? Then Full trust is probably a bad solution for you.
|Figure 1: The .NET Configuration Tool lets you define the security policy for the local machine and current user. It shows three of the four available policy levels.|
This makes partial trust a good thing—a desirable security state. But how does your application get specific permissions? I won't go into the details of how code access security works other than to make one observation about the four policy levels. Figure 1
shows the .NET Configuration Tool 2.0, displaying the three policy levels you can configure with this tool. The tool lets you configure the local machine's policy level by matching an assembly's evidence to one or usually more code groups. At the end of the process the assembly has a permission set assigned to it—the group of permissions it will run with.
Under the default policy installed with .NET, the three external policy levels—enterprise, machine, and user—are all a bit moot. Because you install an ASP.NET application on the local machine—it isn't being run remotely from another location on the network—it gets Full trust by default. This is part of the reason why by default, ASP.NET apps run with Full trust. (I'll get to the other part later in this article.)
Figure 1 does not display the fourth policy level (Application Domain policy level), which you cannot configure using the .NET Configuration Tool 2.0. The Application Domain policy level is often just called the "app domain" level. Because the permission set assigned to an assembly is essentially an intersection of the permissions from the four policy levels, the app domain permissions are the permissions assigned to the assembly. In other words, the app domain, through the ASP.NET trust level, controls a web application's permissions.
|Editor's Note: This article was first published in the January/February 2008 issue of CoDe Magazine, and is reprinted here by permission.|