Export (0) Print
Expand All
3 out of 13 rated this helpful - Rate this topic

Code Access Security and ADO.NET 

The .NET Framework offers role-based security as well as code access security (CAS), both of which are implemented using a common infrastructure supplied by the common language runtime (CLR). In the world of unmanaged code, most applications execute with the permissions of the user or principal. As a result, computer systems can be damaged and private data compromised when malicious or error-filled software is run by a user with elevated privileges. By contrast, managed code executing in the .NET Framework includes code access security, which applies to code alone. Whether the code is allowed to run or not depends on the code's origin or other aspects of the code's identity, not just the identity of the principal. This reduces the likelihood that managed code can be misused.

Code Access Permissions

When code is executed, it presents evidence that is evaluated by the CLR security system. Typically, this evidence comprises the origin of the code including URL, site, and zone, and digital signatures that ensure the identity of the assembly.

The CLR allows code to perform only those operations that the code has permission to perform. Code can request permissions, but those requests are honored based on the security policy set by an administrator.

NoteNote

Code executing in the CLR cannot grant permissions to itself. For example, code can request and be granted fewer permissions than a security policy allows, but it will never be granted more permissions. When granting permissions, start with no permissions at all and then add the narrowest permissions for the particular task being performed. Starting with all permissions and then denying individual ones leads to insecure applications that may contain unintentional security holes from granting more permissions than required. For more information, see Configuring Security Policy and Security Policy Management.

There are three types of code access permissions:

  • Code access permissions derive from the CodeAccessPermission class, which represents access to a protected resource or the ability to perform a protected operation. This includes files and environment variables as well as performing operations such as accessing unmanaged code.

  • Identity permissions represent characteristics that identify an assembly. Permissions are granted to an assembly based on evidence, which can include items such as a digital signature or where the code originated. Identity permissions also derive from the CodeAccessPermission base class. For more information, see Identity Permissions.

  • Role-based security permissions are based on whether a principal has a specified identity or is a member of a specified role. The PrincipalPermission class allows both declarative and imperative permission checks against the active principal. For more information, see Declarative Security and Imperative Security.

To determine whether code is authorized to access a resource or perform an operation, the runtime's security system traverses the call stack, comparing the granted permissions of each caller to the permission being demanded. If any caller in the call stack does not have the demanded permission, a SecurityException is thrown and access is refused. For more information, see Security Demands and Security Optimizations.

Requesting Permissions

The purpose of requesting permissions is to inform the runtime which permissions your application requires in order to run, and to ensure that it receives only the permissions that it actually needs. For example, if your application needs to write data to the local disk, then it requires FileIOPermission. If that permission hasn't been granted, the application will fail when it attempts to write to the disk. However, if the application requests FileIOPermission and that permission has not been granted, the application will generate the exception at the outset and will not load. In a scenario where the application only needs to read data from the disk, you can request that it never be granted any write permissions. In the event of a bug or a malicious attack, your code cannot damage the data on which it operates. For more information, see Requesting Permissions.

Role-Based Security and CAS

Implementing both role-based security and CAS enhances overall security for your application. Role-based security can be based on a Windows account or a custom identity, making information about the security principal available to the current thread. In addition, applications are often required to provide access to data or resources based on credentials supplied by the user. Typically, such applications check the role of a user and provide access to resources based on those roles. Depending on the type of application you are building, you should also consider implementing role-based permissions on your data source. For more information, see "Security Considerations for SQL Server" in SQL Server Books Online, or the product documentation for your data source.

Topic Description

Role-Based Security

Discusses role-based security and provides links to additional topics.

Setting Role-Based Security Policy and Principals

Discusses how to implement role-based security policy.

Role-Based Security Permissions

Discusses the PrincipalPermission object.

Securing Assemblies

The links in this section discuss securing your code and your assemblies. Strong-naming gives an application or component a unique identity that other software can use to refer explicitly to it. Strong-naming your assemblies guards them against being spoofed by an assembly that contains hostile code. It also ensures versioning consistency among different versions of a component. You must strong-name assemblies that will be deployed to the Global Assembly Cache (GAC).

Topic Description

Guidelines for Writing Secure Code

Emphasizes the importance of designing security in your applications from the start.

Creating and Using Strong-Named Assemblies

Discusses how to sign an assembly and reference it in an application.

Delay Signing an Assembly

Discusses strong-naming assemblies where the key is protected.

Strong Name Tool (Sn.exe)

Discusses using the command-line tool Sn.exe to strong-name assemblies.

Building Secure Assemblies

This MSDN white paper contains comprehensive information on writing and deploying secure code.

Partial Trust in ADO.NET 2.0

In ADO.NET 2.0, the .NET Framework Data Provider for SQL Server, the .NET Framework Data Provider for OLE DB, the .NET Framework Data Provider for ODBC, and the .NET Framework Data Provider for Oracle can now all run in partially trusted environments. In previous releases of the .NET Framework, only System.Data.SqlClient was supported in less than full-trust applications.

At minimum, a partially trusted application using the SQL Server provider must have execution and SqlClientPermission permissions.

Permission Attribute Properties for Partial Trust

For partial trust scenarios, you can use SqlClientPermissionAttribute members to further restrict the capabilities available for the .NET Framework Data Provider for SQL Server.

NoteNote

The .NET Framework Data Provider for SQL Server requires the Full Trust Security permission in order to open a SqlConnection with SQL Debugging enabled in SQL Server 2000. SQL Debugging for SQL Server 2005 does not utilize this class. See SQL Server 2005 Books Online for details.

The following table lists the available SqlClientPermissionAttribute properties and their descriptions:

Permission attribute property Description

Action

Gets or sets a security action. Inherited from SecurityAttribute.

AllowBlankPassword

Enables or disables the use of a blank password in a connection string. Valid values are true (to enable the use of blank passwords) and false (to disable the use of blank passwords). Inherited from DBDataPermissionAttribute.

ConnectionString

Identifies a permitted connection string. Multiple connection strings can be identified.

NoteNote

Do not include a user ID or password in your connection string. In this release, you cannot change connection string restrictions using the .NET Framework Configuration Tool.

Inherited from DBDataPermissionAttribute.

KeyRestrictions

Identifies connection string parameters that are allowed or disallowed. Connection string parameters are identified in the form <parameter name>=. Multiple parameters can be specified, delimited using a semicolon (;).

NoteNote

If you do not specify KeyRestrictions, but you set KeyRestrictionBehavior property to AllowOnly or PreventUsage, no additional connection string parameters are allowed. Inherited from DBDataPermissionAttribute.

KeyRestrictionBehavior

Identifies the connection string parameters as the only additional parameters allowed (AllowOnly), or identifies the additional parameters that are not allowed (PreventUsage). AllowOnly is the default. Inherited from DBDataPermissionAttribute.

TypeID

Gets a unique identifier for this attribute when implemented in a derived class. Inherited from Attribute.

Unrestricted

Indicates whether unrestricted permission to the resource is declared. Inherited from SecurityAttribute.

ConnectionString Syntax

The following example demonstrates how to use the connectionStrings element of a configuration file to allow only a specific connection string to be used. See Working with Connection Strings for more information on storing and retrieving connection strings from configuration files.

<connectionStrings>
  <add name="DatabaseConnection" 
    connectionString="Data Source=(local);Initial 
    Catalog=Northwind;Integrated Security=true;" />
</connectionStrings>

KeyRestrictions Syntax

The following example enables the same connection string, enables the use of the Encrypt and Packet Size connection string options, but restricts the use of any other connection string options.

<connectionStrings>
  <add name="DatabaseConnection" 
    connectionString="Data Source=(local);Initial 
    Catalog=Northwind;Integrated Security=true;"
    KeyRestrictions="Encrypt=;Packet Size=;"
    KeyRestrictionBehavior="AllowOnly" />
</connectionStrings>

KeyRestrictionBehavior with PreventUsage Syntax

The following example enables the same connection string and allows all other connection parameters except for User Id, Password, and Persist Security Info.

<connectionStrings>
  <add name="DatabaseConnection" 
    connectionString="Data Source=(local);Initial 
    Catalog=Northwind;Integrated Security=true;"
    KeyRestrictions="User Id=;Password=;Persist Security Info=;"
    KeyRestrictionBehavior="PreventUsage" />
</connectionStrings>

KeyRestrictionBehavior with AllowOnly Syntax

The following example enables two connection strings that also contain Initial Catalog, Connection Timeout, Encrypt, and Packet Size parameters. All other connection string parameters are restricted.

<connectionStrings>
  <add name="DatabaseConnection" 
    connectionString="Data Source=(local);Initial 
    Catalog=Northwind;Integrated Security=true;"
    KeyRestrictions="Initial Catalog;Connection Timeout=;
       Encrypt=;Packet Size=;" 
    KeyRestrictionBehavior="AllowOnly" />

  <add name="DatabaseConnection2" 
    connectionString="Data Source=SqlServer2;Initial 
    Catalog=Northwind2;Integrated Security=true;"
    KeyRestrictions="Initial Catalog;Connection Timeout=;
       Encrypt=;Packet Size=;" 
    KeyRestrictionBehavior="AllowOnly" />
</connectionStrings>

Enabling Partial Trust with a Custom Permission Set

To enable the use of System.Data.SqlClient permissions for a particular zone, a system administrator must create a custom permission set and set it as the permission set for a particular zone. Default permission sets, such as LocalIntranet, cannot be modified. For example, to include System.Data.SqlClient permissions for code that has a Zone of LocalIntranet, a system administrator could copy the permission set for LocalIntranet, rename it to "CustomLocalIntranet", add the System.Data.SqlClient permissions, import the CustomLocalIntranet permission set using the Code Access Security Policy Tool (Caspol.exe), and set the permission set of LocalIntranet_Zone to CustomLocalIntranet.

Sample Permission Set

The following is a sample permission set for the .NET Framework Data Provider for SQL Server in a partially trusted scenario. For information on creating custom permission sets, see Configuring Permission Sets Using Caspol.exe.

<PermissionSet class="System.Security.NamedPermissionSet"
               version="1"
               Name="CustomLocalIntranet"
               Description="Custom permission set given to applications on the local intranet">

   <IPermission class="System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                version="1"
                AllowBlankPassword="False">
      <add ConnectionString="Data Source=(local);Integrated Security=SSPI;"
           KeyRestrictions="Initial Catalog=;Connection Timeout=;Encrypt=;Packet Size=;" 
           KeyRestrictionBehavior="AllowOnly" />
   </IPermission>

</PermissionSet>

Verifying ADO.NET Code Access Using Security Permissions

For partial-trust scenarios, you can require CAS privileges for particular methods in your code by specifying a SqlClientPermissionAttribute. If that privilege is not allowed by the restricted security policy in effect, an exception is thrown before your code is run. For more information on security policy, see Security Policy Management and Security Policy Best Practices.

Example

The following example demonstrates how to write code that requires a particular connection string. It simulates denying unrestricted permissions to System.Data.SqlClient, which a system administrator would implement using a CAS policy in the real world.

Security noteSecurity Note

When designing code access security permissions for ADO.NET, the correct pattern is to start with the most restrictive case (no permissions at all) and then add the specific permissions that are needed for the particular task that the code needs to perform. The opposite pattern, starting with all permissions and then denying a specific permission, is not secure, because there are many ways of expressing the same connection string. For example, if you start with all permissions and then attempt to deny the use of the connection string "server=someserver", the string "server=someserver.mycompany.com" would still be allowed. By always starting by granting no permissions at all, you reduce the chances that there are holes in the permission set.

The following code demonstrates how SqlClient performs the security demand, which throws a SecurityException if the appropriate CAS permissions are not in place. The SecurityException output is displayed in the console window.

static void TestCAS(string connectString1, string connectString2)
{
    // Simulate removing SqlClient permissions.
    SqlClientPermission permission = new 
        SqlClientPermission(PermissionState.Unrestricted);
    permission.Deny();

    // Try to open a connection.
    try
    {
        using (SqlConnection connection = new 
                   SqlConnection(connectString1))
        {
            connection.Open();
            Console.WriteLine("Connection opened, unexpected.");
        }
    }
    catch (System.Security.SecurityException ex)
    {
        Console.WriteLine("Failed, as expected: {0}", 
            ex.FirstPermissionThatFailed);

        // Uncomment the following line to see Exception details.
        //Console.WriteLine("BaseException: " + ex.GetBaseException());
    }

    SqlClientPermission.RevertAll();

    // Add permission for a specific connection string.
    // This would typically be achieved by the administrator deploying 
    // a CAS policy, not in your code.
    permission = new SqlClientPermission(PermissionState.None);
    permission.Add(connectString1,"", KeyRestrictionBehavior.AllowOnly);

    permission.PermitOnly();

    // Try again, it should succeed now.
    try
    {
        using (SqlConnection connection = new SqlConnection(connectString1))
        {
            connection.Open();
        }
        Console.WriteLine("Connection opened, as expected.");
    }
    catch (System.Security.SecurityException ex)
    {
        Console.WriteLine("Unexpected failure: {0}", ex.Message);
    }

    // Try a different connection string. This should fail.
    try
    {
        using (SqlConnection connection = new SqlConnection(connectString2))
        {
            connection.Open();
        }
        Console.WriteLine("Connection opened, unexpected.");
    }
    catch (System.Security.SecurityException ex)
    {
        Console.WriteLine("Failed, as expected: {0}", ex.Message);
    }
}

You should see this output in the Console window:

Failed, as expected: <IPermission class="System.Data.SqlClient.
SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" AllowBlankPassword="False">
<add ConnectionString="Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI" KeyRestrictions=""
KeyRestrictionBehavior="AllowOnly"/>
</IPermission>

Connection opened, as expected.
Failed, as expected: Request failed.

Interoperability with Unmanaged Code

Code that runs outside the common language runtime (CLR) is called unmanaged code. Therefore, security mechanisms such as CAS cannot be applied to unmanaged code. COM components, ActiveX interfaces, and Win32 API functions are examples of unmanaged code. Special security considerations apply when executing unmanaged code so that you do not jeopardize overall application security.

Topic Description

Interoperating with Unmanaged Code

Provides links to additional topics discussing interoperability with unmanaged code.

Primary Interop Assemblies

Describes how to work with primary interop assemblies in a .NET application.

Requesting Permissions

Describes how to request permissions, including how to request permission to access unmanaged code using a SecurityPermissionAttribute.

See Also

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback

Community Additions

ADD
Show:
© 2014 Microsoft. All rights reserved.