Kodåtkomstsäkerhet och ADO.NET

.NET Framework erbjuder rollbaserad säkerhet samt kodåtkomstsäkerhet (CAS), som båda implementeras med hjälp av en gemensam infrastruktur som tillhandahålls av CLR (Common Language Runtime). I en värld av ohanterad kod körs de flesta program med användarens eller huvudnamnets behörigheter. Därför kan datorsystem skadas och privata data komprometteras när skadlig eller felfylld programvara körs av en användare med förhöjd behörighet.

Däremot innehåller hanterad kodkörning i .NET Framework kodåtkomstsäkerhet, som gäller enbart för kod. Om koden tillåts köras eller inte beror på kodens ursprung eller andra aspekter av kodens identitet, inte bara huvudnamnets identitet. Detta minskar sannolikheten för att hanterad kod kan missbrukas.

Kommentar

Code Access Security (CAS) har föråldrats i alla versioner av .NET Framework och .NET. De senaste versionerna av .NET följer inte CAS-anteckningar och skapar fel om CAS-relaterade API:er används. Utvecklare bör söka alternativa sätt att utföra säkerhetsuppgifter.

Behörigheter för kodåtkomst

När koden körs visas bevis som utvärderas av CLR-säkerhetssystemet. Det här beviset består vanligtvis av kodens ursprung, inklusive URL, webbplats och zon samt digitala signaturer som säkerställer sammansättningens identitet.

CLR tillåter att kod endast utför de åtgärder som koden har behörighet att utföra. Kod kan begära behörigheter och dessa begäranden uppfylls baserat på den säkerhetsprincip som angetts av en administratör.

Kommentar

Kod som körs i CLR kan inte bevilja behörigheter till sig själv. Kod kan till exempel begära och beviljas färre behörigheter än vad en säkerhetsprincip tillåter, men den beviljas aldrig fler behörigheter. När du beviljar behörigheter börjar du utan behörigheter alls och lägger sedan till de smalaste behörigheterna för den specifika uppgift som utförs. Att börja med alla behörigheter och sedan neka enskilda leder till osäkra program som kan innehålla oavsiktliga säkerhetshål från att bevilja fler behörigheter än vad som krävs. Mer information finns i Konfigurera hantering av säkerhetsprinciper och säkerhetsprinciper.

Det finns tre typer av behörigheter för kodåtkomst:

  • Code access permissions härleda från CodeAccessPermission klassen. Behörigheter krävs för åtkomst till skyddade resurser, till exempel filer och miljövariabler, och för att utföra skyddade åtgärder, till exempel åtkomst till ohanterad kod.

  • Identity permissions representerar egenskaper som identifierar en sammansättning. Behörigheter beviljas till en sammansättning baserat på bevis, som kan innehålla objekt som en digital signatur eller var koden har sitt ursprung. Identitetsbehörigheter härleds också från basklassen CodeAccessPermission .

  • Role-based security permissions baseras på om ett huvudnamn har en angiven identitet eller är medlem i en angiven roll. Klassen PrincipalPermission tillåter både deklarativa och imperativa behörighetskontroller mot det aktiva huvudkontot.

För att avgöra om kod har behörighet att komma åt en resurs eller utföra en åtgärd går körningens säkerhetssystem igenom anropsstacken och jämför de tilldelade behörigheterna för varje anropare med den behörighet som krävs. Om någon anropare i samtalsstacken inte har den begärda behörigheten genereras en SecurityException och åtkomst nekas.

Begära behörigheter

Syftet med att begära behörigheter är att informera körningen om vilka behörigheter programmet kräver för att kunna köras och att se till att det endast tar emot de behörigheter som det faktiskt behöver. Om ditt program till exempel behöver skriva data till den lokala disken kräver FileIOPermissiondet . Om den behörigheten inte har beviljats misslyckas programmet när det försöker skriva till disken. Men om programbegäranden FileIOPermission och den behörigheten inte har beviljats genererar programmet undantaget från början och läses inte in.

I ett scenario där programmet bara behöver läsa data från disken kan du begära att det aldrig beviljas några skrivbehörigheter. I händelse av en bugg eller ett skadligt angrepp kan koden inte skada de data som den fungerar på. Mer information finns i Begära behörigheter.

Rollbaserad säkerhet och CAS

Implementering av både rollbaserad säkerhet och kodanvänd säkerhet (CAS) förbättrar den övergripande säkerheten för ditt program. Rollbaserad säkerhet kan baseras på ett Windows-konto eller en anpassad identitet, vilket gör information om säkerhetsobjektet tillgängligt för den aktuella tråden. Dessutom krävs ofta program för att ge åtkomst till data eller resurser baserat på autentiseringsuppgifter som tillhandahålls av användaren. Vanligtvis kontrollerar sådana program en användares roll och ger åtkomst till resurser baserat på dessa roller.

Med rollbaserad säkerhet kan en komponent identifiera aktuella användare och deras associerade roller vid körning. Den här informationen mappas sedan med hjälp av en CAS-princip för att fastställa vilken uppsättning behörigheter som beviljas vid körning. För en angiven programdomän kan värden ändra standardrollbaserad säkerhetsprincip och ange ett standardsäkerhetsobjekt som representerar en användare och de roller som är associerade med den användaren.

CLR använder behörigheter för att implementera sin mekanism för att framtvinga begränsningar för hanterad kod. Rollbaserade säkerhetsbehörigheter ger en mekanism för att identifiera om en användare (eller agenten som agerar för användarens räkning) har en viss identitet eller är medlem i en angiven roll. Mer information finns i Säkerhetsbehörigheter.

Beroende på vilken typ av program du skapar bör du även överväga att implementera rollbaserade behörigheter i databasen. Mer information om rollbaserad säkerhet i SQL Server finns i SQL Server Security.

Sammansättningar

Sammansättningar utgör den grundläggande enheten för distribution, versionskontroll, återanvändning, aktiveringsomfång och säkerhetsbehörigheter för ett .NET Framework-program. En sammansättning innehåller en samling typer och resurser som är byggda för att fungera tillsammans och bilda en logisk funktionsenhet. För CLR finns ingen typ utanför kontexten för en sammansättning. Mer information om hur du skapar och distribuerar sammansättningar finns i Programmering med sammansättningar.

Sammansättningar med stark namngivning

Ett starkt namn, eller en digital signatur, består av sammansättningens identitet, som innehåller dess enkla textnamn, versionsnummer och kulturinformation (om det tillhandahålls), plus en offentlig nyckel och en digital signatur. Den digitala signaturen genereras från en sammansättningsfil med hjälp av motsvarande privata nyckel. Sammansättningsfilen innehåller sammansättningsmanifestet, som innehåller namn och hashvärden för alla filer som utgör sammansättningen.

Stark namngivning av en sammansättning ger ett program eller en komponent en unik identitet som andra program kan använda för att uttryckligen referera till den. Starka namngivningsvakter skyddar sammansättningar mot att förfalskas av en sammansättning som innehåller fientlig kod. Stark namngivning säkerställer också versionskonsekvens mellan olika versioner av en komponent. Du måste ha starka namnsammansättningar som ska distribueras till den globala sammansättningscachen (GAC). Mer information finns i Skapa och använda starka namngivna sammansättningar.

Partiellt förtroende för ADO.NET 2.0

I ADO.NET 2.0 kan .NET Framework-dataprovidern för SQL Server, .NET Framework-dataprovidern för OLE DB, .NET Framework-dataprovidern för ODBC och .NET Framework-dataprovidern för Oracle nu alla köras i delvis betrodda miljöer. I tidigare versioner av .NET Framework stöds endast System.Data.SqlClient i program med mindre än fullständigt förtroende.

Minst måste ett delvis betrott program som använder SQL Server-providern ha körning och SqlClientPermission behörigheter.

Egenskaper för behörighetsattribut för partiellt förtroende

För partiella förtroendescenarier kan du använda SqlClientPermissionAttribute medlemmar för att ytterligare begränsa de funktioner som är tillgängliga för .NET Framework-dataprovidern för SQL Server.

I följande tabell visas de tillgängliga SqlClientPermissionAttribute egenskaperna och deras beskrivningar:

Egenskap för behörighetsattribut beskrivning
Action Hämtar eller anger en säkerhetsåtgärd. Ärvd från SecurityAttribute.
AllowBlankPassword Aktiverar eller inaktiverar användningen av ett tomt lösenord i en anslutningssträng. Giltiga värden är true (för att aktivera användning av tomma lösenord) och false (för att inaktivera användningen av tomma lösenord). Ärvd från DBDataPermissionAttribute.
ConnectionString Identifierar en tillåten anslutningssträng. Flera anslutningssträng kan identifieras. Obs! Inkludera inte ett användar-ID eller lösenord i din anslutningssträng. I den här versionen kan du inte ändra anslutningssträng begränsningar med hjälp av konfigurationsverktyget för .NET Framework.

Ärvd från DBDataPermissionAttribute.
KeyRestrictions Identifierar anslutningssträng parametrar som tillåts eller inte tillåts. Anslut ionssträngsparametrar identifieras i formuläret <parameter name>=. Flera parametrar kan anges, avgränsade med ett semikolon (;). Obs! Om du inte anger KeyRestrictions, men du anger KeyRestrictionBehavior egenskapen till AllowOnly eller PreventUsage, tillåts inga ytterligare anslutningssträng parametrar. Ärvd från DBDataPermissionAttribute.
KeyRestrictionBehavior Identifierar de anslutningssträng parametrarna som de enda ytterligare parametrar som tillåts (AllowOnly) eller identifierar de ytterligare parametrar som inte tillåts (PreventUsage). AllowOnly används som standard. Ärvd från DBDataPermissionAttribute.
TypeID Hämtar en unik identifierare för det här attributet när det implementeras i en härledd klass. Ärvd från Attribute.
Unrestricted Anger om obegränsad behörighet till resursen har deklarerats. Ärvd från SecurityAttribute.

syntax för Anslut ionString

I följande exempel visas hur du använder elementet i connectionStrings en konfigurationsfil för att endast tillåta att en specifik anslutningssträng används. Mer information om hur du lagrar och hämtar anslutningssträng från konfigurationsfiler finns i Anslut ionssträngar.

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

KeyRestrictions Syntax

Följande exempel aktiverar samma anslutningssträng, möjliggör användning av Encrypt alternativen och Packet Size anslutningssträng, men begränsar användningen av andra anslutningssträng alternativ.

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

KeyRestrictionBehavior med PreventUsage Syntax

Följande exempel aktiverar samma anslutningssträng och tillåter alla andra anslutningsparametrar förutom User Id, Password och 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 med AllowOnly-syntax

I följande exempel kan du använda två anslutningssträng som också innehåller Initial Catalogparametrarna , Connection Timeout, Encryptoch Packet Size . Alla andra anslutningssträng parametrar är begränsade.

<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>  

Aktivera partiellt förtroende med en anpassad behörighetsuppsättning

Om du vill aktivera användning av System.Data.SqlClient behörigheter för en viss zon måste en systemadministratör skapa en anpassad behörighetsuppsättning och ange den som behörighetsuppsättning för en viss zon. Standardbehörighetsuppsättningar, till exempel LocalIntranet, kan inte ändras. Om du till exempel vill inkludera System.Data.SqlClient behörigheter för kod som har en Zone av LocalIntranetkan en systemadministratör kopiera behörighetsuppsättningen för LocalIntranet, byta namn på den till "CustomLocalIntranet", lägga till System.Data.SqlClient behörigheterna, importera behörighetsuppsättningen CustomLocalIntranet med hjälp av Caspol.exe (Code Access Security Policy Tool) och ange behörighetsuppsättningen LocalIntranet_Zone till CustomLocalIntranet.

Exempel på behörighetsuppsättning

Följande är en exempelbehörighetsuppsättning för .NET Framework Data Provider för SQL Server i ett delvis betrott scenario. Information om hur du skapar anpassade behörighetsuppsättningar finns i Konfigurera behörighetsuppsättningar med hjälp av 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=true;"  
 KeyRestrictions="Initial Catalog=;Connection Timeout=;  
   Encrypt=;Packet Size=;"
 KeyRestrictionBehavior="AllowOnly" />  
 </IPermission>  
</PermissionSet>  

Verifiera ADO.NET kodåtkomst med hjälp av säkerhetsbehörigheter

För scenarier med partiellt förtroende kan du kräva CAS-behörigheter för vissa metoder i koden genom att ange en SqlClientPermissionAttribute. Om den behörigheten inte tillåts av den begränsade säkerhetsprincipen som gäller utlöses ett undantag innan koden körs. Mer information om säkerhetsprinciper finns i Metodtips för hantering av säkerhetsprinciper och säkerhetsprinciper.

Exempel

I följande exempel visas hur du skriver kod som kräver en viss anslutningssträng. Den simulerar neka obegränsade behörigheter till System.Data.SqlClient, som en systemadministratör skulle implementera med hjälp av en CAS-princip i verkligheten.

Viktigt!

När du utformar CAS-behörigheter för ADO.NET är rätt mönster att börja med det mest restriktiva fallet (inga behörigheter alls) och sedan lägga till de specifika behörigheter som behövs för den specifika uppgift som koden behöver utföra. Det motsatta mönstret, som börjar med alla behörigheter och sedan nekar en specifik behörighet, är inte säkert eftersom det finns många sätt att uttrycka samma anslutningssträng. Om du till exempel börjar med alla behörigheter och sedan försöker neka användningen av anslutningssträng "server=someserver" skulle strängen "server=someserver.mycompany.com" fortfarande tillåtas. Genom att alltid börja genom att bevilja inga behörigheter alls minskar du risken för att det finns hål i behörighetsuppsättningen.

Följande kod visar hur SqlClient utför säkerhetsbehovet, vilket genererar en SecurityException om lämpliga CAS-behörigheter inte finns på plats. Utdata SecurityException visas i konsolfönstret.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Security;
using System.Security.Permissions;

namespace PartialTrustTopic {
   public class PartialTrustHelper : MarshalByRefObject {
      public void TestConnectionOpen(string connectionString) {
         // Try to open a connection.
         using (SqlConnection connection = new SqlConnection(connectionString)) {
            connection.Open();
         }
      }
   }

   class Program {
      static void Main(string[] args) {
         TestCAS("Data Source=(local);Integrated Security=true", "Data Source=(local);Integrated Security=true;Initial Catalog=Test");
      }

      static void TestCAS(string connectString1, string connectString2) {
         // Create permission set for sandbox AppDomain.
         // This example only allows execution.
         PermissionSet permissions = new PermissionSet(PermissionState.None);
         permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

            // Create sandbox AppDomain with permission set that only allows execution,
            // and has no SqlClientPermissions.
            AppDomainSetup appDomainSetup = new AppDomainSetup();
         appDomainSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
         AppDomain firstDomain = AppDomain.CreateDomain("NoSqlPermissions", null, appDomainSetup, permissions);

         // Create helper object in sandbox AppDomain so that code can be executed in that AppDomain.
         Type helperType = typeof(PartialTrustHelper);
         PartialTrustHelper firstHelper = (PartialTrustHelper)firstDomain.CreateInstanceAndUnwrap(helperType.Assembly.FullName, helperType.FullName);

         try {
            // Attempt to open a connection in the sandbox AppDomain.
            // This is expected to fail.
            firstHelper.TestConnectionOpen(connectString1);
            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());
         }

         // Add permission for a specific connection string.
         SqlClientPermission sqlPermission = new SqlClientPermission(PermissionState.None);
         sqlPermission.Add(connectString1, "", KeyRestrictionBehavior.AllowOnly);

         permissions.AddPermission(sqlPermission);

         AppDomain secondDomain = AppDomain.CreateDomain("OneSqlPermission", null, appDomainSetup, permissions);
         PartialTrustHelper secondHelper = (PartialTrustHelper)secondDomain.CreateInstanceAndUnwrap(helperType.Assembly.FullName, helperType.FullName);

         // Try connection open again, it should succeed now.
         try {
            secondHelper.TestConnectionOpen(connectString1);
            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 {
            secondHelper.TestConnectionOpen(connectString2);
            Console.WriteLine("Connection opened, unexpected.");
         }
         catch (System.Security.SecurityException ex) {
            Console.WriteLine("Failed, as expected: {0}", ex.Message);
         }
      }
   }
}
Imports System.Data
Imports System.Data.SqlClient
Imports System.Security
Imports System.Security.Permissions

Namespace PartialTrustTopic
    Public Class PartialTrustHelper
        Inherits MarshalByRefObject
        Public Sub TestConnectionOpen(ByVal connectionString As String)
            ' Try to open a connection.
            Using connection As New SqlConnection(connectionString)
                connection.Open()
            End Using
        End Sub
    End Class

    Class Program
        Public Shared Sub Main(ByVal args As String())
            TestCAS("Data Source=(local);Integrated Security=true", "Data Source=(local);Integrated Security=true;Initial Catalog=Test")
        End Sub

        Public Shared Sub TestCAS(ByVal connectString1 As String, ByVal connectString2 As String)
            ' Create permission set for sandbox AppDomain.
            ' This example only allows execution.
            Dim permissions As New PermissionSet(PermissionState.None)
            permissions.AddPermission(New SecurityPermission(SecurityPermissionFlag.Execution))

            ' Create sandbox AppDomain with permission set that only allows execution,
            ' and has no SqlClientPermissions.
            Dim appDomainSetup As New AppDomainSetup()
            appDomainSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase
            Dim firstDomain As AppDomain = AppDomain.CreateDomain("NoSqlPermissions", Nothing, appDomainSetup, permissions)

            ' Create helper object in sandbox AppDomain so that code can be executed in that AppDomain.
            Dim helperType As Type = GetType(PartialTrustHelper)
            Dim firstHelper As PartialTrustHelper = DirectCast(firstDomain.CreateInstanceAndUnwrap(helperType.Assembly.FullName, helperType.FullName), PartialTrustHelper)

            Try
                ' Attempt to open a connection in the sandbox AppDomain.
                ' This is expected to fail.
                firstHelper.TestConnectionOpen(connectString1)
                Console.WriteLine("Connection opened, unexpected.")
            Catch ex As System.Security.SecurityException

                ' Uncomment the following line to see Exception details.
                ' Console.WriteLine("BaseException: " + ex.GetBaseException());
                Console.WriteLine("Failed, as expected: {0}", ex.FirstPermissionThatFailed)
            End Try

            ' Add permission for a specific connection string.
            Dim sqlPermission As New SqlClientPermission(PermissionState.None)
            sqlPermission.Add(connectString1, "", KeyRestrictionBehavior.AllowOnly)

            permissions.AddPermission(sqlPermission)

            Dim secondDomain As AppDomain = AppDomain.CreateDomain("OneSqlPermission", Nothing, appDomainSetup, permissions)
            Dim secondHelper As PartialTrustHelper = DirectCast(secondDomain.CreateInstanceAndUnwrap(helperType.Assembly.FullName, helperType.FullName), PartialTrustHelper)

            ' Try connection open again, it should succeed now.
            Try
                secondHelper.TestConnectionOpen(connectString1)
                Console.WriteLine("Connection opened, as expected.")
            Catch ex As System.Security.SecurityException
                Console.WriteLine("Unexpected failure: {0}", ex.Message)
            End Try

            ' Try a different connection string. This should fail.
            Try
                secondHelper.TestConnectionOpen(connectString2)
                Console.WriteLine("Connection opened, unexpected.")
            Catch ex As System.Security.SecurityException
                Console.WriteLine("Failed, as expected: {0}", ex.Message)
            End Try
        End Sub
    End Class
End Namespace

Du bör se dessa utdata i konsolfönstret:

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.  

Samverkan med ohanterad kod

Kod som körs utanför CLR kallas ohanterad kod. Därför kan säkerhetsmekanismer som CAS inte tillämpas på ohanterad kod. COM-komponenter, ActiveX-gränssnitt och Windows API-funktioner är exempel på ohanterad kod. Särskilda säkerhetsöverväganden gäller vid körning av ohanterad kod så att du inte äventyrar den övergripande programsäkerheten. Mer information finns i Interoperating with Unmanaged Code (Samverka med ohanterad kod).

.NET Framework stöder även bakåtkompatibilitet med befintliga COM-komponenter genom att ge åtkomst via COM-interop. Du kan införliva COM-komponenter i ett .NET Framework-program med hjälp av COM-interopverktyg för att importera relevanta COM-typer. När com-typerna har importerats är de redo att användas. COM-interop gör också att COM-klienter kan komma åt hanterad kod genom att exportera sammansättningsmetadata till ett typbibliotek och registrera den hanterade komponenten som en COM-komponent. Mer information finns i Avancerad COM-samverkan.

Se även