Sponsored Links


Resources

.NET Research Library
Get .NET related white papers, case studies and webcasts

Sandboxing Components for ImpersonationSandboxing Components for ImpersonationSandboxing Components for Impersonation Discuss DiscussDiscuss Printer friendly Printer friendlyPrinter friendly
Sandboxing Components for Impersonation

December 22, 2004

Securing an ASP.NET application goes beyond implementing an authentication and authorization strategy for application users. Several layers of security are necessary to collectively reduce the potential for malicious attacks on a system. Security measures impact network architecture, component design and distribution, access control decisions, and detailed coding practices including input validation, prevention of SQL injections and more. In terms of system design, although user authentication and authorization plays a key role in controlling user access to features, functionality and resources - component level access control can play an even more critical role in reducing an application’s vulnerability to attack.

The identity under which application components are run along with permissions they are granted through code access security policy can limit runtime access to protected resources and privileged functionality. ASP.NET application code can be sandboxed to run in a lower privilege environment in both respects - thereby reducing the attack surface and preventing attackers from gaining access to the system. In this article I will discuss approaches to sandboxing application code and business components that support the application, to provide only the required privileges for each layer to access the resources and functionality it needs. I’ll provide some perspective on component design to support incremental approaches to component sandboxing and privilege elevation. In Part 1 you’ll learn how to configure ASP.NET applications to secure application code, how to apply impersonation and code access security policy to give required access to specific components, and how to avoid some of the pitfalls along the way. In Part 2, I’ll show you how to implement a more elegant sandboxing solution that involves the allocation of components to higher privilege processes using Enterprise Services.

Hardening the ASP.NET Application

The term “sandbox” refers to a restricted environment where application code can run without wreaking havoc on the rest of the system. All ASP.NET application requests should be initially processed within a secure sandbox that has no more privileges than is absolutely necessary to run a basic ASP.NET application. This poses a challenge, however, since Web applications usually require access to resources such as the registry, event logs, files and folders on the local machine or across network boundaries, and data storage. Access to these resources is typically restricted to specific Windows accounts or roles. The Windows identity under which code executes therefore governs this access. The .NET Framework can also restrict access to resources and functionality through security policy – further limiting what application code is able to do. If the ASP.NET application isn’t granted access to those resources because of the governing Windows identity or limited permissions granted by security policy, a meaningful application will not be able to function.

In order to design an effective security strategy for your ASP.NET applications, you must first know how runtime identities and security policies are configured for ASP.NET, and understand their affect on application behavior.

The Importance of Process Identity

The ASP.NET worker process runs under a specific Windows account specified by the <processModel> setting in the machine.config. Application code is governed by this account so it can be tempting to elevate the privileges of this account so that applications can access additional resources and functionality. What you have to consider is that any access granted the worker process account, will also be granted a hacker that manages to attach code to the process. With that in mind, let’s review configuration options and recommended practices.

The default setting for the ASP.NET worker process identity is the machine account as shown here:

<processModel enable="true" userName="machine" password="AutoGenerate" ... />

In fact there are two built-in accounts that can be used here: system or machine. If ASP.NET were configured to use the system account, it would run under the same account as IIS. This is a highly privileged account that has access to virtually all system resources, which makes it a big “no-no” to run your application code with this identity. The machine account, on the other hand, follows the principal of least privilege – making it a safe identity under which application code can run. The machine account has access to a specific set of directories in order for ASP.NET applications to run properly - including the location where ASP.NET temporary files are stored and the global assembly cache (for a complete list see: http://msdn.microsoft.com/library/en-us/cpguide/html/cpconaspnetrequiredaccesscontrollistsacls.asp).

Figure 1 illustrates how the ASP.NET worker process is launched with the configured <processModel> identity. Though each application runs in its own application domain within the worker process, the process identity governs access to resources protected by Windows credentials. If an application requires access to resources not available to the worker process identity, several related options exist:

  1. Grant additional privileges to the machine account
  2. Configure a specific, higher privilege account in lieu of machine
  3. Impersonate a specific, higher privilege account in the web.config
  4. Impersonate a specific, higher privilege user at runtime, as needed

Option 1 and 2 violate our mission to sandbox the application code within a secure environment. Option 3 is configurable on a per-application basis. The following web.config settings tell the ASP.NET runtime to impersonate the dbreadwrite account for all requests to this application:

<identity impersonate="true" userName="dbreadwrite" password="password" /> 

Impersonation puts each request thread into a special state where it uses a second identity (not the process identity) to gain access to resources and functionality. This will work as long as the account has also been granted access required by the ASP.NET runtime (see: http://msdn.microsoft.com/library/en-us/cpguide/html/cpconaspnetrequiredaccesscontrollistsacls.asp). But, this still violates our sandboxing mission since every thread will be elevated to the impersonated identity, which means any malicious code also operates under that identity.

A properly architected application should not require the entire application to run with elevated privileges. Rather, only components that require additional rights should be granted those rights as needed through short-term impersonation – which would be the intent of option 4 above. The point being we can leave the ASP.NET worker process running with limited privileges and find a way to elevate those privileges without opening up the entire application surface to potential hackers.

Application Trust Levels and Security Policy

Code access security also plays a role in sandboxing the application code – because it allows .NET applications to control what individual components can do, regardless of the process identity within which they execute. Each .NET assembly involved in servicing application requests is granted runtime permissions based on evidence including its zone, source location, publisher and strong name. By default ASP.NET application assemblies run with FullTrust, which means they are granted unrestricted access to the system (however, remember that process identity still has the last word). There are a number of predefined security policies available to ASP.NET applications. These policies are configured through the <trust> element of the web.config, whose settings include: Full, High, Medium, Low and Minimal. Each trust level maps to an XML security policy file, shown here as configured in the machine.config:

    <system.web>
      <securityPolicy>
        <trustLevel name="Full" policyFile="internal" />
        <trustLevel name="High" policyFile="web_hightrust.config" />
        <trustLevel name="Medium" policyFile="web_mediumtrust.config" />
        <trustLevel name="Low" policyFile="web_lowtrust.config" />
        <trustLevel name="Minimal" policyFile="web_minimaltrust.config" />
      </securityPolicy>
      <!--  level="[Full|High|Medium|Low|Minimal]" -->
      <trust level="Full" originUrl="" />
    </system.web>

The policy specified by the <trust> element is loaded by the ASP.NET runtime determine permissions to be granted to application assemblies. Though Full is the default setting (an internal policy that is equivalent to FullTrust or unrestricted access) this value can be modified or overridden in the application level web.config. The following example sets the trust level to Low:

<trust level="Low" originUrl="" />

As defined by the XML policy file for Low trust, this setting prevents application assemblies from calling unmanaged code or invoking serviced components, they cannot write to the event log or access the registry, they cannot access OLE DB or SQL server data sources, file I/O activities are restricted to the application directory, and Assert permission is not granted. In fact, with this setting you cannot debug the application either! This constrains application code significantly, which means any meaningful application code requiring additional permissions must find a way to get them on demand.

Custom XML policies can also be written to apply tailored code access security restrictions the application. This is primarily useful if your intent is to elevate privileges for the entire application, something we’re trying to get away from by following the principal of least privilege. Setting the trust level to Low will serve the purpose of creating a very secure sandbox for the application code - which means our focus can shift to how to acquire privileges as needed beyond the sandbox.

For an introduction to code access security, see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod81.asp, and to learn more about ASP.NET trust levels see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod82.asp.

Life Beyond the Sandbox

So far I’ve described how process identity and code access security policy can create a restricted sandbox where application code can execute. Figure 2 illustrates the recommended configuration: ASP.NET worker process running with the lower privilege machine identity and the application domain assigned permissions based on the Low trust level.

At this point, all application assemblies that participate in servicing application requests are limited by the process identity and granted security permissions. Of course this is by design, since any potentially malicious code injected into the process or application domain will also be restricted. To put this in context, Figure 2 illustrates the components in the sample application, and their lack of ability function properly since they cannot access the database, file system or registry. So the challenge becomes granting appropriate access to resources and functionality to each component.

There are a few basic design guidelines that should be followed for developing ASP.NET applications, in order to support life beyond the sandbox:

  1. Do not place any business logic into the code-behind files for the application, particularly any code that may require access to protected resources and functionality.
  2. Allocate components into logically distinct assemblies that can be granted unique runtime identities and additional code access security permissions as needed.

You can see in Figure 2 that the application assembly is separate from assemblies that interact with the database, perform file I/O and invoke the Data Protection API (DPAPI) which touches the registry. Though these components are currently governed by the worker process identity and security policy, the division of high level functionality into separate assemblies is the first step in promoting individually configured sandboxes for their execution through a combination of impersonation, code access security grants, security assertions and process allocation.

Elevating Code Access Privileges

Clearly with a reduced security policy, we need to elevate security policy for specific assemblies supporting the application. This excludes the application assembly since it should comprise only basic code-behind logic and be void of business intelligence.

Strongly Named Assemblies and the GAC

The code-behind and related code are compiled into the application assembly which is deployed to the \bin directory for the application. Supporting assemblies that require additional permissions can (and should) be strongly named and subsequently deployed to the global assembly cache (GAC). In fact strongly named assemblies MUST be deployed to the GAC, because the ASP.NET runtime doesn’t support a configuration where strongly named assemblies are deployed to the \bin directory. The benefit to GAC deployment is that assemblies loaded from the GAC are granted FullTrust by the ASP.NET runtime, which means they’ll be able to do work that the application assembly cannot.

ASP.NET can find any assembly deployed to its \bin directory, but assemblies deployed to the GAC must be explicitly be configured in the <assemblies> section as shown here:

<compilation defaultLanguage="c#" debug="false" >
<assemblies>
	<add assembly="mlb.Util.IO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0622eb5aa947655d" />
	<add assembly="mlb.Util.Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0622eb5aa947655d" />
	<add assembly="mlb.Photos.Dalc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0622eb5aa947655d" />
	<add assembly="mlb.DataProtection, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0622eb5aa947655d" />
</assemblies>
</compilation>

NOTE: Be aware that these settings are all based on the runtime requirements of ASP.NET and do not address debugging requirements for Visual Studio 2003. You will not be able to debug applications set to Low trust level.

As Figure 3 illustrates, supporting assemblies for the sample application - mlb.Photos.Dalc, mlb.Util.IO, mlb.Util.Security, and mlb.DataProtection - are granted FullTrust once deployed to the GAC.

A side-effect of this is that FullTrust assemblies also implicitly demand FullTrust of callers. So at minimum, assemblies invoked directly by the application assembly (a partially trusted assembly) must be decorated with the AllowPartiallyTrustedCallersAttribute.

[assembly: AllowPartiallyTrustedCallers()]

This makes it possible for the application assembly to successfully run with very few security permissions, while it invokes business components at the middle-tier that have been granted FullTrust. Of course, if you have tried this before you probably realize this is only the beginning. Security demands for FullTrust and other specific permissions can still get in the way of successful execution. A security demand from these supporting assemblies, or from other .NET Framework assemblies, will perform a stack walk all the way up to the original caller (the application assembly). But the application assembly cannot satisfy any meaningful permission demands in its current trust level configuration.

Permission Demands, Failed Stack Walks and Assertions

Since the application assembly will not satisfy most permission demands, it will be necessary for middle-tier components to assert permissions to enable functionality. Since components deployed to the GAC are granted FullTrust, they can assert virtually any code access permission, to circumvent a stack walk that is sure to fail when it reaches the application assembly.

The sample project contains several examples where assertions must be applied. For example, when a user uploads a photo, the application code invokes the SaveFile() function exposed by the file I/O component, mlb.Util.IO. Since the application’s code access permissions are set to Low, the application doesn’t have rights to write to the application path, or anywhere else for that matter. Even though mlb.Util.IO is granted FullTrust once deployed to the GAC, a permission demand from the FileStream object will fail once it reaches the application code. Prior to using the FileStream the required permission must be asserted to prevent the demand from completing the stack walk to the application assembly, as shown here:

public void SaveFile(System.IO.Stream fileStream, string filename)
{
  FileStream streamWriter = null;
  FileIOPermission fileIOPerm;

  try
  {
	fileIOPerm = new FileIOPermission(FileIOPermissionAccess.AllAccess, this._path);
	fileIOPerm.Assert();

string filePath = String.Format("{0}\\{1}", this._path, filename);
streamWriter = new
FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None);

	// additional code to save the file

CodeAccessPermission.RevertAssert();
  }
  finally
  {
	try {
CodeAccessPermission.RevertAssert();
}
	catch {}

	if (streamWriter!=null)
		streamWriter.Close();
  }
}

The assertion must be carried out before the permission demand is executed, and should be reverted immediately after the file is saved. In the event an exception prevents the assertion from being reverted, the finally code block also includes the command to revert the assertion (an important precaution to insure the assertion is indeed reverted).

A similar assertion must be made in order for the database component, mlb.Photos.Dalc, to execute commands against the database. In this case the SqlCommand object supplied by the SQL Data Provider demands callers to have SqlClientPermission. The result is that the sample code asserts this permission prior to invoking calls to post or retrieve data:

try
{
System.Data.SqlClient.SqlClientPermission sqlClientPerm = new
		System.Data.SqlClient.SqlClientPermission(PermissionState.Unrestricted);
sqlClientPerm.Assert();

this.sqlConnectionPhotos.Open();
int rows = this.sqlAdapterPhotos.InsertCommand.ExecuteNonQuery();
this.sqlConnectionPhotos.Close();
}
  finally
  {
	try {
CodeAccessPermission.RevertAssert();
}
	catch {}
this.sqlConnectionPhotos.Close();

 }

Although the code required to assert permissions is trivial, clearly it requires a level of comfort with code access security and fairly intimate knowledge of the permission requirements for each assembly. This is a challenge because the tools have not yet reached a point where you can easily detect what permissions are required. This means developers have to be disciplined and pay attention to the requirements of .NET Framework functionality they invoke (security demands are usually well documented).

The upside of this effort is that the ASP.NET application code, which is the first stop for any hacker injections, has a greatly reduced attack surface. This makes it very difficult for malicious code to do anything useful within the bounds of the application sandbox.

At the same time, assertions can be dangerous because they open the door to luring attacks. However, by encapsulating the assertions in the middle-tier assemblies, we are effectively making an assumption that immediate callers will not be malicious. Traditionally an assertion is preceded by a permission demand to offset this risk. For example, in a non-ASP.NET scenario I would traditionally recommend performing a StrongNamePermission demand before asserting FullTrust or UnmanagedCode permission. In this way I could guarantee that the immediate caller was part of my family of assemblies, sharing a common strong name. In this case, we cannot give a strong name to the application assembly, and there are no meaningful permissions that can be demanded that will be satisfied by the stack walk.

NOTE: It is possible to create a custom permission and demand that of the application assembly, to reduce the chance of a luring attack. For more information on how to do this see this MSDN article: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod115.asp

At this point, we’ve locked down the application assembly, elevated middle-tier assemblies to FullTrust, and carefully applied assertions just in time to enable functionality. The next thing we have to deal with is the runtime identity of the ASP.NET worker process, and limitations that have been introduced by running with a lower privilege account.

Impersonation on Demand

We can have our GAC assemblies assert permissions until the cows come home, but without the blessing of the process identity under which code is running there won’t be access to restricted resources and functionality. To overcome the limitations of application code running as the machine account, a higher privilege account can be impersonated for the duration necessary to access restricted resources and functionality.

Impersonation Basics

Though the ASP.NET worker process is running with its configured Windows account, each thread that processes requests can impersonate specific Windows accounts. First a valid Windows token must be retrieved with a call to the LogonUser() API. This token can be wrapped in a WindowsIdentity object and used to impersonate the user on the currently executing thread. Listing 1 shows the LogonUser() API declaration, along with a few other unmanaged functions imported for use from the advapi32.dll.

LISTING 1--------------------------
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace mlb.Util.Security
{
	public class LogonAPI
	{

		public const int SECURITY_IMPERSONATION_LEVEL_SecurityAnonymous=0;
		public const int SECURITY_IMPERSONATION_LEVEL_SecurityIdentification=1;
		public const int SECURITY_IMPERSONATION_LEVEL_SecurityImpersonation=2;
		public const int SECURITY_IMPERSONATION_LEVEL_SecurityDelegation=3;

		public const int LOGON32_PROVIDER_DEFAULT = 0;
		public const int LOGON32_PROVIDER_WINNT35 = 1;
		public const int LOGON32_PROVIDER_WINNT40 = 2;
		public const int LOGON32_PROVIDER_WINNT50 = 3;

		public const int LOGON32_LOGON_INTERACTIVE = 2;
		public const int LOGON32_LOGON_NETWORK = 3;
		public const int LOGON32_LOGON_BATCH = 4;
		public const int LOGON32_LOGON_SERVICE = 5;
		public const int LOGON32_LOGON_UNLOCK = 7;
		public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
		public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

		public const int ERROR_LOGON_FAILURE = 1326;

		[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
		public static extern bool
			LogonUser(string lpszUsername,
			string lpszDomain,
			string lpszPassword, int dwLogonType,
			int dwLogonProvider, ref IntPtr phToken );

		[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
		public static extern bool RevertToSelf();

		 [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
		public static extern  bool CloseHandle(IntPtr handle);

		 [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
		public static extern int DuplicateToken(IntPtr hToken,
			int impersonationLevel,
			ref IntPtr hNewToken);
	}

}

END LISTING 1--------------------------

The code to impersonate a Windows account is trivial, however since we’re dealing with a sandboxed environment there will be a few steps required to make this possible. There are several locations in the sample code that require impersonation prior to accessing resources, so I’ll use the database access example for this discussion, as shown in Listing 2.

LISTING 2

SecurityPermission secPerm = new
SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
secPerm.Assert();

IIdentity user = null;
WindowsPrincipal principal = null;
WindowsImpersonationContext context = null;
IntPtr refToken = IntPtr.Zero;
bool loggedIn;

loggedIn =
LogonAPI.LogonUser("dbreadwrite", "mydomain", "password",
LogonAPI.LOGON32_LOGON_NETWORK_CLEARTEXT,
LogonAPI.LOGON32_PROVIDER_DEFAULT, ref refToken);

if (loggedIn == true)
{
user = new WindowsIdentity(refToken, "NTLM", WindowsAccountType.Normal, true);
	principal = new WindowsPrincipal(user as WindowsIdentity);
context = WindowsIdentity.Impersonate(user.Token);
}
CodeAccessPermission.RevertAssert();

// code to access database resources under dbreadwrite account

context.Undo();

For the sake of simplicity, Listing 2 does not reflect the same level of detail shown in the final code sample for this article. I have removed error handling and flattened the code hierarchy so we can focus on the actual steps required to impersonate credentials. Listing 2 handles impersonation of a valid database account prior to accessing the database, as follows:

  • Since we’re calling unmanaged code, we’ll need to assert UnmanagedCode permission prior to calling LogonUser()
  • When LogonUser() is called, the current thread is impersonating a database user that has read and write privileges: dbreadwrite.
  • With the token returned from LogonUser(), a WindowsIdentity is created to wrap the token. This WindowsIdentity can also be used to create a WindowsPrincipal object that can be assigned to the current thread for role-based security checks.
  • The WindowsIdentity is used to impersonate the wrapped token for the calling thread. This returns an impersonation context which can be used to Undo() the impersonation. Undo() should be wrapped in a try/finally clause to be sure the impersonation is reverted as soon as possible. Otherwise, impersonation is in force until the request thread terminates.

Although in theory impersonation can open up the attack surface, this vulnerability is limited to the duration of the impersonation. By limiting the window in which a higher privilege account is governing the thread, we are still slowing down potential attackers, forcing them to look for information that is buried much deeper, in order to try to hook a process or thread. Furthermore, the account that is being impersonated, although may have access to some protected resources, will not have access to all, thereby limiting the potential impact of an attack.

Protecting Impersonation Credentials

Typical resources that require a higher privilege identity to run include the registry, the file system, and database objects. During the design phase of system development, allocation of functionality to components should also lead to discussions about security boundaries for those components. That means you probably have some idea up front which accounts should be configured throughout the system, to enable specific application functionality.

The sample application defines two database accounts: dbreadwrite and dbreadonly; and one file system account: fsreadwrite. These account credentials must be safely stored somewhere in order for the application to impersonate them on demand. The problem with storing credentials in the assemblies themselves is their vulnerability to disassembly inspection, and their lack of configurability if the accounts are modified. Storing credentials in <appSettings> is a better idea, provided those settings are well encrypted.

The .NET Framework supplies a cryptography API that could be employed to secure private application settings. However, the Data Protection API (DPAPI) provides an API for encrypting and decrypting data that also removes the key management aspect of this process. With the DPAPI the associated account password is used to derive an encryption key, and the operating system manages this key automatically. Although individual user accounts can be used to generate encryption keys, for an ASP.NET application it makes more sense to use the local machine account.

NOTE: For more information on the DPAPI, see this link: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT07.asp. A variation of the instructions given here is implemented in the sample code for this article.

Using the DPAPI utility in the sample code, I created a utility to encrypt connection strings and user credentials that I needed to store in <appSettings>. The resulting <appSettings> on my machine for the database user accounts look like this:

<appSettings>
<add key="dbuserdomain" value="AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAACAYpj5hmfkuKVp8417ROagQAAAACAAAAAAADZgAA
	qAAAABAAAACAw2OpZ9xlfDXBw16H8veTAAAAAASAAACgAAAAEAAAAH4lDLFkKzOXCGrEg0UnfC0QAAA
	AbxLmkenvpnYo8kMAOqrbDxQAAAAywLHqkJhweCUt9lzEf9xF6J9osw==" />
<add key="dbusername" value="AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAACAYpj5hmfkuKVp8417ROagQAAAACAAAAAAADZgAAqAAAA
	BAAAAAi5fHWw6TrBCTFlfVshSYiAAAAAASAAACgAAAAEAAAAPooBkA98SGqG4QaD6YGSw_IAAAAvx6oQrtT6
	zUUAAAAbSMCpcdifmFr+5nvaNCFeibBl8U=" />
<add key="dbuserpw" value="AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAACAYpj5hmfkuKVp8417ROagQAAAACAAAAAAADZgAAqAAAABA
	AAAAi5fHWw6TrBCTFlfVshSYiAAAAAASAAACgAAAAEAAAAPooBkA98SGqG4QaD6YGSw_IAAAAvx6oQrtT6zUUA
	AAAbSMCpcdifmFr+5nvaNCFeibBl8U=" />

...

</appSettings>

When this application is installed to another machine, these keys must be regenerated since the encryption key is associated with a particular machine. That should tell you that part of the deployment process should be a script that can generate keys and add them to the web.config, to streamline the process.

To access protected keys at runtime, the DPAPI utility (mlb.DataProtection) provides high level functions to encrypt and decrypt values. Since this functionality must be highly secure, the assembly is not marked with the AllowPartiallyTrustedCallersAttribute, forcing calling code to assert FullTrust prior to invoking functionality. In several areas of the sample code, where connection strings and user credentials are required, you’ll find similar code to the following:

NamedPermissionSet namedSet = new NamedPermissionSet("FullTrust", PermissionState.Unrestricted);
namedSet.Assert();

domain = DPAPIUtil.DecryptFromMachineStore(ConfigurationSettings.AppSettings["fsuserdomain"]);
userName = DPAPIUtil.DecryptFromMachineStore(ConfigurationSettings.AppSettings["fsusername"]);
password = DPAPIUtil.DecryptFromMachineStore(ConfigurationSettings.AppSettings["fsuserpw"]);

CodeAccessPermission.RevertAssert();

Conclusion

In this article you learned the difference between process identity and code access security permissions, and how to lock down your ASP.NET application components from both perspectives to reduce vulnerability to attack. In addition, you learned how to make real application code function, even within the context of this restricted environment, by elevating code access permissions for middle-tier assemblies, asserting permissions as needed, and impersonating credentials required to access protected resources. The examples so far focus on strategies for sandboxing and elevation without allocating assemblies to independent processes and implementing access control. This approach is important for applications that do not support rich component deployment and distribution options available with Enterprise Services. In Part 2, I’ll take another look at this sandboxing problem on a larger scale, and incorporate more sophisticated component architecture with less coupling between component and privilege elevation.

Get the code sample here:
http://www.dotnetdashboard.net/sessions/securitysummit.aspx

Authors

Michele is a Chief Architect with IDesign, Microsoft Regional Director for San Diego, Microsoft MVP for Web Services and a BEA Technical Director. In addition, Michele is a member of the board of directors for the International Association of Software Architects (IASA). At IDesign Michele provides high-end architecture consulting services, training and mentoring. Her specialties include architecture design for robust, scalable and secure .NET architecture; localization; Web applications and services; and interoperability between .NET and Java platforms. Michele is a member of the INETA; a frequent conference presenter at major technology conferences such as Tech Ed, PDC, SD and Dev Connections; conference chair for SD’s Web Services track; and a regularly published author. Michele’s next book is Windows Communication Framework Jumpstart for O’Reilly, due out in early 2006. Reach her at www.idesign.net or visit her blog at www.dasblonde.net.

News | Blogs | Discussions | Tech talks | White Papers | Downloads | Articles | Media kit | About
All Content Copyright ©2007 TheServerSide Privacy Policy
Site Map