Section 12.1. The .NET Security Architecture


12.1. The .NET Security Architecture

.NET component-oriented security is based on an elegant concept: using an administration tool, the system administrator grants assemblies certain permissions to perform operations with external entities such as the filesystem, the Registry, the user interface, and so on. .NET provides the system administrator with multiple ways to identify which assembly gets granted what permission and what evidence the assembly needs to provide in order to establish its identity. At runtime, whenever an assembly tries to perform a privileged operation or access a resource, .NET verifies that the assembly and its calling assemblies have permission to perform that operation. Although the idea is intuitive enough, there are a substantial number of new terms and concepts to understand before configuring .NET security for your own applications. The rest of this section describes the elements of the .NET security architecture. The next sections describe how to administratively configure security and take programmatic control over security.

12.1.1. Permissions

A permission is a grant to perform a specific operation. Permissions have both a type and a scope. A file I/O permission is different from a user-interface permission in type because they control access to different types of resources. Similarly, a reflection permission is different from an unmanaged code access permission because they control the execution of different types of operations. In scope, a permission can be very narrow, wide, or unrestricted. For example, a file I/O permission can allow reading from a particular file, while writing to the same file may be represented by a different file I/O permission (narrow scope). Alternatively, a file I/O permission may grant access to an entire directory (or a drive), or grant unrestricted access to the filesystem. .NET defines 25 types of permissions that govern all operations and resources an application is likely to use (see Table 12-1).

Of particular interest is the Security permission type, which controls both sensitive operations and security configuration. The list of privileged operations includes execution, invocation of unmanaged code, creating and controlling app domains, serialization, thread manipulation, and remoting configuration. The security configuration aspect includes permission to assert granted permissions; skip assembly verification; control security policies, evidences, and principals; and extend the security infrastructure. These facets are described later.

.NET permissions are subject to the underlying Windows or resource security permissions. For example, if the filesystem is NTFS, it can still deny an application access to a file if the identity under which the application is running isn't granted access to that file. Other examples are when accessing user-specific environment variables and when accessing a SQL server that has its own security policy.


Table 12-1. Security permission types

Permission type

Grants permission to

Example

ASP.NET Hosting

Host ASP.NET objects. Defines several levels.

Minimal level permission is required for using the ASP.NET authentication and authorization classes.

Data Protection

Use the ProtectedData class to protect or unprotect data and memory.

Encrypt a memory block using ProtectedData.Protect( ).

Directory Services

Access Active Directory. Allows browsing a path or writing to it.

Browse all content under LDAP://.

Distributed Transactions

Create a new distributed transaction.

Unrestricted use of distributed transactions.

DNS

Domain-name servers. Permission is required to resolve URLs at runtime.

Deny access to or grant unrestricted access to DNS.

Environment Variables

Read or write the value of specific environment variables.

Write the PATH environment variable.

Event Log

Write, browse, or audit an event log on a specified machine. Can also deny access to event log.

Browse the event log on localhost.

File Dialog

Display the common dialogs used to open or save files, or deny permission to display the dialogs.

Display the File Save dialog.

File I/O

Read, write, or append data to a file, or all files in a directory. Grants path-discovery permission as well.

Write to c:\temp\Myfile.txt.

Isolated Storage

Allow or disallow administration; configure isolation policy and disk quotas.

Allow administration of isolated storage by the user of the assembly and allocate a disk quota of at most 10 KB.

Key Container

Create and delete key containers; export and import keys; sign, open, or encrypt containers.

Import an existing key from a container.

Message Queue

Browse, peek, send, or receive messages from a specified message queue. Allow queue administration as well.

Grant unrestricted access to all message queues.

OLE DB

Access specified OLE DB providers. Can specify whether a blank password is permitted for all providers.

Grant access to the Microsoft OLE DB provider for SQL Server.

Performance Counter

Browse or instrument specified performance counters on designated machines.

Instrument the thread performance counter on the current machine.

Printing

Print (either in safe mode, default mode, or all modes).

Allow all printing operations to all accessible printers.

Reflection

Discover member and type information about other assemblies using reflection. Emit code at runtime.

Allow reflection of both type and member information on other assemblies but deny emission of new code at runtime.

Registry

Read, write, or create Registry keys.

Read the values stored under HKEY_LOCAL_MACHINE\SOFTWARE\.

Security

Control various security aspects.

Allow unmanaged code access.

Service Controller

Control or browse services on specified machines.

Control (start and stop) the fax service on the local machine.

Socket Access

Accept connections on or connect to specific ports on specified machines using either TCP or UDP (or both).

Allow connecting and accepting calls on port 8005 using TCP on the local machine.

SQL Client

Access SQL servers using ADO.NET, and specify whether a blank password is permitted.

Allow unrestricted access to all SQL servers available on the intranet.

Store

Create and delete certificate stores, enumerate existing stores, enumerate certificates in a store, add or remove a certificate from a store.

Permission to add a certificate to a store.

User Interface

Interact with the user using all top-level windows and events, safe top-level windows, safe subwindows, or no windows at all. Control access to the clipboard.

Allow displaying all windows but disallow clipboard access.

Web Access

Allow connecting to or accepting requests from specified web hosts.

Allow invoking a particular web service.

Web Browser

Render content in the web browser Windows Forms control. Can be unrestricted or restricted to rendering only simple HTML (that is, without ActiveX, HTML scripts, Java applets, or other potentially unsafe operations).

Allow restricted use of the web browser control.


12.1.2. Permission Sets

Individual permissions are just thatindividual. To function properly, a given assembly often requires a set of permissions of particular scope and type. .NET allows system administrators to use permission sets, or collections of individual permissions. A permission set can contain as many individual permissions as required. Administrators can construct custom permission sets, or they can use pre-existing, well-known permission sets. .NET provides seven predefined permission sets, also known as named permission sets: Nothing, Execution, Internet, LocalIntranet, Everything, FullTrust, and SkipVerification. Table 12-2 presents the individual permissions granted by each named permission set.

Table 12-2. The named permission sets

Permissions

Nothing

Execution

Internet

LocalIntranet

Everything

FullTrust

SkipVerification

ASP.NET Hosting

 

 

 

 

 

Unrestricted

 

Data Protection

 

 

 

 

Unrestricted

Unrestricted

 

Directory Services

 

 

 

 

 

Unrestricted

 

Distributed Transactions

 

 

 

 

 

Unrestricted

 

DNS

 

 

 

Unrestricted

Unrestricted

Unrestricted

 

Environment Variables

 

 

 

Read USERNAME

Unrestricted

Unrestricted

 

Event Log

 

 

 

 

Unrestricted

Unrestricted

 

File Dialog

 

 

File Open

Unrestricted

Unrestricted

Unrestricted

 

File IO

 

 

 

 

Unrestricted

Unrestricted

 

Isolated Storage

 

 

Domain isolation by user with 10 KB disk quota

Assembly isolation by user, unrestricted disk quota

Unrestricted

Unrestricted

 

Key Container

 

 

 

 

Unrestricted

Unrestricted

 

Message Queue

 

 

 

 

 

Unrestricted

 

OLE DB

 

 

 

 

Unrestricted

Unrestricted

 

Performance Counter

 

 

 

 

Unrestricted

Unrestricted

 

Printing

 

 

Safe printing

Default

Unrestricted

Unrestricted

 

Reflection

 

 

 

Emit

Unrestricted

Unrestricted

 

Registry

 

 

 

 

Unrestricted

Unrestricted

 

Security

 

Execution

Execution

Execution and assertion

All, except skip verification

Unrestricted

Skip code-safety verification

Service Controller

 

 

 

 

 

Unrestricted

 

Socket Access

 

 

 

 

Unrestricted

Unrestricted

 

SQL Client

 

 

 

 

Unrestricted

Unrestricted

 

Store

 

 

 

 

Unrestricted

Unrestricted

 

User Interface

 

 

Safe top-level windows, clipboard ownership

Unrestricted

Unrestricted

Unrestricted

 

Web Access

 

 

 

 

Unrestricted

Unrestricted

 

Web Browser

 

 

Restricted

Restricted

Unrestricted

Unrestricted

 


The named permission sets offer a spectrum of trust:


The Nothing permission set

Grants nothing. Code that has only the Nothing permission set can't execute, and .NET will refuse to load it. The Nothing permission set is used when there is a need to prevent assemblies from running, typically because the code origin is known to be untrustworthy and dangerous. For example, the default .NET security policy associates any code coming from the list of untrusted sites (maintained by Internet Explorer) with the Nothing permission set, effectively preventing such code from causing any harm.


The Execution permission set

Allows code to load and run, but doesn't permit interaction with any kind of external resource and doesn't perform any privileged operations. When an assembly is assigned the Execution permission set (but nothing else), the assembly can perform operations such as numerical calculations, but it can't save the results. By default, .NET does not use the Execution permission set.


The Internet permission set

Gives code some ability to execute and display a user interface, so should be used carefully. Generally, you shouldn't trust code coming from the Internet unless the site of origin is explicitly trusted. Note that the default .NET security policy grants the Internet permission set to all code coming from the Internet. Administrators can change that and explicitly assign the Internet permission set to only selected trusted sites.


The LocalIntranet permission set

Code coming from the local intranet is, of course, more trustworthy than code coming from the Internet. As a result, the LocalIntranet permission set grants code wide permissions. .NET's default associates the LocalIntranet permission set with code originating from the local intranet.


The Everything permission set

Grants code most permissions except for directory services, distributed transactions, message queue, service control, ASP.NET hosting, and permission to skip verification. The lack of permission to skip security verification means that the code must be verifiable. Verifiable code is code that can be verified in a formal manner as type-safe. CLR-compliant compilers can emit unverifiable code, such as unsafe code in C#. You can use the Everything permission set to ensure that the managed code invoked has all the permissions required for normal operation and yet it doesn't use techniques such as pointer arithmetic to access restricted memory areas or areas owned by other app domains (more on that at the end of the chapter). By default, .NET doesn't use the Everything permission set.


The FullTrust permission set

Allows unimpeded access to all resources. .NET trusts such code implicitly and allows it to perform all operations. Only the most trustworthy code should be granted this permission, because there are no safeguards. By default, all code executing from the local machine is granted full.


The SkipVerification permission set

Grants a single permissionpermission to skip code-safety verification. You can use the SkipVerification permission set to explicitly allow unverifiable code, without risking it touching any external resources or performing sensitive operations. For example, imagine porting legacy C or C++ code to C#, when the legacy code uses complex pointer arithmetic. In that case, it may be easier to keep that pointer arithmetic in place using unsafe code than to fully rewrite safer C#. It's overkill to grant that code FullTrust permissions; instead, grant it the SkipVerification permission set and any other specific permissions it may require. Granting assemblies only the minimum permissions they require is a good guideline, because it reduces the chances of damage caused by a malicious party luring a benign assembly to do dirty work on its behalf.

: Assemblies and Code Origin

Component-based security obviously has a lot to do with code origin that is, where the code is coming from. Code origin has nothing to do with remote calls, because the remote object executes locally on the remote machine. Code origin is relevant only when loading an assembly from a remote location. You can load a remote assembly in a number of ways. First, you can have the application indicate in its code-binding policy that it requires an assembly from another machine (by specifying the machine name), or perhaps that the assembly is coming from a network-mapped drive. Applications can also programmatically load an assembly at runtime from a remote location using the static method LoadFrom( ) of the Assembly class:

     public static Assembly LoadFrom(string assemblyFile); 

For example:

     Assembly assembly;     assembly = Assembly.LoadFrom("\\SomeMachine\MyAssembly.dll"); 

That said, by far the most common case of loading an assembly from a remote location is using ClickOnce deployment. As you will see later on in this chapter, a few features of the security infrastructure and Visual Studio 2005 are dedicated for the use of ClickOnce applications.


12.1.3. Security Evidence

System administrators grant permissions to assemblies based on the assembly's identity. The question is, what sort of evidence should an assembly present to .NET in order to establish its identity? A security evidence is some form of proof that an assembly can provide to substantiate its identity. Evidences are vital for .NET security, because without them rogue assemblies can pretend to be something they aren't and gain unauthorized access to resources or operations. There are two types of evidences: origin-based and content-based evidences. An origin-based evidence simply examines where the assembly is coming from and is independent of the actual content of the assembly. The standard origin-based evidences are Application Directory, GAC, Site, URL, and Zone. A content-based evidence examines the content of the assembly, looking for a specific match with specified criteria. The standard content-based evidences are Strong Name, Publisher, and Hash. There is no relationship between permission sets and evidences. A single assembly can be granted multiple permission sets and satisfy a different evidence for each permission set, or it can satisfy the same evidence associated with multiple permission sets. .NET also defines a wildcardthe All Code evidence. Here is a description of the available evidences and how to select an appropriate security evidence.

12.1.3.1 The All Code evidence

The All Code evidence is satisfied by all assemblies.

12.1.3.2 The Application Directory evidence

The Application Directory evidence is satisfied by all assemblies coming from the same directory as or a child directory of the running application. Typically, this evidence allows an application to trust code deployed together with it but distrust other code on the same machine or anywhere else.

12.1.3.3 The GAC evidence

The GAC evidence is satisfied by all assemblies originating from the GAC. Because only an administrator can install assemblies in the GAC, the GAC evidence is used to implicitly demand that whoever installed the evaluated assembly was an administrator. Assemblies that satisfy the GAC evidence are somewhat more trustworthy than assemblies installed by non-administrators, but to what degree is a question of judgment.

12.1.3.4 The Site evidence

The Site evidence is satisfied by all assemblies coming from a specified site, such as http://www.somesite.com or ftp://www.somesite.com. The protocol (and port number, if specified) is ignored, and only the top-level domain portion is used. .NET also ignores any subsite specifications, such as the /myfolder in http://www.somesite.com/myfolder, and extracts the domain name only. Sites can also point to a specific machine, as in tcp://somemachine/myfolder.

12.1.3.5 The URL evidence

The URL evidence is satisfied by all assemblies coming from a specified URL. The URL evidence is more specific than the Site evidence, because .NET takes into account protocol, port number, and subfolders. For example, the following are considered different URL evidences but identical Site evidences:

You can use an asterisk at the end of a URL to indicate that the URL evidence applies to all code coming from a sub-URL as well:

http://www.somesite.com/*
12.1.3.6 The Zone evidence

The Zone evidence is satisfied by all assemblies coming from the specified zone. .NET defines five zones:


The My Computer zone

Identifies code coming from the local machine.


The Local Intranet zone

Identifies code coming from machines on the same LAN. The local intranet is any location identified by a universal name convention (UNC), usually in the form of \\<machinename>\<further scope> (e.g., \\Somemachine\SomeSharedFolder). You can also identify a location as part of the Local Intranet zone using a URL, as long as the URL doesn't contain dots (e.g., http://Somemachine\SomeSharedFolder or tcp://Somemachine\SomeSharedFolder). Note that even if you specify your own local machine name (e.g., \\MyMachine or http://localhost), it will be considered part of the Local Intranet zone, not the My Computer zone. Network-mapped drives are also considered part of the Local Intranet zone.


The Internet zone

Identifies code coming from the Internet. The Internet is considered as any location identified by a dotted or numeric IP address, such as http://www.somesite.com or http://66.129.71.238. Note that by default, even if the URL points to a location on the LAN (including the local machine), such as http://127.0.0.1, it's still considered part of the Internet zone.

If you wish to include local intranet sites as part of the local intranet but refer to them using a generic Internet dotted or numeric URL, you need to add those sites explicitly to the intranet site list. To do so, open Internet Explorer and display the Security tab on the Internet Options dialog. Select the Local Intranet icon, and click the Sites button (see Figure 12-1). In the Local Intranet dialog, click Advanced, and add web sites to this zone. You can add even non-intranet web sites to the Local Intranet zone.



The Trusted Sites zone

Identifies code coming from a list of trusted Internet sites. You can add sites to and remove sites from the Trusted Sites list using Internet Explorergo to the Security tab on the Internet Options dialog, select the Trusted Sites icon, and click Sites (see Figure 12-1) to display the Trusted Sites dialog.

Figure 12-1. Managing zones using Internet Explorer



The Untrusted Sites zone

Identifies code coming from a list of untrusted Internet sites. You can add sites to and remove sites from the Untrusted Sites list using Internet Explorer, similarly to adding sites to and removing sites from the Trusted Sites list.

When you add sites to the lists of trusted and untrusted sites using Internet Explorer, the lists are maintained per user, not per machine. There is no easy documented way to add sites to a machine-wide list.


12.1.3.7 The Strong Name evidence

The Strong Name evidence is satisfied by all assemblies whose public keys match a specified key value. The Strong Name evidence is an excellent way to trust all code coming from a particular vendor, assuming the vendor uses the same public key to sign all its assemblies. The Strong Name evidence can optionally contain the assembly names and/or version numbers. As a result, the system administrator can opt to trust only a particular version of a specific assembly coming from a particular vendor identified by a public key. That said, the name and version typically are not supplieddoing so implies that a vendor can be trusted with only that particular assembly or version, which is conceptually inconsistent with the notion of a trustworthy vendor.

12.1.3.8 The Hash evidence

The Hash evidence grants the permission set associated with it to the single assembly whose computational hash matches a specified hash. The assembly in question need not have a strong name. As a result, the Hash evidence is useful only for uniquely identifying an assembly with a friendly name and granting permissions only to that trusted assembly. The Hash evidence is the most stringent form of evidence, but it is also the most maintenance-intensiveyou need to update it on every revision of the assembly. The Hash evidence can be used to detect changes to an assembly, even if the new assembly has the same strong name and version number. System administrators can configure which cryptographic hashing algorithm to use: either SHA1 (the default) or MD5.

12.1.3.9 The Publisher evidence

The Publisher evidence is satisfied by all assemblies that are digitally signed with a specified certificate, such as AuthentiCode. To digitally sign an assembly with a certificate, first build it, and then use the SignTool.exe command-line utility, specifying the assembly to sign and the file containing the digital certificate. SignTool.exe can optionally launch a wizard to guide you through the signing process.

12.1.3.10 Selecting a security evidence

Choosing a security level to apply always involves a trade-off between risks and usability. In general, you should prefer content- to origin-based evidence, because content-based evidence is more accurate. For example, the Strong Name evidence safely and consistently identifies an assembly. With origin-based evidence such as the Site evidence, the same assembly may be trusted if it comes from one site but not trusted if it comes from a different site. In addition, origin-based evidence is more susceptible to subversion than content-based evidence. It's next to impossible to fake a strong name, but it's possible to fool your machine into thinking that a certain IP address maps to a trusted site by subverting the DNS server. Another breach of origin-based evidence is compromising the proxy server on the local network so that instead of returning an assembly from a trusted site, it returns a different assembly but makes it look like it came from a trusted site. You should do a careful threat analysis, and trust origin-based evidences only as far as the DNS and other network facilities can be trusted. Origin-based evidences let you interact with much wider sets of assemblies than content-based evidences, which require individual configuration. Origin-based evidences also let you apply a generic security blanket, without having intimate knowledge of the assemblies on the client machine; content-based evidences, on the other hand, require you to be intimately aware of the making of the assemblies. Consequently, origin-based evidences are often used by framework developers (such as Microsoft), while application developers favor content-based evidences.

12.1.4. Code Groups and Security Policies

.NET uses code groups to classify assemblies when it decides on the security permissions granted for each assembly. A code group is a binding of a single permission set with a particular evidence (see Figure 12-2).

Figure 12-2. A code group is a binding of a single permission set and a single evidence


To be granted the permissions in the permission set associated with the code group, an assembly must first satisfy the evidence of that code group. However, a meaningful security policy needs to be much more granular than what a single code group with a single evidence and permission set can express. A .NET security policy is a collection of code groups. Code groups in a policy are independent of one another in every respect. They can all use the same evidence, different evidences, or a mix. Similarly, different code groups can use different or identical permission sets. The permissions granted by a policy to a given assembly is the union of all the individual permissions granted by the evaluated code groups in that policy whose evidence the assembly satisfies. For example, consider the security policy in Figure 12-3. In this figure, the assembly satisfies the evidences of code groups A, B, and C, but not the evidences required by code groups D and E. As a result, the assembly will be granted only the union of the permissions granted by code groups A, B, and C.

Figure 12-3. A security policy


12.1.4.1 Combining policies

.NET allows administrators to provide multiple security policies. The benefit of having multiple security policies is that it enables policies to have different scopes. Some policies can be restrictive and should be applied only in specific cases, such as with individual users or machines with limited privileges. Some policies can be more permissive and apply to all machines and users in an organization. Therefore, it's quite possible that an assembly is granted some permissions by one policy but is denied the same permissions by another policy. Because all the policies must concur on the allowed permissions, the actual permissions granted to an assembly are the intersection of all the permissions granted by all the security policies (see Figure 12-4).

Figure 12-4. An assembly is allowed the intersection of permissions granted by the various polices


12.1.4.2 Policy levels

In actuality, there are only four types (or levels) of security policies, and .NET is aware of these four levels. Although technically administrators can configure these policy levels in any way, the convention is to use them according to their intent. The Enterprise policy should define a policy that affects all machines in the enterprise. Each machine should have a Machine policy defining a policy specific to that machine, and the User policy should define a policy for each individual user. The system administrator configures these three policy levels. The last policy level is the Application Domain policy, which applies only to code running in a specific application domain. You can only configure the Application Domain policy programmatically, by calling the SetAppDomainPolicy( ) method of the AppDomain class. Customizing the Application Domain policy is primarily for advanced casesfor example, for creating an app domain with deliberately low permissions so that you can load untrusted code into that domain. The default Application Domain policy grants all code full trust. Tool vendors can also take advantage of the App Domain policy. For example, Visual Studio 2005 supports partial-trust debugging, as described later in this chapter. Partial-trust debugging relies on installing a custom App Domain security policy. (App Domain security policies are beyond the scope of this chapter. For additional information, see the MSDN Library.)

System administrators typically take advantage of the hierarchical nature of the policy levels, placing policies that are more restrictive downstream and the more liberal policies upstream. This allows overall flexibility with granular security policies, tight in some places and looser in others. For example, the Enterprise policy is likely to contain only the known, must-be-blocked web sites or vendors. Other than that, the Enterprise policy can be very liberal, permitting all other operations and zones. Individual machines can be restricted if necessary, via the Machine policy. For instance, a development machine can have more permissions than a public machine in a reception area. Similarly, some users (such as system administrators) can have liberal, if not unrestricted, User policies, while non-technical staff can have very restricted User policies, even if they all share the same machine.

12.1.5. How It All Works Together

When .NET loads an assembly, it computes the permissions that assembly is granted: for each security policy, .NET aggregates the permissions from the evaluated code groups satisfied in that policy, and then .NET intersects the policies to find the combined overall collection of permissions the assembly is granted. That set of permissions is calculated only once (per app domain), and it persists in memory for as long as the assembly remains loaded. Whenever an assembly invokes calls on one of the .NET Framework classes (or any other class, including your own, as explained later), that class may demand from .NET that the assembly calling it have the required security permissions to access it. For example, the file I/O classes demand appropriate file I/O permissions, and Windows Forms applications demand user interface permissions. If the assembly doesn't have the appropriate security permissions, a security exception is thrown. However, it isn't sufficient that the assembly that called the demanding class has the requested permissionsif .NET were to check for permissions only on the assembly immediately up the call chain, that could constitute a security breach. Imagine a malicious assembly that doesn't have the required permissions to access a class such as FileStream. That assembly could work around the lack of permissions by calling instead a benign assembly that has the permissions to do its dirty work for it. Therefore, whenever a class demands security permission checks, .NET traverses the entire call stack, making sure that every assembly up the call chain has the required permissions. This is known as the security permission stack walk. When the first assembly without permissions is found during the stack walk, .NET aborts the stack walk and throws an exception at the point where the original security demand took place.

If an exception is raised because of lack of a security permission, you can find which permission is missing by examining the PermissionType property of the SecurityException object. Other useful properties of SecurityException include which method demanded the security permission (the Method property), the assembly that failed the call (the FailedAssemblyInfo property), and the origin of that assembly (the Zone and Url properties).




Programming. NET Components
Programming .NET Components, 2nd Edition
ISBN: 0596102070
EAN: 2147483647
Year: 2003
Pages: 145
Authors: Juval Lowy

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net