Uncategorized

Using Declarative and Imperative Security to Protect Methods

CAS can be used either declaratively, in which case the compiler performs security checks prior to running code, or imperatively, in which case the code itself performs security checks and controls what happens if the check fails. Aparte de utilizar las declaraciones CAS para proteger assemblies totalmente o de manera completa, you can also use CAS to declaratively protect individual methods within an assembly or use CAS to imperatively protect sections of code within a method. In this lesson you’ll learn how and why to use both imperative and declarative CAS demands to protect code within an assembly.

Types of Method Permission Requests

Although there are only three types of CAS assembly declarations (RequestOptional, RequestMinimum, and RequestRefuse), you have six options available for imperative and declarative permissions within a method. The following list describes each option:

  • Assert: Instructs the runtime to ignore the fact that callers might not have the specified permission. Assemblies must have the Assert Any Permission That Has Been Granted security permission setting.
  • Demand: Instructs the runtime to throw an exception if the caller and all callers higher in the stack lack the specified permission.
  • Deny: Causes the runtime to reduce the method’s access by removing the specified permission.
  • InheritanceDemand: Instructs the runtime to throw an exception if the assembly inheriting from the class lacks the specified permission.
  • LinkDemand: Causes the runtime to throw an exception if the immediate caller, but not callers higher in the stack, lack the specified permission.
  • PermitOnly: Instructs the runtime to reduce the method’s access by removing all permissions except for the specified permission.

To understand each of these methods, consider a group of four guests who want to enter an exclusive party. The host (your method) has hired a bouncer (the .NET Framework runtime) to make sure that only guests (calling assemblies) with an invitation (a CAS permission) are allowed to enter the party (call your method).

If the host calls InvitedGuests.LinkDemand, the bouncer will check the invitation of the first guest and then allow everyone else into the party. This is quick, but it might let people sneak into the party. If the host calls InvitedGuests.Demand, the bouncer will check the invitation of every guest individually. This process takes more time, but it ensures that nobody can sneak in.

To speed up the process of checking invitations, the first invited guests might use InvitedGuests.Assert to assure the bouncer that all the guests in the group were invited—assuming that the bouncer trusted the first guest enough. This procedure would also allow the first guest to bring guests who lacked invitations, which might be a good thing if the host wanted to have a lot of people at the party but didn’t want to hand out too many invitations (that might fall into the wrong hands).

However, it might be a bad thing if a thief discovered that he could sneak into the party. If the host wanted to ensure that people danced at the party (and never did anything else), the host would use Dancing.PermitOnly to instruct the bouncer to make sure that guests stayed on the dance floor. If the host wanted people to do anything but dance, the host would use Dancing.Deny to prevent anyone from dancing.

Guidelines for Using Method Permission Requests

Como desarrollador, usted tiene muchas opciones para la aplicación de CAS en sus aplicaciones. Elegir cómo implementar CAS para una situación particular puede ser complicado, sin embargo. Follow these guidelines to choose which CAS methods to use:

  • Use SecurityAction.PermitOnly declarations to limit the permissions available to each method. List every permission the method requires.
  • Use SecurityAction.Deny declarations to further refine the permissions available to each method
  • Use CodeAccessPermission.PermitOnly to imperatively reduce permissions when a section of a method requires fewer permissions than the rest of the method. This is particularly important when calling objects created by third parties. Use CodeAccessPermission.RevertPermitOnly to restore the permission.
  • Use CodeAccessPermission.Assert when you want to allow partially trusted code to call a method that requires permissions the caller might lack. Review your code carefully for potential security vulnerabilities; Assert can be abused by an attacker to gain elevated privileges. After you perform the functions requiring elevated privileges, use CodeAccessPermission.RevertAssert to restore the original permissions.
  • Use CodeAccessPermission.Demand only when your assembly implements customized functionality that does not rely on functionality built into the .NET Framework, such as calls to unmanaged code.

NOTE: Security risks of declarative demands

There’s a school of thought that says declarative security demands are less secure than imperative security demands because declarative demands can reveal to attackers too much about the code’s design and potential vulnerabilities. It’s true that declarative security demands are a bit easier for an attacker to analyze, but a sophisticated attacker could also examine imperative demands by using a tool that analyzes your assembly’s Intermediate Language (IL) code. It’s a bit harder for the attacker to analyze IL than to analyze the declarative security demands, but it wouldn’t make much of a difference to an attacker who was sophisticated enough to make use of security demand information. Also, declarative demands are faster than imperative demands.

Techniques for Demanding Permissions

Two of the SecurityAction enumerations and two of the CodeAccessPermission methods cause the runtime to throw an exception if the specified CAS permission is missing: Demand and LinkDemand. The difference between the two enumerations and methods is that Demand causes the permission check to verify the access of all callers, whereas LinkDemand verifies only the immediate caller.

To understand the difference, compare the Demand process demonstrated in Figure 11-9 with the LinkDemand process demonstrated in Figure 11-10. As you can see, Demand will detect whether any caller lacks the demanded permission or permission set, and will throw an exception. This is more secure than using LinkDemand, which checks only the immediate caller. However, as with almost every security mechanism, there is a trade-off. Demand requires the runtime to do more checks, which requires more processing time and slows performance. Using LinkDemand improves performance but increases the risk of an attacker successfully bypassing the check.

Demanding Permission 1.

IMPORTANT Demand and LinkDemand check the caller

Demand and LinkDemand do not check the current method’s permissions—they check the caller. However, if your assembly calls a private method that uses Demand or LinkDemand, the runtime will check your assembly’s permission because in this case your assembly is the caller.

LinkDemand Permission

Creating CAS method declarations is very similar to creating CAS assembly declarations. However, you must create the declarations as attributes to the method instead of to the assembly and you must use different SecurityAction enumerations. To create a declarative request, use one of the classes discussed in Lesson 2 of this chapter with the SecurityAction.Demand or SecurityAction.LinkDemand enumerations. The following sample shows two methods that use FileIOPermissionAttribute (in System.Security .Permissions) and WebPermissionAttribute (in System.Net) classes to declaratively verify that callers of particular methods have access to specific files and the www.microsoft.com Web site.

[FileIOPermission(SecurityAction.Demand, Write = @"C:\Program Files\")]
public static void createProgramFolder()
{
// Method logic
}

[WebPermission(SecurityAction.Demand, ConnectPattern = @"http://www\.microsoft\.com/.*")]
public static void requestWebPage()
{
// Method logic
}

If you write classes from which other developers will derive, you can restrict which assemblies can inherit from your classes using the SecurityAction.InheritanceDemand enumeration. For example, only assemblies signed with the C:\Certificates\MyCertificate.cer certificate could inherit from the following class:

[PublisherIdentityPermission(SecurityAction.InheritanceDemand, CertFile = @"C:\Certificates\MyCertificate.cer")]
public class ProtectedInheritance
{
// Class logic
}

You can use the same declarative syntax to protect individual class members from being overridden by a derived class. This approach is necessary only when you want to provide levels of protection for individual members that are higher than those for the base class.

How to Imperatively Demand CAS Permissions

For each of the SecurityAction enumerations used to specify CAS declarations, there is a CodeAccessPermission method with the same name and function used for imperative permissions. You will use the SecurityAction enumerations for declarative security and the CodeAccessPermission methods for imperative security. The following sample performs the same checks as the sample code that used declarative CAS demands, but it performs the check imperatively:

public static void createProgramFolder()
{
       try
       {

              FileIOPermission filePermissions =new FileIOPermission(FileIOPermissionAccess.Write, @"C:\Program Files\");
              filePermissions.Demand();
             // Method logic
        }
        catch
        {
             // Error-handling logic
        }
}

public static void requestWebPage()

       try
       {
              Regex connectPattern = new Regex(@"
http://www\.microsoft\.com/.*");
              WebPermission webPermissions = new WebPermission(NetworkAccess.Connect, connectPattern);
              webPermissions.Demand();
             // Method logic
       }
       catch
       {
              // Error-handling logic
       }
}

Recuerda, la ventaja de utilizar las exigencias imperativas es que se puede capturar la excepción de seguridad dentro de su método y tratarla correctamente. Si desea generar una excepción de vuelta al autor de la llamada, utilice una demanda declarativa.

How to Analyze Granted Permissions

If you need to determine whether your assembly has a particular CAS permission, don’t use Demand. Demand is designed to check an assembly’s caller for permission, not the assembly itself. Instead, use the System.Security.SecurityManager.IsGranted method, as demonstrated by the following code sample:

        FileIOPermission filePermissions = new FileIOPermission(FileIOPermissionAccess.Read, @"C:\Windows\");

        if ( SecurityManager.IsGranted(filePermissions) == true )
            // Assembly can read the C:\Windows directory
        else
            // Assembly cannot read the C:\Windows directory

BEST PRACTICES: Avoid redundant demands

Most classes in the .NET Framework use demands to ensure that callers have the permissions required to use them, so also calling Demand is redundant. For example, if you’re reading a line from a text file using a StreamWriter object, the object itself will demand FileIOPermission. Generally, use demands to protect custom resources that require custom permissions.

Techniques for Limiting Permissions

Always use CAS assembly declarations to restrict the CAS permissions granted to your assembly so that your assembly has only the bare minimum required for all functionality. You can control permissions on a more granular level by restricting permissions for individual methods using method declarations or by restricting permissions within methods using imperative statements.

Two of the SecurityAction enumerations and permission methods cause the runtime to reduce CAS permissions: Deny and PermitOnly. The difference between the two enumerations is that Deny removes a single permission or permission set, whereas PermitOnly removes all permissions except the requested permission or permission set. Recall from Lesson 2 that Deny performs a similar function to RequestRefuse, whereas PermitOnly is similar to RequestOptional.

How to Declaratively Limit Method Permissions
The following two declarations demonstrate how to prevent a method from accessing the C:\Windows\ directory and how to limit outgoing Web requests to only
www.microsoft.com:

[FileIOPermission(SecurityAction.Deny, ViewAndModify = @"C:\Windows\")]
[WebPermission(SecurityAction.PermitOnly, ConnectPattern = @"
http://www\.microsoft\.com/.*")]

NOTE: Limitations of declarative security

Declarative security criteria must be static. If you need to dynamically generate file paths, Web addresses, or any other aspects of the security criteria, you must enforce the security limitations imperatively.

How to Imperatively Limit Permissions

The following sample forces the same limitations as the sample code that used declarative CAS demands, but it limits the permissions imperatively:

// Deny access to the Windows directory
FileIOPermission filePermissions = new FileIOPermission(FileIOPermissionAccess.AllAccess, @"C:\Windows\");
filePermissions.Deny();
// Method logic
// Permit only Web access, and limit it to
www.microsoft.com
Regex connectPattern = new Regex(@"
http://www\.microsoft\.com/.*");
WebPermission webPermissions = new WebPermission(NetworkAccess.Connect, connectPattern);
webPermissions.PermitOnly();
// Method logic

If part of your code needs to use a permission that you previously blocked with Deny or PermitOnly, use the System.Security.CodeAccessPermission.RevertDeny or System.Security.CodeAccessPermission.RevertPermitOnly static methods to reenable the permission.

Best Practice for Handling Errors

Use PermitOnly to limit permissions during error-handling routines. Attackers often initiate an error condition in an application and then abuse that error condition to perform tasks that would not be possible under normal circumstances.

Using PermitOnly to limit CAS permissions to the bare minimum required to log the event and report an error to the user significantly reduces the risk that your error-handling routine can be abused. If your application will continue running after the error, be sure to revert to your original permissions—otherwise, normal application functionality will not be available.

For example, the following code catches an exception, restricts CAS permissions to those required to add events, and then reverts to the previous permission set:

try
{
        // Assembly logic
}
catch
{
          EventLogPermission errorPerms = new EventLogPermission(PermissionState.Unrestricted);
          errorPerms.PermitOnly();
          // Log event
          CodeAccessPermission.RevertPermitOnly();
}

Restricting permissions to those required for a specific block of code is an excellent example of following the principle of least privilege. Although it’s particularly important during error-catching routines, you can use this technique to limit the permissions of any block of code.

How to Relax Permissions and Potentially Improve Performance

Using CAS demands improves the security of an assembly but can decrease performance. In particular, calling a permission’s Demand method is costly because it forces the runtime to systematically check the permission of every caller. LinkDemand, discussed earlier, is one way to improve upon the performance of the Demand method, but it sacrifices some level of security. Another technique is the Assert method, which causes the runtime to bypass any security checks.

IMPORTANT: Compared with assert in C++
CodeAccessPermission.Assert is nothing like the assert function in C or C++.

Permission objects include the Assert method to enable a method to vouch for all callers. Figure 11-11 shows how a call to Assert stops the runtime from checking the CAS permissions of assemblies higher in the stack. This has two effects: improving performance by reducing the number of permission checks and allowing underprivileged code to call methods with higher CAS permission requirements.

Assert blocks demand checks

For example, if you create a RegistryPermission object and call the Assert method, your assembly must be granted RegistryPermission, but any code calling your assembly does not require the permission. If you call another method that uses Demand to require RegistryPermission, Demand will succeed whether or not your caller has been granted RegistryPermission.

You can use Assert either declaratively or imperatively, and the syntax is identical to other types of CAS declarations. The following example asserts permissions declaratively:

[FileIOPermission(SecurityAction.Assert, ViewAndModify = @"C:\Windows\")]
[WebPermission(SecurityAction.Assert, ConnectPattern = @"
http://www\.microsoft\.com/.*")]

Although the following example asserts permissions imperatively:

// Block all CAS permission checks for file access to the Windows directory
FileIOPermission filePermissions = new FileIOPermission(FileIOPermissionAccess.AllAccess, @"C:\Windows\");
filePermissions.Assert();
// Method logic
// Block all CAS permission checks for Web access to
www.microsoft.com
Regex connectPattern = new Regex(@"
http://www\.microsoft\.com/.*");
WebPermission webPermissions = new WebPermission(NetworkAccess.Connect, connectPattern);
webPermissions.Assert();
// Method logic

To successfully use Assert, the assembly must have the SecurityPermissionFlag.Assertion privilege as well as the privilege being asserted. In the .NET Framework Configuration tool, SecurityPermissionFlag.Assertion is represented by the Assert Any Permission That Has Been Granted item in the Security permission properties dialog box. The FullTrust, LocalIntranet, and Everything permission sets have this permission.

Using Assert allows an assembly to vouch for the security of lesser-privileged assemblies. This is an excellent way to grant additional functionality to assemblies that would normally lack CAS permissions. For example, you can use an Assert to allow an assembly in the Internet zone to save a file to the user’s disk. Simply create an assembly with the AllowPartiallyTrustedCallersAttribute. Then create a public method that writes the file, create a FileIOPermission object, and call the Assert method before writing the file. The assembly in the Internet zone can save a file to a user’s disk without requiring the administrators to grant file permissions to the Internet zone.

To decrease the opportunity for an attacker to abuse asserted permissions, use the CodeAccessPermission.RevertAssert static method. As the name suggests, calling this method erases the assertion and returns CAS permission checking to the normal state. Use a try/finally block to ensure that you call RevertAssert after every Assert, even if a failure occurs. The following method demonstrates this and is also an excellent example of how to fail to a more secure permission set:

FileIOPermission filePermissions = new FileIOPermission(FileIOPermissionAccess.Write, @"C:\Inetpub\");
filePermissions.Assert();

try
{
          StreamWriter newFile = new StreamWriter(@"C:\Inetpub\NewFile.txt");
          newFile.WriteLine("Lesser privileged applications can save a file.");
          newFile.Close();
}
finally
{
          CodeAccessPermission.RevertAssert();
}

Assert does have a few limitations. You can use Assert only once in a method. If you have to assert multiple permissions, you need to create a custom permission set (described later in this lesson). Second, Assert doesn’t override the operating system’s role-based security, regardless of the assembly’s CAS permissions. If a user lacks permission to write to the D drive and runs an assembly with full trust that asserts that file permission, the Assert will succeed, but the assembly still can’t write to the D drive. The assembly is still limited by the user’s access restrictions.

How to Call Trusted Code from Partially Trusted Code

To prevent partially trusted code from bypassing security checks, partially trusted code can’t call strong-named assemblies by default. You can control this on an assembly-by-assembly basis, however, by adding the AllowPartiallyTrustedCallersAttribute assembly-level custom attribute:

[assembly:AllowPartiallyTrustedCallers]

If your assembly doesn’t have a strong name, partially trusted code can access your public methods even when you don’t add that attribute.

How to Use Permission Sets

Permission sets are a collection of permissions that can be used imperatively in the same ways you use individual permissions. Use the System.Security.Permissions.PermissionSet class to create a permission set and then use the AddPermission method to specify the permissions that define the permission set. Then you can call any standard permission methods, including Assert, Demand, Deny, and PermitOnly.

For example, the following code creates a permission set consisting of read access to the C:\Windows folder, write access to the C:\Inetpub\ folder, and read access to the HKEY_LOCAL_MACHINE\Software registry key. Then it demands access to all those resources to cause the runtime to throw an exception if any of the specified permissions are not available.

PermissionSet myPerms = new PermissionSet(PermissionState.None);
myPerms.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, @"C:\Windows"));
myPerms.AddPermission(new FileIOPermission(FileIOPermissionAccess.Write, @"C:\Inetpub"));
myPerms.AddPermission(new RegistryPermission(RegistryPermissionAccess.Write,@"HKEY_LOCAL_MACHINE\Software"));
myPerms.Demand();

You can caxll Assert only once in a method, so if you need to assert multiple permissions, you must use a permission set.

Microsoft Patterns & Practices

Uncategorized

Application Security for Developers

Todo el mundo ha escuchado que usted no debe iniciar sesión en el equipo como administrador. La razón no es porque no confía en si mismo , es porque no confía en las aplicaciones que se ejecutan. Cuando ejecuta una aplicación no administrada en Microsoft Windows Server 2003, Microsoft Windows XP y versiones anteriores de Windows, aquel codigo obtiene todos los privilegios que tu cuenta de usuario tiene. Si ejecuta accidentalmente un virus o un caballo de Troya, la aplicación puede hacer cualquier cosa que su cuenta de usuario tiene permisos para hacer. Por lo tanto está obligado a iniciar sesión con privilegios mínimos para restringir los permisos de la aplicación.

Code access security (CAS), a concept that the .NET Framework introduced to Windows, enables you to control the permissions that individual applications have. If a friend sends you a new .NET Framework text editor, you can restrict it to opening a window and prompting you to open and save files—and nothing else. The text edited wouldn’t be able to send e-mails, upload files to a Web site, or create files, even if you are logged on as an Administrator.

CAS enables users to restrict on a very granular level what managed code can do. As a developer, you must understand how to create applications that work even when some permissions are restricted. You can also use CAS to improve your application’s security by restricting which callers can use your code and forcibly limiting your application to a restricted permission set.

Understanding Code Access Security

If you have worked with previous versions of the .NET Framework, you might already be familiar with code access security (CAS) concepts. If you have been a Microsoft Windows developer but haven’t previously used the .NET Framework, using CAS requires you to understand completely novel security concepts. This lesson describes the concept behind CAS and each of the components that the .NET Framework uses to implement CAS.

What Is Code Access Security?

Code access security (CAS) is a security system that allows administrators and developers to control application authorization similar to the way they have always been able to authorize users. With CAS, you can allow one application to read and write to the registry, while restricting access for a different application. You can control authorization for most of the same resources you’ve always been able to restrict using the operating system’s role-based security (RBS), including the following:

■ The file system

■ The registry

■ Printers

■ The event logs

You can also restrict resources that you can’t control using RBS. For example, you can control whether a particular application can send Web requests to the Internet or whether an application can make DNS requests. These are the types of requests that malicious applications are likely to make to abuse a user’s privacy, so it makes sense that CAS allows you to restrict those permissions.

Unfortunately, CAS can be applied only to managed applications that use the .NET Framework runtime. Unmanaged applications run without any CAS restrictions andare limited only by the operating system’s RBS. If CAS is used to restrict the permissions of an assembly, the assembly is considered partially trusted. Partially trusted assemblies must undergo CAS permission checks each time they access a protected resource. Some assemblies are exempt from CAS checks and are considered fully trusted. Fully trusted assemblies, like unmanaged code, can access any system resource that the user has permissions to access.

Elements of Code Access Security

Every security system needs a way to identify users and determine what a user can and can’t do, and CAS is no exception. However, because CAS identifies and assigns permissions to applications rather than to people, it can’t use the user names, passwords, and access control lists (ACLs) that you’re accustomed to.

Instead, CAS identifies assemblies using evidence. Each piece of evidence is a way that an assembly can be identified, such as the location where the assembly is stored, a hash of the assembly’s code, or the assembly’s signature. An assembly’s evidence determines which code group it belongs to. Code groups, in turn, grant an assembly a permission set. The sections that follow describe each of these components in more detail.

What Is Evidence?

Evidence is the information that the runtime gathers about an assembly to determine which code groups the assembly belongs to. Common forms of evidence include the folder or Web site from which the assembly is running and digital signatures.

Evidence: un término equivocado

La identificación podría ser un término mejor que evidencia. Evidencia suena como un conjunto de pistas que se utilizó para realizar un seguimiento de alguien que no quería ser identificado. En CAS, evidencia es utilizadó como pasaporte de una persona, la contraseña y PIN: información que demuestra la identidad y describe a un individuo como merecedores de un cierto nivel de confianza.

Table 11-1 shows the common types of evidence that a host can present to the runtime. Each row corresponds to a member class of the System.Security.Policy namespace.

Evidence Types

There are two types of evidence: host evidence and assembly evidence. Host evidence describes the assembly’s origin, such as the application directory, URL, or site. Host evidence can also describe the assembly’s identity, such as the hash, publisher, or strong name. Assembly evidence is custom user- or developer-provided evidence.

What Is a Permission?

A permission is a CAS access control entry. For example, the File Dialog permission determines whether an assembly can prompt the user with the Open dialog box, the Save dialog box, both, or neither. Figure 11-1 shows the File Dialog permission being configured.

By default, 19 permissions are available for configuration in the .NET Framework Configuration tool. Each corresponds to two members of the System.Security.Permissions namespace: one for imperative use and one for declarative use. Table 11-2 describes each of these permissions. Additionally, you can add custom permissions.

Permission Settings

Figure 11-1 Permissions specify whether an assembly can and can’t do specific actions

Default PermissionsDefault Permissions 2 Default Permissions 3 y 4

What Is a Permission Set?

A permission set is a CAS ACL. For example, the Internet default permission set contains the following permissions:

■ File Dialog

■ Isolated Storage File

■ Security

■ User Interface

■ Printing

The LocalIntranet zone contains more permissions, based on the theory that code running on your local network deserves more trust than code running from the Internet:

■ Environment Variables

■ File Dialog

■ Isolated Storage File

■ Reflection

■ Security

■ User Interface

■ DNS

■ Printing

The .NET Framework includes seven default permission sets, as described in Table 11-3.

Default Permission Sets

What Are Code Groups?

Code groups are authorization devices that associate assemblies with permission sets. Code groups provide a similar service to CAS as user groups provide to RBS. For

example, if an administrator wants to grant a set of users access to a folder, the administrator creates a user group, adds the users to the group, and then assigns file permissions to the group. Code groups work similarly, except that you don’t have to manually add individual assemblies to a group. Instead, group membership is determined by the evidence that you specify as the code group’s membership condition.

For example, any code running from the Internet should be a member of the Internet_Zone code group. As you can see from Figure 11-2, the Internet_Zone code group’s default membership condition is that the host presents Zone evidence, and that piece of Zone evidence identifies the assembly as being in the Internet zone.

Internet Zone Properties

Figure 11-2 The Internet_Zone code group membership is restricted by using Zone evidence

Whereas user groups control authorization based on distributed ACLs associated with each resource, code groups use centralized permission sets. For example, Figure 11-3 shows that the Internet_Zone code group assigns the Internet permission set. For convenience, the dialog box lists the permission set’s individual permissions. However, you cannot specify individual permissions for a code group. A code group must be associated with a permission set.

Internet Zone Properties PS

Figure 11-3 The Internet_Zone code group assigns the Internet permission set

BEST PRACTICES: Working with files

Applications running in the Internet and LocalIntranet zones do not receive the FileIOPermission, and as such, cannot directly access files. They do, however, have FileDialogPermission. Therefore, assemblies in the Internet zone can open files by prompting the user to select the file using an OpenFileDialog object. Assemblies in the LocalIntranet zone can also save files by using the SaveFileDialog object. To access files without FileIOPermission, call the ShowDialog method of either OpenFileDialog or SaveFileDialog. If the user selects a file, you can use the file handle returned by the OpenFile method to access the file.

It might seem limiting that you can specify only a single type of evidence and a single permission set for a code group. However, just as a user account can be a member of multiple user groups, an assembly can be a member of multiple code groups. The assembly will receive all the permissions assigned to each of the code groups (known as the union of the permission sets). Additionally, you can nest code groups within each other, and assign permissions only if the assembly meets all the evidence requirements of both the parent and child code groups. Nesting code groups allows you to assign permissions based on an assembly having more than one type of evidence. Figure 11-4 shows the Microsoft_Strong_Name code group nested within the My_Computer_Zone code group, which in turn is nested within the All_Code group.

Net FrameWork 2 Configuration Figure 11-4 You can nest code groups to require multiple types of evidence

Table 11-4 lists the default machine code groups residing directly within the All_Code code group. Additionally, some of these code groups contain nested code groups.

Default Code Groups

What Is Security Policy?

A security policy is a logical grouping of code groups and permission sets. Additionally, a security policy can contain custom assemblies that define other types of policies. Security policies provide administrators with the flexibility to configure CAS settings at multiple levels. By default, there are four configurable policy levels: Enterprise, Machine, User, and Application Domain.

The Enterprise level is the highest security policy level, describing security policy for an entire enterprise. Enterprise security policy can be configured by using the Active Directory directory service. Machine policy, the second security policy level, applies to all code run on a particular computer. User policy is the third level, and it defines permissions on a per-user basis. The runtime evaluates the Enterprise, Machine, and User levels separately, and it grants an assembly the minimum set of permissions granted by any of the levels (known as the intersection of the permission sets). By default, the Enterprise and User security policies grant all code full trust, which causes the Machine security policy to alone restrict CAS permissions.

Usefulness of Multiple Layers of Security Policy

To understand how security policies are used, consider an application developer who wants to play with an assembly she downloaded from the Internet. The developer has downloaded the assembly to her local computer, so it will run within the My Computer Zone. The developer’s computer is a member of an Active Directory domain, and a domain administrator has created a code group in the Enterprise security policy that grants assemblies on the local computer the Everything permission set. This is more restrictive than the FullTrust permission set that the Machine security policy grants assemblies in the My Computer zone, so the Everything permission set takes precedence.

The developer isn’t sure that the assembly is safe to run, however, so she wants to apply the Internet permission set to prevent the assembly from writing to the disk or communicating across the network. She doesn’t log on to her computer as an Administrator, but she can still launch the .NET Framework Configuration tool and modify the User security policy. (Standard users aren’t allowed to modify the Machine security policy.) By modifying the User security policy, she can restrict assemblies in the My Computer zone to the Internet permission set. Assemblies that she runs will be restricted without affecting other users of the same computer.

The assembly is a member of three code groups: one in the Enterprise security policy, one in the Machine security policy, and one in the User security policy. The runtime determines the assembly’s permissions by comparing each code group’s permission sets and using the most restrictive set of permissions shared by all three permission sets (the intersection). Because the FullTrust and Everything permission sets contain all the Internet permission set’s permissions (plus a few more permissions), the most restrictive set of permissions is exactly that defined by the Internet permission set.

How CAS Works with Operating System Security

CAS is completely independent of operating system security. In fact, you must use entirely different tools to administer CAS. Although you can control a user’s or group’s file permissions using Microsoft Windows Explorer, you have to use the .NET Framework Configuration tool to grant or restrict an assembly’s file permissions.

CAS works on top of existing operating system security. When determining whether an assembly can take a particular action, both CAS and the operating system security are evaluated. The most restrictive set of permissions is applied. For example, if CAS grants an assembly access to write to the C:\Windows\ folder but the user running the assembly does not have that permission, the assembly cannot write to the folder. Figure 11-5 shows how CAS relates to operating system security.

CAS Complement Figure 11-5 CAS complements, but does not replace, role-based security

How to Use the .NET Framework Configuration Tool to Configure CAS The .NET Framework Configuration tool provides a graphical interface for managing .NET Framework security policy and applications that use remoting services. You can perform many different CAS-related tasks, including the following:

■ Evaluating an assembly to determine which code groups it is a member of

■ Evaluating an assembly to determine which permissions it will be assigned

■ Adding new permission sets

■ Adding new code groups

■ Increasing an assembly’s trust

■ Adjusting zone security

■ Resetting policy levels

How to Determine Which Code Groups Grant Permissions to an Assembly

When troubleshooting CAS permissions, you might need to determine which code groups grant permissions to your assembly. To do this, launch the .NET Framework Configuration tool and perform the following steps:

1. Click Runtime Security Policy.

2. Click Evaluate Assembly. The Evaluate An Assembly Wizard appears.

3. On the What Would You Like To Evaluate page, click Browse. Select your assembly and then click Open.

4. Click the View Code Groups That Grant Permissions To The Assembly option. Click Next.

5. Expand each policy level to determine which code groups grant permissions to your assembly. Figure 11-6 shows an assembly that receives permissions from the My_Computer_Zone code group.

Evaluate an Assembly

Figure 11-6 Use the Evaluate An Assembly Wizard to determine which code groups apply permissions to your assembly

6. Click Finish.

How to Determine Total CAS Permissions Granted to an Assembly

When troubleshooting CAS permissions, you might need to determine which permissions the runtime will grant to your assembly. To do this, launch the .NET Framework Configuration tool and perform the following steps:

1. Click Runtime Security Policy.

2. Click Evaluate Assembly. The Evaluate An Assembly Wizard appears.

3. On the What Would You Like To Evaluate page, click Browse. Select your assembly and then click Open.

4. Click the View Permissions Granted To The Assembly option. Click Next.

5. The wizard displays each permission assigned to your assembly. To view the detailed permission settings, select any permission and then click the View Permission button.

6. Click Finish.

How to Add a Permission Set

To create a new permission set, launch the .NET Framework Configuration tool and perform the following steps:

1. Expand Runtime Security Policy.

2. Expand Enterprise, Machine, or User, depending on the policy level in which you want to define the permission set.

3. Click Permission Sets. In the right pane, click Create New Permission Set.

4. On the Identify The New Permission Set page, specify a name and description. Click Next.

5. On the Assign Individual Permissions To Permission Set page, perform the following steps:

A. Click the permission you want to add to the permission set, and click Add.

B. For each permission, specify the permission settings that are unique to that permission and click OK.

C. Repeat this process for each individual permission required by your permission set.

6. Click Finish.

How to Add a Code Group

To add a code group, launch the .NET Framework Configuration tool and perform the following steps:

1. Expand Runtime Security Policy.

2. Expand Enterprise, Machine, or User, depending on the policy level in which you want to define the code group.

3. Expand Code Groups, expand All_Code, and examine the existing child code groups. If the code group you want to create defines a subset of permissions for an existing code group, click that code group. Otherwise, click All_Code.

4. Click Add A Child Code Group.

5. On the Identify The New Code Group page, type a name and a description, and then click Next.

6. On the Choose A Condition Type page, specify the condition type for the code group by choosing the evidence the runtime will use to identify the code. Click Next.

7. On the Assign A Permission Set To The Code Group page, click the Use Existing Permission Set option if one of the current permission sets exactly meets your needs. Otherwise, click Create A New Permission Set. Click Next.

8. If you selected Create A New Permission Set, perform the following steps:

A. On the Identify The New Permission Set page, specify a name and description. Click Next.

B. On the Assign Individual Permissions To Permission Set page, click the permissions you want in the permission set and click Add. For each permission, specify the permission settings that are unique to that permission and click OK. Click Next.

9. On the Completing The Wizard page, click Finish.

How to Increase an Assembly’s Trust

If you have restricted the default CAS permissions on your computer, you might need to grant additional trust to specific assemblies to grant them the permissions they need to run correctly. To do this, launch the .NET Framework Configuration tool and perform the following steps:

1. Click Runtime Security Policy.

2. Click Increase Assembly Trust. The Trust An Assembly Wizard appears.

3. On the What Would You Like To Modify page, click Make Changes To This Computer to adjust the Mach ine policy level, or click Make Changes For The Current User Only to affect the User policy level. Click Next. You must be an administrator to adjust the Machine policy level.

4. On the What Assembly Do You Want To Trust page, click Browse. Select the assembly you want to trust and then click Open. You can trust only assemblies that have a strong name. Click Next.

5. On the Choose The Minimum Level Of Trust For The Assembly page, select the minimum trust level for the assembly. Click Next.

6. On the Completing The Wizard page, review your selections and then click Finish.

How to Adjust Zone Security

By default, the .NET Framework includes five zones, each with a unique set of CAS permissions. You should make use of these default zones whenever possible, but you might need to change the permission set that a zone uses. To do this, launch the .NET Framework Configuration tool and perform the following steps:

1. Expand Runtime Security Policy, expand Machine, expand Code Groups, and then expand All_Code.

2. Click the zone you want to adjust. In the right pane, click Edit Code Group Properties.

3. Click the Permission Set tab (shown in Figure 11-7) and then click an item in the Permission Set list to specify the desired permission set. Click OK.

LocalIntranet zone properties

Figure 11-7 Adjust the permissions assigned to a zone by adjusting the associated code group’s properties

As a developer, one of the first things you should do is adjust the permission set assigned to the My_Computer_Zone code group. By default, it’s set to Full Trust, which means any CAS statements in your applications will be completely ignored. Change this to the Everything permission set, which grants similar permissions but respects CAS statements in assemblies. Alternatively, you can further restrict access to local assemblies by choosing another permission set.

How to Reset Policy Levels

You might need to restore the default policy levels after making modifications. To do this, launch the .NET Framework Configuration tool and perform the following steps:

1. Click Runtime Security Policy. In the right pane, click Reset All Policy Levels.

2. Click Yes and then click OK.

The .NET Framework Configuration tool restores the original policy level settings, including removing all custom code groups and permission sets that you created.

Demo: Compile and Test the Permissions of a Sample Assembly

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Printing;
using System.Security;
using System.Security.Permissions;

namespace ListPermissions
{
    class Program
    {
        static void Main(string[] args)
        {
            writePermissionState(new FileIOPermission(PermissionState.Unrestricted));
            writePermissionState(new EnvironmentPermission(EnvironmentPermissionAccess.Read, "USERNAME"));
            writePermissionState(new FileDialogPermission(FileDialogPermissionAccess.Open));
            writePermissionState(new IsolatedStorageFilePermission(PermissionState.Unrestricted));
            writePermissionState(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));
            writePermissionState(new UIPermission(UIPermissionWindow.SafeTopLevelWindows));
            writePermissionState(new PrintingPermission(PrintingPermissionLevel.SafePrinting));

            Console.WriteLine("\nPress Enter key to continue");
            Console.Read();
        }

        static private void writePermissionState(CodeAccessPermission p)
        {
            // Write True or False depending on whether the user has the permission
            Console.WriteLine(p.GetType().ToString() + ": " + SecurityManager.IsGranted(p));
        }
    }
}

Resultado:

Ch11 Lesson 1 Exercise 01

Como era de esperarse, tengo todos los permisos, pues claro es mi laptop.