Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional ASP.NET Security - Jeff Ferguson

.pdf
Скачиваний:
28
Добавлен:
24.05.2014
Размер:
13.26 Mб
Скачать

Code Access Security

Rogue

not among Gl

Assembly

 

Al calls into A2

\

Trusted Assembly For each Assembly in the upper call stack, CLR checks if

FileAccess permission is

FileStream Assembly

permissions

^^

Demands for FileAccess permission

In this diagram Gl, G2, and G3 are the permissions each assembly has been granted by security policies at load time, and the large arrow on the right the direction of the stack walk.

Evidences

Now that we've provided the big picture, let's investigate the details, starting with CAS evidences.

Evidences provide information about an assembly identity. They can be split into two main categories: assembly inner properties (such as assembly Strong Name or Publisher) and assembly origin information (such as URL, Site, Zone). The former information is fixed, while the latter can vary. In the following table, we can see a list of the .NET Framework built-in evidences.

Evidence

Description

Evidence Type

 

 

 

Application

Base path for probing private assemblies

Assembly origin

Directory

 

 

Hash

Cryptographic hash such as SHA1

Within assembly

Publisher

Authenticode signature

Within assembly

Site

Site of origin, such as

Assembly origin

 

http://www.microsoft.com

 

Strong Name

Cryptographically strong name of the

Within assembly

 

assembly (generated by sn. exe tool)

 

URL

URL of origin

Assembly origin

Zone

Zone of origin, such as Internet Zone

Assembly origin

 

 

 

Some of these evidences may not be available for some assemblies, such as the Publisher or the Strong Name.

315

Note that some evidences are stronger than others, depending on how easily they can be tampered with. For instance, Strong Name evidence is much stronger (expecially if using 1024-bit keys) than URL evidence, since DNS and web sites can be hijacked.

The evidence entries shown above are defined as built-in for the following reasons:

Q They are automatically evaluated and attached to the assembly by the CLR loader when referenced for the first time.

Q The default policy configuration set up when the. NET framework is installed is based upon such evidences.

Each built-in evidence is represented by a specific class in the BCL (there is a Site class, a Url class, and so on). Each built-in evidence class has a companion "membership condition" class (such as the ZoneMembershipCondition class, StrongNameMembershipCondition class, and so on). Membership condition classes are contacted by the policy evaluator during the permission granting process.

We need to introduce other concepts before being able examine how they are used in any detail; we encounter more details when we come to look at CAS policies in more detail, later in this chapter.

Application, Domain, and Assembly Evidence

So far we have looked at assembly permissions and evidences. Some CAS permissions are also applicable to application domains as a whole, determining what the application domain is allowed to do (such as creating another application domain). For this reason, the CLR determines and attaches evidences to application domains as well.

When an application domain or an assembly is loaded automatically by the CLR, we have no way to modify the assigned evidence set. However, the CLR exposes methods that enable us to create application domains or load assemblies explicitly. In this case, we are given the opportunity to modify the evidence set (adding new evidences or overriding evidences provided by the CLR).

The BCL provides different overloaded methods to create an Application Domain. If we use the basic method signature, that takes only the domain friendly name, the CLR copies the caller domain evidence to the newly created one:

AppDomain myappdomain = AppDomain.CreateDomainf"myappdomain");

However, other overloaded methods enable us to specify explicitly what evidence must be associated with the new application domain. In the following sample, we override the Zone evidence setting to Internet.

//create

a new evidence

set

object

initialized with the

evidence

values

of

//the

current

Application

domain

 

 

 

 

Evidence

ev

= AppDomain.CurrentDomain.Evidence;

 

 

 

Zone

z

=

new Zone(SecurityZone.Internet);

 

 

 

//Add or

override

( i f

yet

existing)

the newly created

evidence

to the

evidence

set

 

 

 

 

 

 

 

 

 

 

ev.AddHost(z);

 

 

 

 

 

 

 

 

AppDomain myappdomain = AppDomain.CreateDomain{"myappdomain", ev);

316

Code Access Security

Almost the same applies when explicitly loading an assembly into an application domain (using Load, LoadFrom, ExecuteAssembly, and so on). When only the overloaded method that gets the assembly name is used, the CLR loader automatically provides proper evidences to the assembly.

There are other overloaded methods that let us specify the evidence that must be assigned to the loaded assembly. Note that there is a subtle difference here. The evidence provided by the loader is attached to the assembly in any case (this doesn't happen when creating an application domain unless we use the simplest CreateDomain overloaded method, which gets only the assembly friendly name). Assembly evidences that are explicitly specified are added (if they do not already exist), or overriden in the case of those provided by the CLR.

In the following sample, the Zone evidence provided by the CLR (Zone=Internet or Zone=Intranet, since the assembly is loaded from a URL) is overridden with a Zone=MyComputer evidence. These few lines of code have a big impact on CAS Security. The permission the policy evaluator will assign to the assembly will be FullTrust.

Zone z = new Zone(SecurityZone.MyComputer); ev.AddHost(z);

myappdomain.ExecuteAssembly( "http://serverl/cas/ConsoleApplication2.exe", ev);

A host must have been granted a specific permission by the CLR (SecurityPermissionAttribute class with ControlEvidence property set to True) to be able to assign evidences to other application domains or loaded assemblies. Application domains with such permission are commonly referred as trusted domain hosts.

Custom Evidence

The Evidence infrastructure is completely extensible, since any serializable object can be provided as an Evidence entry. We can programmatically provide custom evidences when loading assemblies or application domains explicitly, as we saw above. To have the CLR load a custom evidence automatically, as happens for built-in evidences, we must embed our custom evidence definition as a resource of the assembly using the assembly linker tool (al. exe) specifying the file containing the evidence definition with the / e switch.

Note, however, that a generic serializable object is of no use until we define and register a companion Membership Condition class in our security policy. Membership condition classes are required to implement the IMembershipCondition interface.

We will look in detail later in the section - when we look at security policies - at the steps required to register a custom evidence class in the CAS policy configuration.

Runtime Hosts

Since, at present, the windows operating system has no built-in knowledge of the .NET runtime, a few bits of unmanaged code are required to load and start up the CLR in the process before any .NET code can be run (note that when the CLR is loaded it automatically creates a default application). Any unmanaged code that loads and bootstraps the CLR is called a Runtime host.

317

The .NET Framework comes with three built-in runtime hosts: one to run .NET applications in the Windows shell, a second one that hosts ASP.NET applications, and the last one to let us run .NET applications with IE.

The unmanaged API that loads the CLR runtime is exposed as a COM interface. This means that the .NET Framework enables us to write our custom runtime host in unmanaged code, even in VB6, with few lines of code. To do this, we need to reference mscoree . tlb and ms cor lib. tlb and then write something such as:

clr = new mscoree.CorRuntimeHost,• clr.start;

appdomain = new mscorlib.AppDomain; clr.GetDefaultDomain appdomain; appdomain.ExecuteAssembly_2(<assemblypath>);

If unmanaged code could inject evidences or any security-related settings into a .NET application, this would open a can of worms, making all CAS infrastructure useless. Fortunately this is not the case. Although mscorlib. tlb exposes the Evidence interface, and all other CAS related interfaces, such interfaces have no methods defined, thus making the CLR sealed to unmanaged exploits (there is actually no clear reason why these interfaces are present at all).

Code Access Security Permissions

CAS permissions define what an assembly is or is not allowed to do. The .NET Framework Base Class Library comes with a list of built-in permission classes, one for each resource or service it provides access to. Each assembly of the BCL providing access to a specific resource protects it by putting proper security demands on the corresponding permission object each time the resource is requested. This is done in order to guarantee that all the assemblies in the call stack have been granted the demanded permission by CAS security policies.

This following table shows the built-in permissions in the .NET Framework (the meanings are self explanatory for most of the permissions types).

Permission Classes

System.DirectoryServices.DirectoryServicesPermission

System.NET.DnsPermission

System.EnvironmentPermission

System.Diagnostics.EventLogPermission

System.Security.Permissions.FileDialogPermission

System.Security.Permissions.FilelOPermission

System.Security.Permissions.IsolatedStorageFilePermission

System.Security.Permissions.IsolatedStoragePermission

System.Messaging.MessageQueuePermission

318

Code Access Security

Permission Classes

System.Data.OleDbPermission

System.Drawing.Printing.PrintingPermission

System.Security.Permissions.ReflectionPermission

System.Security.Permissions.RegistryPermission

System.Security.Permissions.SecurityPermission

System.ServiceProcess.ServiceControllerPermission

System.NET.SocketPermission

System.Data.SqlClient.SqlClientPermission

System.Security.Permissions.UlPermission

System.NET.WebPermission

System.Diagnostics.PerformanceCounterPermission

The only permission object that requires some explanation is the SecurityPermission class. This class is used to allow permission to different disparate actions such as setting assembly evidences, creating application domains, and calling into unmanaged code (API and COM objects).

Take extreme caution to avoid granting the unmanaged code permission if not absolutely required. When a .NET assembly is allowed to call into unmanaged it can potentially bypass any code access security checks and thus do whatever it likes on the system.

In the following figure we can see all the specific permissions that can be set via the SecurityPermission class.

Grant assemblies the foBowing security permissions:

r r.

Enable assembly execution

ABow cafls to unmanaged assemblies Assert any permission that has been granted Skip verification

Enable thread control ABow policy control

Allow domain policy control Allow principal control

Create and control application domains Enable serialization formatter

Alow evidence control Extend infrastructure

Enable remoting configuration

Grant assemblies unrestricted access to aS security permissions

OK Cancel

319

As we can see, permission classes provide fine-grained control for different system resources. Some of these permissions map closely to the ones provided by the underlying operating system (FilelOPermission), while others are higher-level permissions that map closely to common application tasks (WebPermission, OleDbPermission, and so on).

All permission classes must implement the IPermission, ISecurityEncodable, IStackWalk, and lUnrestrictedPermission interfaces (all defined in the System. Security namespace). In reality, all built-in permissions objects do not explicitly implement all four interfaces, they inherit from the System. Security .CodeAccesPermission class instead. This class provides an implementation of the first three interfaces so that only the lUnrestrictedPermission interface has to be implemented explicitly. Note, however, that some methods of the CodeAccessPermission class must be overridden by each permission class. This is because their implementation depends on the behavior of specific permission classes. We will examine these methods when we come to look at the custom permission classes.

To provide declarative support via attributes for security demands and requests, each permission class has associated with it an attribute type counterpart class. For instance, the name of the corresponding attribute class for the FilelOPermission class is FilelOPermissionAttribute.

While the behavior of some permission types can be simply expressed with an all or nothing choice, most permissions need to expose more granular and specific semantics to allow effective control of the protected resource (for instance read, write, or append permissions).

To achieve this, each permission class specializes its semantics from the base CodeAccessPermission class by providing different overloaded constructors and specific properties or methods. All or nothing permission types simply expose a constructor that takes a parameter of type PermissionState whose value can be None or Unrestricted.

An example of an all or nothing permission class is the DnsPermission class, which controls rights to access Domain Name Systems (DNS) servers on the network.

[Serializable] public DnsPermission (PermissionState state);

An example of a more complex permission class is the FilelOPermission class. Since this needs to provide more powerful semantics, it exposes both different overloaded constructors and specific methods. These accept as parameters an ad hoc enumerator, specifying what action is granted permission, and another parameter specifying the list of files or directories the permission applies to. Here we show one of the overloaded constructors of this class and one of its specific methods that can be used to set its state:

[Serializable] public FilelOPermission (

FilelOPermissionAccess access, string [] pathList

[Serializable] public void AddPathList

( FilelOPermissionAccess

320

Code Access Security

Note that even complex permission classes must define the basic constructor that gets a permissionsState parameter.

Custom permission classes

.NET built-in permissions are designed to cover most application requirements. There are cases though, where you might need to implement CAS permissions on application-specific resources or services. This can be done thanks to the extensibility of the permission infrastructure.

In the same way as built-in permission classes, a custom permission is a class that inherits from the SecurityPermission class and implements the lUnrestrictedPermission interface.

To implement a specific behavior, a permission class is required to override the following methods of the SecurityPermission base class: Copy, Intersect, IsSubsetOf, FromXml, and ToXml. The implementation of Copy, FromXml, and ToXml is boiler plate code. These must operate in the following ways:

Q The Copy method must return an exact copy of the object instance.

Q The FromXml method is called by the CLR. A SecurityElement (a class implementing a lightweight version of the XML DOM) is passed as a parameter, and is used by the method implementation to set the state of the permission object.

Q The ToXml method is called by the CLR to get the state of the permission class back, in the form of a SecurityElement object.

More interesting are the IsSubsetOf and the Intersect methods. These are constructed in the following way:

public abstract bool

IsSubsetOf( IPermission target );

public abstract IPermission Intersect) IPermission target );

The CLR calls into the SecurityPermission class to process, respectively, Request and Demand calls.

According to the security permission object semantics, these methods must return true or false, comparing the status of the permission object against another instance of the same class that is passed in as a method parameter (see the method signature, above).

The implementation of all or nothing permission objects is straightforward, but can become quite complex, depending on the semantics of the implemented permissions. We will investigate the steps required to register a custom permission class in the CAS policy configuration a little later, when we look at security policies in more detail.

Remember that we need to implement an attribute type counterpart class if declarative use of the class is needed (for instance, to make a security Request). A custom permission class is available, within MyCustomPermission project, with the code download for this book.

321

Identity Permissions

Strictly speaking, identity permissions don't pertain to the CAS model. Nevertheless, we'll discuss them a little here, as they can help to secure an application in conjunction with CAS. The type of security provided by Identity permissions is commonly named Controlled Sharing.

Identity permission objects are created by the CLR and attached to an assembly when it is loaded. They are configured by the CLR in order to match the values of the assembly evidence. The built-in assembly evidences mapped to identity permissions are: Siteldentity, Publisherldentity, StrongNameldentity, Urlldentity and Zoneldentity.

Identity permissions can be used for security requests and demands. Suppose, for instance, that company X wants to make sure that no one else uses functionality implemented in the assemblies it has developed. This is easily done by placing a security demand on the strong name identity permission. Since only Company X holds the public-private key pair required to strongly sign assemblies with the demanded strong name, no one else will be able to place a security demand on the strong name identity permission.

Of course, a strong name identity permission demand is ignored by the CLR if the call is issued by an assembly not signed with the demanded strong name.

To get the result we want, we also need to define such classes as sealed or, more likely, place an inheritance demand, in addition to the strong name identity permission demand, in order to guarantee that such classes are not exploited by inheriting from them (we will look at some security implications of inheritance later in this chapter).

Note that identity permissions do not extend CAS policy permissions but intersect with them, so that they can only restrict but not extend permissions granted by CAS policies. For instance, suppose we have to extend the permissions of an assembly when downloaded from the Internet if it has a particular Strong Name. In such situations, identity permissions is not the way to go. To get the desired result we must appropriately customize CAS polices. We'll look at how to do this in the next section.

Code Access Security Policies

We have now investigated in some detail assembly evidence and CAS permissions. With a solid understanding of these two concepts, we can examine the toughest part of the CAS infrastructure: security policies and the security policies evaluator.

Security policies grant a set of permissions to an assembly, according to its evidence, when it is loaded into an application domain. CAS defines three distinct security policy levels:

Q Enterprise (to be deployed around the enterprise by administrators via msi files using the Group Policy snap-in or System Management Server (SMS)

Q

Machine Q

User

Additionally, CAS allows a trusted host to programmatically define an application-specific policy, and inject it into a newly created application domain. This approach will be used, for example, by the next version of SQL Server, to tighten the security on assemblies that run within the application domain, which is set up by the database runtime host.

322

Code Access Security

Unless specified explicitly, the final permissions granted by the CAS infrastructure to an assembly will be those granted in the intersection of the permissions acquired within each policy evaluation, plus the application domain policy, if defined:

Application

Domain

Machine"

User

Allowed

 

 

Permissions

Enterprise

The three security policy configurations, for Enterprise, Machine, and User, are stored in XML files:

Enterprise policy is defined in:

<WinDir>\Microsoft.NET\Framework\<version>\config\enterprisesec.config

Machine policy is defined in:

<WinDir>\Microsoft.NET\Framework\<version>\config\security.config

User policy is defined in:

<Documents and Settings Path>\<Username>\Application DataXMicrosoft\CLR Security Config\<version>\security.config

Being XML-based, security policies can be manually edited, but this isn 't recommended, unless you really know what you 're doing.

The BCL provides a set of classes that expose the policy structure as an object model. This object model lets us programmatically access and modify the three policies configuration and create application-specific ones. We'll examine this shortly.

The .NET Framework provides a couple of tools to edit policies. There is a UI, MMC-based, tool called Microsoft .NET Framework Configuration, which is accessible from Start/Settings/Administrative Tools, from which we can manage the three policy levels here:

;Iftf -NET Framework Configuration

Action View

Tree I

^ My Computer ;• -^)

Assembly Cache • -QgJ

Configured Assemblies ; ^3

Remoting Services

-(Jl Runtime Security Policy :

GO ^ Enterprise © II

IfflBSffiB B • 0 User @

Applications

Permission Sets and Code Groups

Additionally, a command-line-based tool called caspol. exe is available. Neither of these tools acts on the XML files directly, but they rely on the policy administrative classes mentioned above.

Before describing the logic used by the policy evaluator when matching the assembly evidence against the policy configuration, we need to introduce a couple of additional concepts: Permission Sets and Code

Groups.

A Permission Set is a named set of permissions registered in a specific security policy. These are not shared among different policies.

Code Groups are the building blocks of security policies. A code group is defined as the association between a membership condition and a permission set.

A membership condition is simply a specific value of an evidence type, for instance Zone=lnternet, URL=http.7/www.microsoft.com, and so on. In other words, a membership condition is an instance of an evidence class that has been initialized with a specific state.

When assembly evidence contains an evidence entry matching the code group membership condition, the assembly is a member of the code group, and thus the permission set assigned to the code group is granted to the assembly.

The kind of code group we have mentioned is implemented by the UnionCodeGroup class (this is the kind of code group we will deal with in the rest of the chapter). The .NET Framework defines other types of code groups: the NetCodeGroup class and the FileCodeGroup class. These code groups are different from UnionCodeGroups because they do not have an associated static permission set. The NetCodeGroup class and the FileCodeGroup class evaluate and grant permissions dynamically in order to provide special policy functionalities, giving, respectively, permission to an assembly to connect back to its site of origin, and to manipulate files located in the directory from which the assembly has been loaded.

The following figure depicts the logic used by (Union) code groups to decide whether their associated permission set has to be granted to an assembly. Assembly A has the following evidence set: Zone, Hash and StrongName. During the policy evaluation flow (which we will be looking at in somoe more detail a little later on) assembly A evidence is compared to the code group B membership condition. The code group B membership condition is Zone=Intranet. Policy evaluation will grant the Everything permission set to assembly A if, and only if, the assembly A Zone evidence value is Intranet.

324

Соседние файлы в предмете Программирование