Configuring Security

Team-Fly    

Developing XML Web Services and Server Components with Visual C#™ .NET and the .NET Framework, Exam Cram™ 2 (Exam 70-320)
By Amit Kalani, Priti Kalani

Table of Contents
Chapter 12.  Security Issues


Broadly speaking, .NET security breaks down into two separate areas:

  • Code access security This type of security manages the security of .NET source code itself. You can tell the .NET Framework the resources your code needs to execute properly, and the .NET Framework will check for permission to access those resources on the machine at runtime. Code access security is very flexible and includes the capability to define your own sets of necessary permissions. Code access security can also be used by administrators to ensure that undesired code never gets the chance to run on a system.

  • Role-based security This type of security manages the user rather than the code. Using role-based security enables you to provide (or deny) access to resources based on an identity provided by the user running the code. In practical terms, this means you can limit program execution to particular users or groups on the computer.

Understanding Code Access Security

Code access security controls what code can do on your computer. Permissions, code groups, and permission sets are the three important parts of the code access security.

Permissions

Code access security is based on specific permissions that the common language runtime (CLR) can grant to or deny from code. For example, the authorization to read or write information in the Windows Registry requires the RegistryPermission permission on that part of your code. Code can make four different types of permission requests:

  • It can request the minimum permissions that it requires to run.

  • It can request optional permissions that it would like but does not require.

  • It can refuse permissions to ensure that it does not have access to particular resources.

  • It can demand permissions on the part of calling code.

Based on a variety of factors (including the origin of the code and the information in the machine and application configuration files), the CLR decides whether a particular permission should be granted. If a piece of code cannot obtain the minimum permissions that it requires, that piece of code does not execute. The security settings of the computer determine the maximum permissions that code can be granted, but code is allowed to request (and receive) fewer permissions than the maximum.

The .NET Framework groups permissions into three types:

  • Code access permissions represent access to a protected resource or the capability to perform a protected operation.

  • Identity permissions represent access based on credentials that are a part of the code itself.

  • Role-based permissions represent access based on the user who is running the code.

Each permission in the .NET Framework is represented by a particular class that derives from System.Security.CodeAccessPermission. Table 12.1 lists the permissions that are the most important for controlling the actions that code can take on a particular computer.

Table 12.1. Code Access Permissions in the .NET Framework

Permission

Explanation

DirectoryServicesPermission

Controls access to the System.DirectoryServices namespace

DnsPermission

Controls access to domain name system (DNS) services

EnvironmentPermission

Controls access to environment variables

EventLogPermission

Controls access to the Windows event log

FileDialogPermission

Controls access to files selected from the Open dialog box

FileIOPermission

Controls access to reading and writing files and directories

IsolatedStorageFilePermission

Controls access to private virtual file systems

IsolatedStoragePermission

Controls access to generic isolated storage

MessageQueuePermission

Controls access to message queuing via MSMQ

OleDbPermission

Controls access to data via the System.Data.OleDb namespace

PerformanceCounterPermission

Controls access to performance counters

PrintingPermission

Controls access to printers

ReflectionPermission

Controls access to the reflection features of .NET

RegistryPermission

Controls access to the Windows Registry

SecurityPermission

Controls access to unmanaged code

ServiceControllerPermission

Controls access to starting and stopping services

SocketPermission

Controls access to Windows sockets

SqlClientPermission

Controls access to data via the System.Data.SqlClient namespace

UIPermission

Controls access to the user interface

WebPermission

Controls access to making Web connections

To start working in the .NET security framework, your code can request the minimum permissions that it needs to function correctly. You can requests permissions by applying an attribute to an assembly. Follow these steps to see how to make such a request:

  1. Create a new blank solution (C12) at the location C:\EC70320.

  2. Add a new Visual C# .NET Windows application named Example12_1 to the solution.

  3. Place a Button control (btnGetFile) and an OpenFileDialog component (dlgOpen) on the form.

  4. Switch to Code view and add the following code at the top with other using statements:

     using System.Security.Permissions; [assembly:FileDialogPermissionAttribute(     SecurityAction.RequestMinimum, Unrestricted=true)] 
  5. Add the following code to handle the Click event of the Button control:

     private void btnGetFile_Click(object sender, System.EventArgs e) {     try     {         if(dlgOpen.ShowDialog() == DialogResult.OK)             MessageBox.Show(dlgOpen.FileName);     }     catch (Exception ex)     {         MessageBox.Show("Exception: " + ex.Message);     } } 
  6. Build and run the project. Verify that you can browse for a file.

The FileDialogPermissionAttribute enables the assembly to request the FileDialogPermission permission, which, in turn, allows access to the system's file dialog boxes. In this case, if the code runs without any problem, it means that it was granted the requested permission. By default, you have full permissions to run any code that originates on your own computer.

Code Groups and Permission Sets

A code group is a set of assemblies that share a security context. You define a code group by specifying the membership condition for the group. Every assembly in a code group receives the same permissions from that group. However, because an assembly could be a member of multiple code groups, two assemblies in the same group might end up with different permissions.

The .NET Framework supports seven different membership conditions for code groups:

  • Application directory Selects all the code in the installation directory of the running application.

  • Cryptographic hash Selects all the code that matches a specified cryptographic hash. Practically speaking, this is a way to define a code group that consists of a single assembly.

  • Software publisher Selects all the code from a specified publisher, as verified by Authenticode signing.

  • Site Selects all the code from a particular Internet domain.

  • Strong name Selects all the code that has a specified strong name.

  • URL Selects all the code from a specified URL.

  • Zone Selects all the code from a specified security zone (Internet, Local Intranet, Trusted Sites, My Computer, or Untrusted Sites).

Permissions are granted in permission sets. A permission set is a set of one or more code access permissions that are granted as a unit. If you want to grant only a single permission, you must construct a permission set that contains only that single permission; you can't grant permissions directly. The .NET Framework supplies seven built-in permission sets:

  • Nothing Grants no permissions.

  • Execution Grants permission to run but not access protected resources.

  • Internet Grants limited permissions designed for code of unknown origin.

  • LocalIntranet Grants high permissions designed for code within an enterprise.

  • Everything Grants all permissions except for the permission to skip verification.

  • SkipVerification Grants the permission to skip security checks.

  • FullTrust Grants full access to all resources. This permission set includes all permissions.

You can also create your own custom permission sets, as described in the next section.

Granting Permission

The easiest way to grant or deny permissions in the .NET Framework is to use the Microsoft .NET Framework Configuration tool.

  1. Open the Microsoft .NET Framework 1.1 Configuration tool from the Administrative Tools section of the Windows Control Panel.

  2. Expand the Runtime Security Policy node, then the User node, and then the Permission Sets node to see the built-in .NET permission sets.

  3. Right-click the Everything permission set and select Duplicate. A new permission set named Copy of Everything is created.

  4. Right-click the Copy of Everything permission set and select Rename. Rename the permission set No FileDialog.

  5. With the No FileDialog permission set selected, click the Change Permissions link in the right panel of the configuration tool. In the Create Permission Set dialog box, select File Dialog and click Remove. Click Finish to save your changes.

  6. Expand the Code Groups node and click the default All Code code group. Click the Add a Child Code Group link in the right panel of the configuration tool.

  7. In the Create Code Group dialog box, name the new group Example12_1. Enter a description and click Next.

  8. Choose the Hash condition. Click the Import button and browse to Example12_1.exe. Click Open to calculate the hash for this file. Click Next.

  9. Select the No FileDialog permission set and click Next. Click Finish to create the new code group.

  10. Right-click the Example12_1 code group and select Properties. Check the first check box (this policy level will only have the permissions from the permission set associated with this code group) to make this code group exclusive. Exclusive code group ensures that only the permission set associated with the code group you are adding or modifying is considered when some code fits the membership condition of the code group. Click OK to apply the settings and close the dialog box.

  11. Run the Example12_1.exe application by double-clicking it in Windows Explorer. A policy exception error box appears indicating that the code cannot be run. Click No to dismiss the error box.

graphics/tip_icon.gif

The .NET Framework SDK also includes the Code Access Security Policy tool, caspol.exe, which can manipulate code groups and permission sets from the command line. If you're trying to automate security operations, you can make good use of this tool from a batch file.


Imperative Security

Requesting permissions through the use of attributes is known as declarative security. There's a second method to request permissions, known as imperative security. With imperative security, you create objects to represent the permissions that your code requires. The following code snippet shows how to request FileDialog permission through a FileDialogPermission object:

 try {     FileDialogPermission fdp = new     FileDialogPermission(PermissionState.Unrestricted);     // Check to see whether the code has the specified permission     fdp.Demand();     if(dlgOpen.ShowDialog() == DialogResult.OK)        MessageBox.Show(dlgOpen.FileName); } catch(Exception ex) {     MessageBox.Show("Exception: " + ex.Message); } 

In this code, when the security policy is such that the FileDialog permission cannot be granted, the code throws an exception.

graphics/alert_icon.gif

The only time you absolutely must have imperative security is when you need to make security decisions based on factors that are known only at runtime, such as the name of a particular file. In many other cases, declarative security is easier to use.


Computing Permissions

Determining the actual permissions applied to any given piece of code is a complex process. To begin the process, you should think about permissions at the Enterprise level only. The CLR starts by examining the evidence that a particular piece of code presents to determine its membership in code groups at that level. Evidence is just an overall term for the various identity permissions (publisher, strong name, hash, and so on) that can go into code group membership.

Code groups are organized into a hierarchy. In general, the CLR examines all the code groups in the hierarchy to determine membership. However, any code group in the hierarchy may be marked as Exclusive. The CLR stops checking for group membership if code is found to be a member of an Exclusive code group. Either way, code is determined to be a member of zero or more code groups as a first step.

Next, the CLR retrieves the permission set for each code group that contains the code. If the code is a member of an Exclusive code group, only the permission set of that code group is taken into account. If the code is a member of more than one code group and none of them is an Exclusive code group, all the permission sets of those code groups are taken into account. The permission set for the code is the union of the permission sets of all relevant code groups. That is, if the code is a member of two code groups and one code group grants FileDialog permission but the other does not, the code has FileDialog permission from this step.

The process accounts for the permissions at one level (the Enterprise level). But there are actually four levels of permissions: Enterprise, Machine, User, and Application Domain. Only the first three of these levels can be managed within the .NET Framework Configuration tool. However, if you need specific security checking within an application domain (which, roughly speaking, is a session in which code runs), you can do this in code. An application domain can reduce the permissions granted to code within that application domain, but it cannot expand them.

The CLR determines which of the four levels are relevant by starting at the top (the Enterprise level) and working down. Any given code group can have the LevelFinal property, in which case the examination stops there. For example, if code is a member of a code group on the Machine level and that group has the LevelFinal property, only the Enterprise and Machine levels are considered when security is assigned. The CLR computes the permissions for each level separately and then assigns the code the intersection of the permissions of all relevant levels. That is, if code is granted the FileDialog permission on the Enterprise and Machine levels but is not granted FileDialog permission on the User level, the code does not have FileDialog permission.

At this point, the CLR knows what permissions should be granted to the code in question, considered in isolation. But code does not run in isolation; it runs as part of an application. The final step of evaluating code access permissions is to perform a stack walk. In a stack walk, the CLR examines all code in the calling chain from the original application to the code being evaluated. The final permission set for the code is the intersection of the permission sets of all code in the calling chain. That is, if code is granted FileDialog permission but the code that called it was not granted FileDialog permission, the code is not granted FileDialog permission.

graphics/alert_icon.gif

The Microsoft .NET Framework Configuration tool can help you determine the effective permissions for a piece of code. To determine the effective permissions, right-click the Runtime Security Policy node and select Evaluate Assembly. You can see the effective permissions for an assembly here, or you can get a list of all the code groups that contribute to the assembly's permissions.


Requesting Other Types of Permissions

You might at times want to request a particular permission even though your application doesn't absolutely require that permission for a user to proceed. To request optional permissions, you use the SecurityAction.RequestOptional action.

To make use of optional permissions in Visual C# .NET, your code must have a Main() method with a try-catch block. If optional permissions for the assembly can't be granted, this block catches the exception. If minimum permissions can't be granted, the program is shut down, whether this block is present or not.

graphics/caution_icon.gif

When you request minimum permissions, the CLR gives your assembly any other permissions it can in addition to the minimum permissions. When you request optional permissions, the CLR gives the assembly only those permissions and no others. So if you make an optional permissions request, you must be sure to request all the permissions that your code requires, including user interface permissions if you display any user interface.


You can also tell the CLR about permissions that you do not want your code to have. This can be useful if the code is potentially available to untrusted callers (for example, users who invoke the code over the Internet), and you want to limit the potential harm that they can do. The action for this is SecurityAction.RequestRefuse.

Finally, you might want to ensure that all the code that calls your code has a particular permission. For example, you might want to raise an exception if any code in the calling stack doesn't have the RegistryPermission permission. You can do this by specifying SecurityAction.Demand in the declaration of the security attribute.

Using Custom Security Attributes

In some cases, you might find that the built-in security permissions do not fit your needs. In such cases, you can create your own custom permissions. To implement a custom permission, your class inherits from the CodeAccessPermission class. The new class must override five key methods to provide its own interfaces to the security system:

  • Copy() Creates an exact copy of the current instance

  • Intersect() Returns the intersection of permissions between the current instance and a passed-in instance of the class

  • IsSubsetOf() Returns true if a passed-in instance includes everything allowed by the current instance

  • FromXml() Decodes an XML representation of the permission

  • ToXml() Encodes the current instance as XML

Your class must support a constructor that accepts an instance of the PermissionState enumeration (which has a value of Unrestricted or None). Although it's not strictly required, your code should also implement a method named IsUnrestricted(), which returns true if the particular instance represents unrestricted access to the resource. This makes your custom permission more compatible with the built-in permissions in the .NET Framework.

To support declarative security, you should also implement an attribute class for your permission. This attribute class should derive from CodeAccessSecurityAttribute (which, in turn, derives from SecurityAttribute). The class should override the CreatePermission() method of the IPermission interface. Within this function, you should create an instance of your base custom permission class and set its properties according to the parameters from the declarative security invocation. Any attribute class must be marked with the Serializable attribute so that it can be serialized into metadata along with the class to which it is applied.


    Team-Fly    
    Top


    MCAD Developing XML Web Services and Server Components with Visual C#. NET and the. NET Framework Exam Cram 2 (Exam Cram 70-320)
    Managing Globally with Information Technology
    ISBN: 789728974
    EAN: 2147483647
    Year: 2002
    Pages: 179

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