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.
Behörigheter för begäran
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.
Starka namngivna sammansättningar
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.
Delvis 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 niska veze. 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 niska veze. Flera niska veze kan identifieras. Obs! Inkludera inte ett användar-ID eller lösenord i din niska veze. I den här versionen kan du inte ändra niska veze begränsningar med hjälp av konfigurationsverktyget för .NET Framework. Ärvd från DBDataPermissionAttribute. |
KeyRestrictions |
Identifierar niska veze parametrar som tillåts eller inte tillåts. Anslutningssträngsparametrar identifieras i formuläret <parameternamn>=. 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 niska veze parametrar. Ärvd från DBDataPermissionAttribute. |
KeyRestrictionBehavior |
Identifierar de niska veze 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. |
ConnectionString-syntax
I följande exempel visas hur du använder -elementet i connectionStrings
en konfigurationsfil för att endast tillåta att en specifik niska veze används. Mer information om hur du lagrar och hämtar niska veze från konfigurationsfiler finns i Anslutningssträngar.
<connectionStrings>
<add name="DatabaseConnection"
connectionString="Data Source=(local);Initial
Catalog=Northwind;Integrated Security=true;" />
</connectionStrings>
Viktigt!
Microsoft rekommenderar att du använder det säkraste tillgängliga autentiseringsflödet. Om du ansluter till Azure SQL är hanterade identiteter för Azure-resurser den rekommenderade autentiseringsmetoden.
KeyRestrictions-syntax
Följande exempel aktiverar samma niska veze, möjliggör användning av Encrypt
alternativen och Packet Size
niska veze, men begränsar användningen av andra niska veze alternativ.
<connectionStrings>
<add name="DatabaseConnection"
connectionString="Data Source=(local);Initial
Catalog=Northwind;Integrated Security=true;"
KeyRestrictions="Encrypt=;Packet Size=;"
KeyRestrictionBehavior="AllowOnly" />
</connectionStrings>
Viktigt!
Microsoft rekommenderar att du använder det säkraste tillgängliga autentiseringsflödet. Om du ansluter till Azure SQL är hanterade identiteter för Azure-resurser den rekommenderade autentiseringsmetoden.
KeyRestrictionBehavior med PreventUsage-syntax
Följande exempel aktiverar samma niska veze 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>
Viktigt!
Microsoft rekommenderar att du använder det säkraste tillgängliga autentiseringsflödet. Om du ansluter till Azure SQL är hanterade identiteter för Azure-resurser den rekommenderade autentiseringsmetoden.
KeyRestrictionBehavior med AllowOnly-syntax
I följande exempel aktiveras två niska veze som också innehåller Initial Catalog
parametrarna , Connection Timeout
, Encrypt
och Packet Size
. Alla andra niska veze 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>
Viktigt!
Microsoft rekommenderar att du använder det säkraste tillgängliga autentiseringsflödet. Om du ansluter till Azure SQL är hanterade identiteter för Azure-resurser den rekommenderade autentiseringsmetoden.
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 LocalIntranet
kan 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>
Viktigt!
Microsoft rekommenderar att du använder det säkraste tillgängliga autentiseringsflödet. Om du ansluter till Azure SQL är hanterade identiteter för Azure-resurser den rekommenderade autentiseringsmetoden.
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 niska veze. 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 niska veze. Om du till exempel börjar med alla behörigheter och sedan försöker neka användningen av niska veze "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("secure-connnection-string1", "secure-connnection-string2");
}
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.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.
Viktigt!
Microsoft rekommenderar att du använder det säkraste tillgängliga autentiseringsflödet. Om du ansluter till Azure SQL är hanterade identiteter för Azure-resurser den rekommenderade autentiseringsmetoden.
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.