
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:
- Grant additional privileges to the machine account
- Configure a specific, higher privilege account in lieu of machine
- Impersonate a specific, higher privilege account in the web.config
- 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:
- 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.
- 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.
|
|