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

Professional ASP.NET Security - Jeff Ferguson

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

Code Access Security

I If yes, Assembly A gets the

I Everything permission set

Zone X = Intranet ?

Code Group

Membership: Zone = Intranet

Permission Set = Everything

Built-in Permission Sets

The .NET Framework comes with seven built-in permission sets.

a FullTrust

a SkipVerification

Q Execution

Q Nothing

a Locallntranet

a Internet

a Everything

None of these permission sets can be modified or deleted except for the last one.

At installation time, the Everything permission set contains all the built-in CAS permissions, as we can see here:

Tree

 

 

Permission

 

 

 

^ My Computer

@ Environment Variables

;•••>§&)AssemblyCache

j?j File Dialog

i- -{jgj Configured Assemblies

2 File IO

=• -^3 Remoting Services

2 Isolated Storage File

B -l^p Runtime Security Policy

?] Reflection

:

S3- ^ Enterprise

§ Registry

|

B S Machine

2J Security

I

a Q) Code Groups

?j User Interface

i

0-l^p Permission Sets

2 DNS

 

 

^ FullTrust g

?| Printing jvj

 

 

SkipVerification

Event Log

 

 

m Execution

[^ Socket Access

:

 

|j Nothing

iv) Web Access

 

^ Locallntranet

 

1 ;

 

g Internet

[2J Performance Counter

;

^

^3 Directory Services

;

 

Qjp Policy

^ Message Queue

1

ffi-6

^ Service Controller

-•• ft Applications

?j OLE DB

 

 

 

ID SQL Client

 

 

 

 

In default configuration, the FullTrust permission set and the Everything permission set match. The difference between these is that the FullTrust permission set will implicitly contain additional custom permissions, if defined in security policies configuration, while this is not true for the Everything permission set, which takes into account, in a default configuration, only built-in permission. In other words, FullTrust completely bypasses security CAS checks, and this behavior cannot be modified.

The .NET Framework SP1 has tightened permissions granted to the Internet Code Group. Previously, permissions granted to the Internet zone were: FileDialog. IsolatedStorage. Security (code execution), Userlnterface and Printing.

The permission set granted to the Internet zone has been changed to Nothing in SP1. This implies that without security adjustments, no .NET code downloaded from the Internet will run. It's not quite clear if this is a permanent decision or a temporary one, required, perhaps, to protect the CLR from undocumented security flaws.

CAS enables us to add other permissions sets, possibly by cloning an existing one, and this is what we would typically do when customizing CAS policies configuration.

Policy Structure

Each CAS policy is structured as a single-root hierarchical tree of code groups. When installing the .NET Framework runtime, CAS policies are set up with a reasonable default configuration. Enterprise and User policy configuration is basically switched off in the sense that they do not pose any restrictic on code execution. Both Enterprise and User policy have a single Code group whose membership condition is All_Code (this means that no matter what evidence we have, we will be given membersh condition) and the granted permission set is FullTrust.

The only active policy is defined at Machine level. Basically, this policy poses no restriction on assemblies loaded from the local computer, while forcing increasing restrictions for assemblies loade' from the Intranet Zone, Trusted Zone, and the Internet Zone:

326

Code Access Security

p-Qj) Runtime Security Policy ES

*^ Enterprise H B Machine

IB -»l CcdeGroups

i- ' ^ Q E B B I

My_Computer_Zone Microsoft_5trong_PJame ECMA_5trong_Name LocalIntranet_Zone <^ Intranet_Same_Site_Access <^ Intranet_Same_Directory_Access Internet_Zone Restricted_Zone Trusted_Zone -^ Tfusted_5ame_Site_Access

Policy Structure Object Model

We will here briefly look at the policy structure object model. Basically, this enables us to: G

Navigate along the code group structure, and modify it G

Get and Set a code

group's membership conditions and permission set G

Resolve membership

conditions against an assembly evidence, and so on

 

It's worth noting that the same object model is used both for policy configuration and during the permission granting process.

The object model entry point is the System, security. SecurityManager class, which exposes only static methods. The SecurityManager class enables us to import an XML policy configuration file (LoadPolicyLevelFromFile) or export it (SavePolicyLevel).

The same actions can be performed using the Open and New options respectively from the pop-up menu that shows up by right-clicking the Runtime Security Policy node in the Microsoft .NET Framework Configuration interface, as illustrated in the previous screenshot.

Calling the SecurityManager PolicyHierarchy method, we return an enumerator that can be used to access the three PolicyLevel objects (four, if an application defined policy is set).

The RootCodeGroup property of a PolicyLevel object provides access to the root code group object of the policy. We can get from it an enumerator to access its child code groups using the Children property, and so on:

lEnumerator policyenumerator = SecurityManager.PolicyHierarchy(); while (policyenumerator.MoveNext())

PolicyLevel aPolicyLevel = (PolicyLevel)policyenumerator.Current; CodeGroup rootcodegroup = aPolicyLevel.RootCodeGroup; Debug.Wri teLine(rootcodegroup.Name)

As you can see, this object model is quite straightforward. Further code samples will be provided along the way when describing the policy permission granting process, adding a custom code group, and so on.

Policy Evaluation at work

Since a CAS policy is no>t a flat iLst of code groups, you may have guessed already that the process of granting permissions is mot so str aightforward.

The process we are goinjg to examine right now is executed against the three polices in the following order: Enterprise, Mach ine, and User (plus the application domain policy, if defined).

As already mentioned, the resulting permissions granted to the assembly will be obtained, intersecting the permission granted by each policy.

Permission Granting Process Step by Step

In this section, the proce-ss is described, with the help of some small code examples, which use the policy object model that we previously mentioned.

The process starts immediately after the CLR loads the assembly into the application domain:

//Loading an assembly

Assembly SampleAssembly = Assembly .LoadFrom

( "http: //localhost/cas/ConsoleApplicationl.exe") ;

At this point, the policy evaluator calls the Resolve method of each policy and returns a

Pol icyStatement object. Basically, a PolicyStatement object represents a list of permissions:

//policy evaluatoi:

iterates

over policies

 

PolicyStatement glbPolS

= new PolicyStatement (new

 

PermissionSet (PermissionState .None) )

 

 

PolicyStatement []

polPolS

= new

PolicyStatement [3] ; lEnumerator

policyenumerator =

SecurityManager . PolicyHierarchy ( )

; int i=0;

while

(policyenumerator .MoveNext () ) {

 

PolicyLevel aPolicyLevel

=

( PolicyLevel Jpolicyenumerator .Current;

polPolS [i] =

PolicyLevel. Resolve (SampleAssembly . Evidence) ;

i

+=1;

 

 

 

 

 

What the Resolve method does is to pick up the root code group object of the policy, and call its Resolve method:

//PolicyResolve

PolicyStatement Resolve (Evidence assemevidence)

{

return this .RootCodeGroup. Resolve (assemevidence) ,-}

The Resolve method compares the membership condition against the assembly evidence calling the Check method. If the Check method returns true, the permissions set associated with the code group is added to the granted permissions of the assembly (more precisely, a union is made with those already granted):

328

Code Access Security

// Code Group Resolve

PolicyStatement Resolve (Evidence AssemblyEvidence)

{

PermissionSet

permset

=

 

 

 

new PermissionSet (PermissionState. None

) ; if

 

(this .MembershipCondition. Check

(AssemblyEvidence

)) {

PolicyStatement CGPolicyStatement =

 

 

this .PolicyStatement

; if

(CGPolicyStatement

!= null)

permset =

CGPolicyStatement . PermissionSet .Union (permset) ;

In a default configuration, the membership condition test is always positive on the root node, since the membership condition is All_Code. The Resolve method of the Root object then proceeds, extracting its child code groups and calling the Resolve method again on them. This recursive algorithm on a tree branch stops when a node fails to pass the check test. In other words, if and only if the check method succeeded on a node, the code group proceeds checking its child nodes; if it's not the case, its child nodes are ignored.

As a result of this process, the set of granted permissions for a policy is the union of the permissions of the code groups to which the assembly has been granted membership.

// continue Resolve method

lEnumerator ChildCodeGroups = this .Children. GetEnumerator ( ) ; while (ChildCodeGroups .MoveNext () )

{

PolicyStatement childPolStatement =

(CodeGroup) ChildCodeGroups .Current .Resolve (AssemblyEvidence) ; if (childPolStatement . PermissionSet != null)

permset=permset.Union(childPolStatement.PermissionSet);} } return new PolicyStatement (thispermissionset) ;

As indicated before, the resulting three permission sets are then intersected to construct the set of permissions granted to the assembly.

'

End iteration

over

 

policies glbPolS. PermissionSet =

 

 

polPolS[0] . PermissionSet . Intersect (polPolS [1] .PermissionSet

) ;

glbPolS. PermissionSet

=

 

glbPolS. PermissionSet . Intersect (polPolS [2] .PermissionSet) ;

In the following diagram, a graphic representation of the process is shown. The large arrow indicates the security policy evaluation order. Black blocks represent code groups where an assembly has passed the membership condition check; white ones are code groups where the check has failed; and gray ones are skipped code groups (since the assembly has not matched the membership condition of their parent code group).

329

Permission set granting evaluation order

Enterprise

Machine

User

Application Domain

Modify the Default Policy Granting Process

We can modify the process described above, applying a couple of special attributes to one or more code groups of a policy structure. To be more specific, such attributes are applicable to the associated code group's PolicyStatement object (we introduced this object in the previous section).

Both attributes are defined via different values of the PolicyStatementAttribute enum.

[Flags]

enum PolicyStatementAttribute

{

Nothing,

Exclusive,

LevelFinal ,

All = Exclusive | LevelFinal

When, during the permission-granting process, an assembly evidence matches the membership condition of a code group set to Exclusive, the policy structure traversal for this specific policy is stopped and the assembly gets only the permissions defined for this code group. Even if the assembly evidence matches other code group membership conditions in the policy structure they will be ignored and their permissions not assigned.

We can set to Exclusive only one code group within a specific policy structure. If we fail to do so, the CAS runtime will be corrupted: we won't be able to reopen the policy editor snap-in, and any attempt to run a .NET application will fail with a security exception. At that point, the only way to restore a correct configuration is to edit the XML policy file manually.

330

Code Access Security

We can set the code group policy statement attribute to Exclusive using the security manager object model in the following way:

codgroup.PolicyStatement.Attributes = PolicyStatementAttribute.Exclusive;

A match with an Exclusive code group doesn't imply that other lower-level polices are skipped. This is exactly what the LevelFinal attribute is for.

When an assembly has membership to a code group with the LevelFinal attribute set, it is assigned the permissions granted by the policy and lower-level polices are skipped (that's why the policy evaluation order is relevant). The LevelFinal attribute alone does not imply Exclusive, thus we can apply the final attribute to more then one code group. Note, however that application-defined policies are always evaluated, regardless of the LevelFinal attribute.

The exclusive and LevelFinal attributes can be set easily with the Microsoft .NET Framework Configuration snap-in, as shown here:

Customizing Security Policies

While the default policy configuration is acceptable in most cases, we may need to modify it for various reasons. The only built-in code group whose permissions can be changed is the Everything code group. Since it's not advisable to modify this, because this may impact on the whole system, we often end up adding custom code groups when we want to modify the permissions granted to specific assemblies.

For instance, one common requirement is to extend the permissions of an assembly downloaded from the Internet (which have become nothing by default after SP1) if it has a specific strong name or is downloaded from a specific URL.

To do so, we just have to open the .NET Framework configuration snap-in, go to the machine policy, select the AILCode code group, right-click, and choose New. A wizard shows up. In the first page, we provide a name and a description for the code group. In the second, we choose the evidence we are interested in (the dropdown list is populated with all built-in evidences) and provide the required parameters. The lowest part of the form is dynamically generated according to the evidence type selected, since different evidence types require different types of information:

! Create Code Group

Choose a condition type

The membership condition determines whether or not an assembly meets specific requirements lo get the permissions associated with a code group.

Choose the condition type for this code group;

URL

The URL membership condition is true for all assemblies that originate from the URl specified below, Assemblies that rneef: this membership condition will be granted the permissions associated with this code group,

URL: .. _ _ _ ....................................................................................

_

jhttp://www.sabbasofLconVassen"iblies/|

The URL must include the protocol such as 'ftp://1 or 'http;//'. An asterisk (*) can be used as a wildcard character at the end of the URL,

Examples;

http;//fA'ww, microsoft, com/specif i<:_assernbry.dlf f tp ;//f tp, microsoft, com/pub/*

<Back

Cancel

Now we can assign to the code group an existing permission set ,or create a new one on the fly:

332

Code Access Security

Create Code Group

Assign a Permission Set to the Code Group

Code groups must have an associated permission set. Use an existing one or create a new one.

Would you lihe to use an existing permission set already defined in this policy level or create a new permission set?

(* Use exeitirtg permission set;

C Create a new permission set

<8aek

Caned

That's it!

We can also implement this by using caspol. exe, using a command line of the following form:

>caspol -addgroup All_Code -url "http://www.sabbasoft.com/assemblies/" Everything -name "MyCodeGroup"

Using Custom Evidences and Permissions

To use custom evidence and permission classes when defining a code group, we must first follow the steps shown below to make security policies aware of the custom class:

G Strongly sign the assembly where the custom class is defined (use the sn command-line tool to generate a private-public key pair).

Q Add the assembly to the GAC (gacutil -i <assemblyname>).

Q Add the assembly to the policy assemblies list of the specific policy where we want to use the custom permission or the custom evidence (using the .NET Framework configuration snap-in or caspol. exe).

When using the .NET Framework configuration snap-in or caspol. exe to define code groups with custom evidence or permissions classes, we must provide evidence and/or permission information via an XML file with a specific syntax. Basically, this XML file specifies the class name implementing the custom object, and an additional number of parameters specifying the configuration of the permission or the evidence (for instance, myZone membership condition = 'mylnternetZone'). The number and name of such parameters depends on the specific class and must reflect the XML structure of the SecurityElement object passed in and out from the FromXml and ToXml method implementations.

333

The following XML defines a custom evidence:

<IMembershipCondition

class="CustomEvidenceAssembly .MyCustomEvidenceMembershipCondition, CustomEvidenceAssembly, Version=l . 0 . 3300 . 0, Culture=neutral, PublicKeyToken=6e8a3cc3d5b9f871"

version=" l" customvalue="avalue"

The following defines a custom permission:

< I Permission class="MyCustomPermission.MyCustomPermissionClass, MyCustomPermission, Version=l . 0 . 0 . 0, Culture=neutral, PublicKeyToken=dfea214a880e7202"

version=" 1" Unrestricted="True" />

Note that the Class attribute provides all the required information to uniquely identify a strong-named assembly, the Version attribute is related to the version of the .NET framework we are working with, and one or more specific attributes specify the permission or evidence value.

Code Access Security and ASP.NET Applications

As we've seen in previous chapters, ASP.NET applications can address identity-related security issues that differ greatly from standard Windows applications. This is not the case when it comes to CAS. In the most common scenario, the IIS virtual directory where ASP.NET applications are deployed is mapped to a local computer directory. This implies that, according to CAS, ASP.NET assemblies (ASP.NET pages are compiled into an assembly on the fly on first request) get a Zone=MyComputer evidence value. This means that a FullTrust permission set is granted to ASP.NET assemblies (in the default security policy configuration).

As ASP.NET developers, we may have to deal with CAS access controls in only two scenarios. The first one (which applies to any kind of .NET application) is when, within an ASP.NET page, an assembly is downloaded from a URL (this would include UNC - Uniform Naming Convention - network shares).

The downloaded assembly will be granted a limited set of permissions and the developer (or more likely a system administrator) will have to modify security policy configuration to enable the assembly to run with the required set of permissions.

The second situation where CAS may enter onto the scene is when the IIS virtual directory is mapped to a UNC path. In this case, the ASP.NET assemblies are loaded with intranet permissions set that will not be sufficient even to allow the ASP.NET page to run (in a default security policy configuration). In case we really need such a deployment configuration, the best solution is to adjust the local machine security policy, adding a code group that assigns FullTrust permissions to code whose UPvL eviden< type (or alternatively site evidence type) matches the UNC deployment location.

334

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