セキュリティの基本概念

注意

この記事は Windows に適用されます。

ASP.NET Core の詳細については、「ASP.NET Core セキュリティの概要」を参照してください。

.NET では、モバイル コードに関するセキュリティへの対応を支援し、各ユーザーにどのような権限を与えるかをコンポーネントで決定できるようにするためのサポートを提供するロールベース セキュリティがあります。

タイプ セーフとセキュリティ

タイプ セーフなコードは、アクセス権限を与えられているメモリ位置にだけアクセスします。 この場合のタイプ セーフとは、メモリのタイプ セーフの意味です。広い意味でのタイプ セーフと混同しないでください。たとえば、タイプ セーフなコードは、他のオブジェクトのプライベート フィールドから値を読み取ることができません。 適切に定義された許容される方法でだけ、タイプにアクセスします。

ジャスト イン タイム (JIT: Just-In-Time) コンパイル時に、オプションの検査プロセスは、ネイティブなマシン コードに JIT コンパイルされるメソッドのメタデータと共通中間言語 (CIL) を調べて、タイプ セーフかどうかを確認します。 コードに検査を省略するためのアクセス許可がある場合、このプロセスは省略されます。 検査の詳細については、「マネージド実行プロセス」を参照してください。

タイプ セーフの検査はマネージド コードの実行に必須ではありませんが、アセンブリの分離とセキュリティの適用において、タイプ セーフであることが重要な意味を持ちます。 コードがタイプ セーフであると、共通言語ランタイムはアセンブリを互いに完全に分離できます。 アセンブリが互いに分離していると、アセンブリどうしが悪い影響を及ぼしあうことがなく、アプリケーションの信頼性が向上します。 タイプ セーフなコンポーネントは、信頼されるレベルが異なっていても、同じプロセスで安全に実行できます。 コードがタイプ セーフでないと、望ましくない副作用が生じることがあります。 たとえば、ランタイムは、マネージド コードがネイティブ (アンマネージ) コードにアクセスしたり、不正な操作を実行することを防止できません。 コードがタイプ セーフであると、ランタイムのセキュリティ適用機構によって、必要なアクセス許可を持たないコードがネイティブ コードにアクセスすることはできません。 タイプ セーフでないすべてのコードは、列挙子メンバー SecurityPermission が渡された SkipVerification を与えられていないと実行できません。

Note

コード アクセス セキュリティ (CAS) は、.NET Framework と .NET のすべてのバージョンで非推奨になりました。 最近のバージョンの .NET では、CAS 関連の API が使われている場合、CAS の注釈は使われず、エラーが発生します。 開発者は、代わりの手段を見つけてセキュリティ タスクを実現する必要があります。

プリンシパル

プリンシパルは、ユーザーの ID とロールを表し、ユーザーの代わりを務めます。 .NET のロール ベース セキュリティでは、次の 3 種類のプリンシパルがサポートされています。

  • 汎用プリンシパルは、Windows のユーザーとロールとは無関係に存在するユーザーとロールを表します。

  • Windows プリンシパルは、Windows のユーザーとそのロール (または Windows グループ) を表します。 Windows プリンシパルは、他のユーザーを偽装できます。つまり、Windows プリンシパルは、あるユーザーに属する ID を提示し、そのユーザーの代わりにリソースにアクセスできます。

  • カスタム プリンシパルは、アプリケーションが必要に応じて自由に定義できます。 カスタム プリンシパルによって、プリンシパルの ID とロールの基本概念を拡張できます。

詳しくは、「プリンシパル オブジェクトと ID オブジェクト」をご覧ください。

認証

認証とは、ユーザーの資格情報を調べ、資格情報をなんらかの権限に対して検証することによって、プリンシパルの身元 を発見および確認するプロセスです。 認証時に得られる情報は、コードで直接使用できます。 また、.NET のロール ベース セキュリティを使用して、現在のユーザーを認証したり、そのプリンシパルにコードへのアクセスを許可するかどうかを判断したりできます。 特定のロールに関してプリンシパルを認証する方法の例については、WindowsPrincipal.IsInRole メソッドのオーバーロードを参照してください。 たとえば、WindowsPrincipal.IsInRole(String) オーバーロードを使用すると、現在のユーザーが Administrators グループのメンバーであるかどうかを判断できます。

さまざまな認証メカニズムが現在使用されていて、その多くを .NET のロール ベース セキュリティと一緒に使用できます。 最も一般に使用されている認証機構としては、基本認証、ダイジェスト認証、パスポート認証、オペレーティング システム認証 (NTLM 認証や Kerberos 認証など)、およびアプリケーション定義の認証機構などがあります。

以下の例では、アクティブ プリンシパルが管理者である必要があります。 name パラメーターは null で、これにより、管理者ユーザーがこの確認要求を渡すことを許可されます。

Note

Windows Vista では、ユーザー アカウント制御 (UAC: User Account Control) でユーザーの権限が決定されます。 ユーザーが組み込みの Administrators グループのメンバーである場合、そのユーザーには標準ユーザー アクセス トークンおよび管理者アクセス トークンの 2 つのランタイム アクセス トークンが割り当てられています。 既定では、ユーザーは標準ユーザー ロールに所属します。 管理者であることを要求するコードを実行するには、最初に、ユーザーの権限を標準ユーザーから管理者に昇格させる必要があります。 この操作は、アプリケーションの起動時にアプリケーション アイコンを右クリックし、管理者として実行することを指定して行うことができます。

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

次の例は、プリンシパルの ID と、プリンシパルで使用できるロールを判別する方法を示しています。 この例のアプリケーションは、現在のユーザーがアプリケーションの使用を許可するロールに含まれていることを確認できます。

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

承認

承認とは、要求されたアクションの実行をプリンシパルに許可するかどうかを判断するプロセスです。 承認は認証の後に行われ、プリンシパルの ID とロールについての情報を使用して、そのプリンシパルがアクセスできるリソースを判断します。 認可は、.NET のロール ベース セキュリティを使用して実装できます。

関連項目