Concepts fondamentaux sur la sécurité
Notes
Cet article s’applique à Windows.
Pour plus d’informations sur ASP.NET Core, consultez Présentation de la sécurité ASP.NET Core.
.NET offre la sécurité basée sur les rôles pour aider à résoudre les problèmes de sécurité relatifs au code mobile et pour permettre aux composants de déterminer ce que les utilisateurs sont autorisés à faire.
Sécurité de type et sécurité
Le code de type sécurisé accède uniquement aux emplacements de mémoire auxquels il est autorisé à accéder. (Dans le cadre de cette présentation, la sécurité de type fait spécifiquement référence à la sécurité de type de la mémoire et ne doit pas être confondue avec la sécurité de type dans un contexte plus large.) Par exemple, le code de type sécurisé ne peut pas lire les valeurs des champs privés d’un autre objet. Il accède aux types uniquement de manière autorisée et bien définie.
Pendant la compilation juste-à-temps (JIT, Just-In-Time), un processus de vérification facultatif examine les métadonnées et le langage CIL (Common Intermediate Language) d’une méthode devant subir une compilation JIT en code machine natif pour vérifier qu’ils sont sécurisés du point de vue des types. Ce processus est omis si le code est autorisé à ignorer la vérification. Pour plus d’informations sur la vérification, consultez Processus d’exécution managée.
Bien que la vérification de sécurité de type ne soit pas obligatoire pour exécuter du code managé, la sécurité de type joue un rôle crucial dans l'isolation des assemblys et dans la mise en œuvre de la sécurité. Quand le code est de type sécurisé, le Common Language Runtime peut isoler totalement les assemblys les uns des autres. Cette isolation permet de s'assurer que les assemblys ne peuvent pas nuire les uns aux autres et augmente la fiabilité des applications. Les composants de type sécurisé peuvent s'exécuter en toute sécurité dans le même processus, même s'ils sont approuvés à différents niveaux. Quand le code n'est pas de type sécurisé, des effets secondaires indésirables peuvent se produire. Par exemple, le runtime ne peut pas empêcher du code managé d'appeler du code natif (non managé) et d'exécuter des opérations nuisibles. Quand le code est de type sécurisé, le mécanisme de sécurité du runtime garantit qu'il n'accède pas à du code natif, sauf s'il a l'autorisation de le faire. Tout le code qui n'est pas de type sécurisé ne peut s'exécuter que s'il a obtenu l'autorisation SecurityPermission avec le membre d'énumération transmis SkipVerification.
Notes
La sécurité d’accès du code (CAS) a été déconseillée dans toutes les versions du .NET Framework et de .NET. Les versions récentes de .NET ne respectent pas les annotations CAS et produisent des erreurs si les API liées à CAS sont utilisées. Les développeurs doivent chercher d’autres moyens pour accomplir les tâches liées à la sécurité.
Principal
Un principal représente l'identité et le rôle d'un utilisateur et agit au nom de l'utilisateur. .NET, la sécurité basée sur les rôles prend en charge trois types de principaux :
Les principaux génériques représentent les utilisateurs et les rôles qui existent indépendamment des utilisateurs et des rôles Windows.
Les principaux Windows représentent les utilisateurs et les rôles Windows (ou leurs groupes Windows). Un principal Windows peut emprunter l'identité d'un autre utilisateur, ce qui signifie qu'il peut accéder à une ressource sous le nom d'un utilisateur tout en présentant l'identité de l'autre utilisateur.
Les principaux personnalisés peuvent être définis par une application, en fonction des besoins de celle-ci. Ils peuvent étendre les notions de base applicables à l'identité et aux rôles du principal.
Pour plus d’informations, consultez Objets Principal et Identity.
Authentification
Le processus d'authentification consiste à établir et à vérifier l'identité d'un principal en examinant les informations d'identification de l'utilisateur et en les validant auprès de l'autorité appropriée. Votre code peut utiliser directement les informations obtenues au cours de l'authentification. Vous pouvez également utiliser la sécurité basée sur les rôles de .NET pour authentifier l’utilisateur actuel et déterminer s’il faut ou non autoriser ce principal à accéder à votre code. Consultez les surcharges de la méthode WindowsPrincipal.IsInRole pour obtenir des exemples d'authentification du principal pour des rôles spécifiques. Par exemple, vous pouvez utiliser la surcharge WindowsPrincipal.IsInRole(String) pour déterminer si l'utilisateur actuel est membre du groupe Administrateurs.
De nombreux mécanismes d’authentification sont utilisés de nos jours et la majorité d’entre eux peuvent être utilisés avec la sécurité basée sur les rôles de .NET. Parmi les mécanismes les plus courants figurent notamment Basic, Digest, Passport, les mécanismes liés aux systèmes d'exploitation (tels que NTLM ou Kerberos) ou encore ceux définis par les applications.
Exemple
L'exemple suivant nécessite que le principal actif soit un administrateur. Le paramètre name
est null
, qui autorise tout utilisateur ayant la qualité d'administrateur à passer la demande.
Notes
Dans Windows Vista, le contrôle de compte d'utilisateur détermine les privilèges d'un utilisateur. Si vous êtes membre du groupe Administrateurs intégrés, deux jetons d'accès au moment de l'exécution vous sont assignés : un jeton d'accès utilisateur standard et un jeton d'accès administrateur. Par défaut, vous êtes dans le rôle d'utilisateur standard. Pour exécuter le code nécessitant que vous soyez administrateur, vous devez d'abord élever vos privilèges d'utilisateur standard à administrateur. Vous pouvez effectuer cela au démarrage d'une application en cliquant avec le bouton droit sur l'icône de l'application et en indiquant que vous voulez l'exécuter en tant qu'administrateur.
using namespace System;
using namespace System::Security;
using namespace System::Security::Permissions;
using namespace System::Security::Policy;
using namespace System::Security::Principal;
int main(array<System::String ^> ^args)
{
System::String^ null;
AppDomain::CurrentDomain->SetPrincipalPolicy(PrincipalPolicy::WindowsPrincipal);
PrincipalPermission^ principalPerm = gcnew PrincipalPermission(null, "Administrators" );
principalPerm->Demand();
Console::WriteLine("Demand succeeded");
return 0;
}
using System;
using System.Threading;
using System.Security.Permissions;
using System.Security.Principal;
class SecurityPrincipalDemo
{
public static void Main()
{
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
PrincipalPermission principalPerm = new PrincipalPermission(null, "Administrators");
principalPerm.Demand();
Console.WriteLine("Demand succeeded.");
}
}
Imports System.Threading
Imports System.Security.Permissions
Imports System.Security.Principal
Class SecurityPrincipalDemo
Public Shared Sub Main()
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal)
Dim principalPerm As New PrincipalPermission(Nothing, "Administrators")
principalPerm.Demand()
Console.WriteLine("Demand succeeded.")
End Sub
End Class
L'exemple suivant montre comment déterminer l'identité du principal et les rôles disponibles pour celui-ci. Une application de cet exemple peut consister à confirmer que le rôle de l'utilisateur actuel l'autorise à utiliser votre application.
public:
static void DemonstrateWindowsBuiltInRoleEnum()
{
AppDomain^ myDomain = Thread::GetDomain();
myDomain->SetPrincipalPolicy( PrincipalPolicy::WindowsPrincipal );
WindowsPrincipal^ myPrincipal = dynamic_cast<WindowsPrincipal^>(Thread::CurrentPrincipal);
Console::WriteLine( "{0} belongs to: ", myPrincipal->Identity->Name );
Array^ wbirFields = Enum::GetValues( WindowsBuiltInRole::typeid );
for each ( Object^ roleName in wbirFields )
{
try
{
Console::WriteLine( "{0}? {1}.", roleName,
myPrincipal->IsInRole( *dynamic_cast<WindowsBuiltInRole^>(roleName) ) );
}
catch ( Exception^ )
{
Console::WriteLine( "{0}: Could not obtain role for this RID.",
roleName );
}
}
}
using System;
using System.Threading;
using System.Security.Permissions;
using System.Security.Principal;
class SecurityPrincipalDemo
{
public static void DemonstrateWindowsBuiltInRoleEnum()
{
AppDomain myDomain = Thread.GetDomain();
myDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal myPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
Console.WriteLine("{0} belongs to: ", myPrincipal.Identity.Name.ToString());
Array wbirFields = Enum.GetValues(typeof(WindowsBuiltInRole));
foreach (object roleName in wbirFields)
{
try
{
// Cast the role name to a RID represented by the WindowsBuildInRole value.
Console.WriteLine("{0}? {1}.", roleName,
myPrincipal.IsInRole((WindowsBuiltInRole)roleName));
Console.WriteLine("The RID for this role is: " + ((int)roleName).ToString());
}
catch (Exception)
{
Console.WriteLine("{0}: Could not obtain role for this RID.",
roleName);
}
}
// Get the role using the string value of the role.
Console.WriteLine("{0}? {1}.", "Administrators",
myPrincipal.IsInRole("BUILTIN\\" + "Administrators"));
Console.WriteLine("{0}? {1}.", "Users",
myPrincipal.IsInRole("BUILTIN\\" + "Users"));
// Get the role using the WindowsBuiltInRole enumeration value.
Console.WriteLine("{0}? {1}.", WindowsBuiltInRole.Administrator,
myPrincipal.IsInRole(WindowsBuiltInRole.Administrator));
// Get the role using the WellKnownSidType.
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
Console.WriteLine("WellKnownSidType BuiltinAdministratorsSid {0}? {1}.", sid.Value, myPrincipal.IsInRole(sid));
}
public static void Main()
{
DemonstrateWindowsBuiltInRoleEnum();
}
}
Imports System.Threading
Imports System.Security.Permissions
Imports System.Security.Principal
Class SecurityPrincipalDemo
Public Shared Sub DemonstrateWindowsBuiltInRoleEnum()
Dim myDomain As AppDomain = Thread.GetDomain()
myDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal)
Dim myPrincipal As WindowsPrincipal = CType(Thread.CurrentPrincipal, WindowsPrincipal)
Console.WriteLine("{0} belongs to: ", myPrincipal.Identity.Name.ToString())
Dim wbirFields As Array = [Enum].GetValues(GetType(WindowsBuiltInRole))
Dim roleName As Object
For Each roleName In wbirFields
Try
' Cast the role name to a RID represented by the WindowsBuildInRole value.
Console.WriteLine("{0}? {1}.", roleName, myPrincipal.IsInRole(CType(roleName, WindowsBuiltInRole)))
Console.WriteLine("The RID for this role is: " + Fix(roleName).ToString())
Catch
Console.WriteLine("{0}: Could not obtain role for this RID.", roleName)
End Try
Next roleName
' Get the role using the string value of the role.
Console.WriteLine("{0}? {1}.", "Administrators", myPrincipal.IsInRole("BUILTIN\" + "Administrators"))
Console.WriteLine("{0}? {1}.", "Users", myPrincipal.IsInRole("BUILTIN\" + "Users"))
' Get the role using the WindowsBuiltInRole enumeration value.
Console.WriteLine("{0}? {1}.", WindowsBuiltInRole.Administrator, myPrincipal.IsInRole(WindowsBuiltInRole.Administrator))
' Get the role using the WellKnownSidType.
Dim sid As New SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, Nothing)
Console.WriteLine("WellKnownSidType BuiltinAdministratorsSid {0}? {1}.", sid.Value, myPrincipal.IsInRole(sid))
End Sub
Public Shared Sub Main()
DemonstrateWindowsBuiltInRoleEnum()
End Sub
End Class
Autorisation
L'autorisation est le processus qui consiste à déterminer si un principal est autorisé à exécuter l'opération demandée. L'autorisation a lieu après l'authentification, et utilise les informations se rapportant à l'identité et aux rôles du principal pour déterminer les ressources auxquelles il peut avoir accès. Vous pouvez utiliser la sécurité basée sur les rôles de .NET pour l’implémentation de l’autorisation.