Conceitos principais de segurança
Observação
Este artigo aplica-se ao Windows.
Para obter informações sobre o ASP.NET Core, consulte a Visão geral da segurança do ASP.NET Core.
O .NET oferece segurança baseada em função, para ajudar a resolver as preocupações de segurança sobre o código móvel e dar suporte para permitir que os componentes determinem o que os usuários estão autorizados a fazer.
Segurança de tipos e proteção
O código fortemente tipado acessa apenas os locais de memória que está autorizado a acessar. (Para essa discussão, a segurança de tipos refere-se especificamente à segurança de tipos de memória e não deve ser confundida com a segurança de tipos em um aspecto mais abrangente.) Por exemplo, o código fortemente tipado não pode ler os valores dos campos privados de outro objeto. Ele acessa os tipos apenas de maneiras bem definidas e permitidas.
Durante a compilação JIT, um processo de verificação opcional examina os metadados e a CIL (Linguagem Intermediária Comum) de um método a ser submetido à compilação JIT em código de computador nativo, para verificar se eles são fortemente tipados. Esse processo será ignorado, se o código tiver permissão para ignorar a verificação. Para obter mais informações sobre verificação, confira Processo de Execução Gerenciada.
Embora a verificação da segurança de tipos não seja obrigatória para executar o código gerenciado, a segurança de tipos desempenha um papel fundamental no isolamento do assembly e na imposição de segurança. Quando o código é fortemente tipado, o Common Language Runtime pode isolar completamente os assemblies uns dos outros. Esse isolamento ajuda a garantir que os assemblies não afetem negativamente uns aos outros e aumenta a confiabilidade do aplicativo. Os componentes fortemente tipados podem ser executados com segurança no mesmo processo, mesmo que sejam confiáveis em níveis diferentes. Quando o código não é fortemente tipado, efeitos colaterais indesejados podem ocorrer. Por exemplo, o runtime não pode impedir que o código gerenciado chame o código nativo (não gerenciado) e execute operações mal-intencionadas. Quando o código é fortemente tipado, o mecanismo de imposição de segurança do runtime garante que ele não acesse o código nativo, a menos que tenha permissão para tanto. Todo o código que não fortemente tipado deve receber SecurityPermission com o membro de enumeração aprovado SkipVerification para execução.
Observação
O CAS (Segurança de Acesso do Código) foi preterido em todas as versões do .NET Framework e do .NET. As versões recentes do .NET não aceitam anotações de CAS e produzem erros caso as APIs relacionadas ao CAS sejam usadas. Os desenvolvedores devem buscar meios alternativos de realizar tarefas de segurança.
Principal
Uma entidade de segurança representa a identidade e a função de um usuário e atua em nome do usuário. A segurança baseada em função no .NET permite três tipos de entidades de segurança:
As entidades de segurança genéricas representam usuários e funções que existem independentemente de usuários e funções do Windows.
As entidades de segurança do Windows representam usuários do Windows e suas funções (ou seus grupos do Windows). Uma entidade de segurança do Windows pode representar outro usuário, o que significa que a entidade de segurança pode acessar um recurso em nome de um usuário, ao apresentar a identidade que pertence a esse usuário.
As entidades de segurança personalizadas podem ser definidas por um aplicativo de qualquer forma necessária para esse aplicativo específico. Elas podem estender as noções básicas da identidade e das funções da entidade de segurança.
Para obter mais informações, confira Objetos de entidade de segurança e de identidade.
Autenticação
Autenticação é o processo de descobrir e verificar a identidade de uma entidade de segurança, examinando as credenciais do usuário e validando essas credenciais em relação a determinada autoridade. As informações obtidas durante a autenticação podem ser diretamente utilizáveis pelo código. Você também pode usar a segurança baseada em função do .NET, para autenticar o usuário atual e determinar se deseja permitir que essa entidade de segurança acesse o código. Confira as sobrecargas do método WindowsPrincipal.IsInRole para obter exemplos de como autenticar a entidade de segurança para funções específicas. Por exemplo, você pode usar a sobrecarga WindowsPrincipal.IsInRole(String) para determinar se o usuário atual é membro do grupo Administradores.
Uma variedade de mecanismos de autenticação são usados atualmente. Muitos deles podem ser usados com a segurança baseada em função do .NET. Alguns dos mecanismos mais usados são mecanismos básicos, digest, Passport, sistema operacional (como NTLM ou Kerberos) ou definidos pelo aplicativo.
Exemplo
O exemplo a seguir exige que a entidade de segurança ativa seja um administrador. O parâmetro name
é null
, o que permite que qualquer usuário que seja um administrador passe a demanda.
Observação
No Windows Vista, o UAC (Controle de Conta de Usuário) determina os privilégios de um usuário. Se for um membro do grupo Administradores Internos, você receberá dois tokens de acesso do tempo de execução: um token de acesso do usuário padrão e um token de acesso do administrador. Por padrão, você está na função de usuário padrão. Para executar o código que exige que você seja um administrador, você deve primeiro elevar os privilégios de usuário padrão para administrador. Você pode fazer isso ao iniciar um aplicativo, clicando com o botão direito do mouse no ícone do aplicativo e indicando que você deseja executar como administrador.
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
O exemplo a seguir demonstra como determinar a identidade da entidade de segurança e as funções disponíveis para a entidade de segurança. Um aplicativo deste exemplo pode ser usado para confirmar que o usuário atual está em uma função que você permite que use o aplicativo.
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
Autorização
Autorização é o processo de determinar se uma entidade de segurança tem permissão para executar uma ação solicitada. A autorização ocorre após a autenticação e usa informações sobre a identidade e as funções da entidade de segurança, para determinar quais recursos a entidade de segurança pode acessar. Você pode usar a segurança baseada em função do .NET para implementar a autorização.