EXECUTE AS の使用によるデータベースの権限借用の拡張

SQL Server では、単独の EXECUTE AS ステートメントを明示的に使用するか、モジュール内で EXECUTE AS 句を暗黙的に使用することで、他のプリンシパルの権限を借用できる機能がサポートされます。単独の EXECUTE AS ステートメントは、EXECUTE AS LOGIN ステートメントを使用してサーバー レベルのプリンシパル (ログイン) の権限を借用するために使用します。また、EXECUTE AS USER ステートメントを使用してデータベース レベルのプリンシパル (ユーザー) の権限を借用するためにも使用します。

モジュール内の EXECUTE AS 句で行われる暗黙の権限借用は、指定したユーザーまたはログインの権限をデータベース レベルまたはサーバー レベルで借用します。この権限借用は、ストアド プロシージャ、関数などのデータベース レベルのモジュールか、サーバー レベルのトリガなどのサーバー レベルのモジュールのいずれかに依存します。

権限借用のスコープについて

EXECUTE AS LOGIN ステートメントを使用する場合や、サーバー スコープのモジュール内で EXECUTE AS 句を使用してプリンシパルの権限を借用する場合、権限借用のスコープはサーバー全体になります。つまり、いずれかの方法でコンテキストを切り替えた後は、サーバー内にある、権限借用したログインがアクセス許可を持っているすべてのリソースに、アクセスできるようになります。

ただし、EXECUTE AS USER ステートメントを使用するか、またはデータベース スコープのモジュール内で EXECUTE AS 句を使用して、プリンシパルの権限を借用した場合、権限借用の既定のスコープはそのデータベースに制限されます。つまり、データベースのスコープ外のオブジェクトを参照するとエラーが返されます。このような既定動作になった理由を理解するために、次のシナリオを考えてみましょう。

データベースの所有者がデータベース内では完全なアクセス許可を持っているにもかかわらず、データベースのスコープ外にはまったくアクセス許可がない場合があります。そのため、データベース所有者が現在のアクセス許可のスコープ外のリソースにアクセスするために、他のユーザーの権限を借用する、または第三者に権限借用を許可することは、SQL Server では許可されません。

たとえば、あるホスティング環境に 2 つのデータベースがあり、それぞれのデータベースを所有するエンティティが異なるとします。データベース1 の所有者は Bob で、データベース2 の所有者は Fred です。Bob も Fred も、互いに自分のデータベース内のリソースにはアクセスしてほしくありません。データベース1 の所有者である Bob はデータベース内に Fred に相当するユーザーを作成できます。Bob はデータベース 1 内に完全なアクセス許可があるので、ユーザー Fred の権限を借用できます。しかし、SQL Server によりセキュリティの制限が課せられるので、権限を借用したコンテキストでも Bob が Fred のデータベースにアクセスすることはできません。この既定の制限が適切に行われないと、Bob は Fred に知られることなく Fred のデータにアクセスできてしまいます。このような理由から、既定ではデータベース レベルの権限借用のスコープはそのデータベースに制限されます。

ただし、権限借用のスコープを選択的にデータベース外部まで拡張できるようにすることが便利な場合もあります。たとえば、あるアプリケーションで 2 つのデータベースを使用していて、一方のデータベースからもう一方のデータベースにアクセスする必要がある場合です。

あるマーケティング用アプリケーションで Marketing データベースの GetSalesProjections というストアド プロシージャを呼び出す場合を考えてみます。このストアド プロシージャには実行コンテキストの切り替えが定義されています。このストアド プロシージャで Sales データベースを呼び出し、SalesStats テーブルから売上情報を取得します。既定では、あるデータベースで確立された実行コンテキストはそのデータベースの外では無効になるので、このシナリオは機能しません。しかし、ユーザーが Sales データベースに直接アクセスしたり、その中のオブジェクトに対するアクセス許可を持っていることは、このマーケティング用アプリケーションの開発者にとって望ましくありません。理想的には、ストアド プロシージャで EXECUTE AS 句を使用して、Sales データベースに必要なアクセス許可のあるユーザーの権限を借用するのが適切なソリューションです。ただし、現行では既定の制限により、それができません。このため、どのようにこの問題を解決するかは開発者にとっての課題になります。

SQL Server では、2 つのデータベースの間に信頼モデルを確立することで、あるデータベース内で確立したデータベース権限借用のスコープを選択的に拡張できます。ただし、信頼モデルと権限借用のスコープを選択的に拡張する方法について説明する前に、認証とは何か、および SQL Server の認証子の役割について理解しておく必要があります。

認証子について

認証とは、特定のプリンシパルの身元を確立し、システムに証明するプロセスです。認証子とは、特定のプリンシパルの正当性を認証、つまり保証するエンティティです。たとえば、SQL Server に接続が行われるとき、その接続で使用するために確立したログインが SQL Server のインスタンスによって認証されます。

ユーザーが EXECUTE AS LOGIN ステートメントを使用してコンテキストをサーバー レベルで明示的に切り替える場合を考えてみます。切り替えには、サーバー レベルで権限を借用する権限が必要です。その権限があると、権限を与えられた EXECUTE AS LOGIN ステートメントの呼び出し元は、SQL Server インスタンス内であればどこでも、指定されたログインの権限を借用できます。実際に、ステートメントの呼び出し元は、権限借用対象のログインとしてログインする動作をシミュレートできます。サーバー レベルのスコープの権限の所有者は SQL Server インスタンスの所有者である sysadmin です。このサーバー レベルの権限借用の例では、sysadmin または SQL Server インスタンス自体が認証子です。

一方、EXECUTE AS USER ステートメントまたはデータベース スコープのモジュールの EXECUTE AS 句によってコンテキストが確立される場合を考えてみます。この場合、データベース スコープ内での権限借用の権限が確認されます。ユーザーの IMPERSONATE 権限の既定のスコープはデータベース自体で、その所有者は dbo です。また、権限借用の認証子はデータベース所有者です。また、権限借用元ユーザーの ID やその正当性を保証するのも事実上、データベース所有者です。データベース所有者はデータベース全体を所有しているので、そのデータベース内であればどこでも権限を借用したコンテキストは正当と見なされます。ただし、この権限を借用したコンテキストはデータベースの外部では無効です。

認証子の使用方法

認証子は、確立されたコンテキストが特定のスコープ内で有効かどうかを判断するために使用されます。多くの場合、識別子は SA (システム管理者) または SQL Server インスタンスです。また、データベースの場合は dbo です。事実上の認証子は、特定のユーザーまたはログインのコンテキストが確立されるスコープの所有者です。この認証子の情報は、ログインやユーザーのトークン情報内にキャプチャされ、sys.user_token ビューと sys.login_token ビューから表示できます。詳細については、「実行コンテキストについて」を参照してください。

注意

トークン ビューに認証子の情報が返されない場合、認証子は SQL Server インスタンスです。コンテキストの切り替えがない場合、または権限借用がサーバー レベルの場合がこれに該当します。

スコープの所有者を認証子とする実行コンテキストは、スコープ全体で有効です。スコープの所有者 (データベースなど) はスコープ内のすべてのエンティティから暗黙的に信頼されるためです。認識子を信頼している他のスコープ (他のデータベース、SQL Server インスタンス自体など) でもその認識子の実行コンテキストは有効です。したがって、権限を借用したユーザー コンテキストがデータベースのスコープ外で有効かどうかは、コンテキストの認証子が対象のスコープ内で信頼されているかどうかで決まります。信頼関係を確立するには、対象のスコープが他のデータベースの場合は AUTHENTICATE 権限を、SQL Server インスタンスの場合は AUTHENTICATE SERVER 権限を認証子に許可します。

権限借用のスコープの拡張

権限借用のスコープをデータベース内から他のデータベースや SQL Server インスタンスなど、対象のスコープに拡張するには、次の条件を満たしている必要があります。

  • 認証子は対象のスコープで信頼されている必要があります。

  • ソース データベースが信頼可能としてマークされている必要があります。

認証子に対する信頼

次の図で、先ほどの Sales データベースおよび Marketing データベースの例を使用して、Marketing データベースのストアド プロシージャ GetSalesProjectionsSales データベースの SalesStats テーブルのデータにアクセスするときの動作を説明します。ストアド プロシージャには EXECUTE AS USER MarketingExec 句が含まれています。Sales データベースの所有者は SalesDBO で、Marketing データベースの所有者は MarketingDBO です。

モジュールの実行コンテキストを切り替える EXECUTE AS

ユーザーが GetSalesProjections ストアド プロシージャを呼び出すと、EXECUTE AS 句によってストアド プロシージャの実行コンテキストがそのユーザーから MarketingExec ユーザーに暗黙的に切り替わります。このコンテキストの認証子は Marketing データベースの所有者である MarketingDBO です。既定でこのストアド プロシージャからアクセスできるリソースは、MarketingExec ユーザーがアクセスを許可されている、Marketing データベース内のすべてのリソースです。しかし、Sales データベースのテーブルにアクセスするには、Sales データベースが認証子 MarketingDBO を信頼している必要があります。

これを実現するには、Sales データベースに MarketingDBO というユーザーを作成し、MarketingDBO ログインにマッピングし、Sales データベースに対する AUTHENTICATE 権限を許可します。その結果、AUTHENTICATE 権限が許可されたユーザーを認証子とする実行コンテキストが Sales データベースで有効になります。認証子 MarketingDBO には Sales データベースで AUTHENTICATE 権限が許可されているので、Marketing データベースの GetSalesProjections ストアド プロシージャの EXECUTE AS 句によって確立されたユーザー MarketingExec のコンテキストは、Sales データベースで信頼されます。

ここまではデータベース外部のオブジェクトにアクセスするために権限借用のスコープを拡張する例でしたが、権限借用のスコープは SQL Server インスタンスにも拡張できます。たとえば、プロシージャの目的がログインを作成することであった場合は、サーバー全体のアクセス許可を必要とするサーバー レベルの操作なので、コンテキストの認証子に AUTHENTICATE SERVER 権限を許可する必要があります。AUTHENTICATE SERVER 権限を認証子に許可することは、その認証子を使用するコンテキストが、SQL Server インスタンスに直接ログインした場合と同様に SQL Server インスタンス全体で信頼されることを意味します。

データベースに対する信頼

SQL Server では、データベース レベルの権限借用のスコープを拡張する操作のセキュリティと粒度を高めるために、さらに一歩進んだ信頼モデルが実装されています。対象のスコープでコンテキストの認証子を信頼する方法として AUTHENTICATE 権限を使用することもできますが、SQL Server インスタンスでソース データベースとその内容を信頼するかどうかをユーザーが決定することもできます。

これを例示するために、MarketingDBO プリンシパルが Conference という別のデータベースを所有しているとします。また、MarketingDBOMarketing データベース内で指定した実行コンテキストに Sales データベースのリソースへのアクセス許可を与えるとします。ただし、Conference データベースで確立したコンテキストには Sales データベースへのアクセス許可を与えません。

この要件を満たすには、データベース外部のリソースにアクセスするために権限借用コンテキストを使用するモジュールを含んだデータベースを、信頼可能としてマークする必要があります。TRUSTWORTHY プロパティは、SQL Server インスタンスがデータベースとその内容を信頼するかどうかを示します。TRUSTWORTHY プロパティには次の 2 つの目的があります。

  1. 高い特権を持つユーザーのコンテキストで実行されるように定義された、悪意のあるモジュールを含む危険性のあるデータベースが、SQL Server インスタンスにアタッチされることに起因する脅威を緩和する。

    アタッチされるデータベースには既定では信頼可能のマークを付けないことで、これを実現しています。また、データベースに信頼可能というマークがなければ、潜在的に悪意のあるモジュールからデータベース外部のリソースにアクセスできないようにするという方法もあります。TRUSTWORTHY プロパティをデータベースに設定できるのは、sysadmin 固定サーバー ロールのメンバに限られます。

  2. 複数のデータベースに共通している所有者が、あるスコープで認証子として信頼されている場合に、外部リソースへのアクセスを許可するデータベースと禁止するデータベースを SQL Server インスタンスの管理者が区別できるようになる。

この動作を制御するには TRUSTWORTHY プロパティを使用します。たとえば、対象のスコープで認証子として信頼されている所有者が 2 つのデータベースを所有している場合、権限の借用で、データベース 1 のコンテキストを信頼し、データベース 2 のコンテキストを信頼しないようにするとします。TRUSTWORTHY プロパティをデータベース 1 では ON に、データベース 2 では OFF に設定すると、データベース 2 のモジュールはデータベース外部のリソースにアクセスできません。

次の図は、TRUSTWORTHY データベース プロパティを使用してソース データベースのスコープ外部のリソースへのアクセスを制御する方法を示します。MarketingDBO は、Marketing データベースと Conference データベースの所有者であり、Sales データベース内の AUTHENTICATE 権限を持っています。認証子 (MarketingDBO) が対象のスコープで信頼されており、ソース データベース (Marketing) が信頼可能であるという 2 つのセキュリティ要件を満たしているので、Marketing データベースの GetSalesProjections ストアド プロシージャは Sales データベースに正常にアクセスできます。Conference データベースは、認証子 MarketingDBO が対象のスコープで信頼されているいうセキュリティ要件しか満たしていないので、Sales データベースにアクセスすると拒否されます。

外部リソースへのデータベース アクセスの制御

権限を借用したコンテキストを使用してデータベースのスコープ外のリソースへのアクセスを試行すると、要求元のデータベースが信頼可能であるかどうかという点と、認証子が信頼できるかどうかという点が、SQL Server インスタンスによって常に検証されます。

認証子としての証明書と非対称キー

データベース所有者を認証子にすることで、データベース内で確立された権限借用コンテキストをデータベース スコープ外のリソースにアクセスできるように拡張できます。これには、外部リソースがデータベース所有者を信頼し、データベース自体も信頼可能である必要があります。ただしこの方式では、信頼されたデータベース所有者に対象のスコープでの AUTHENTICATE 権限または AUTHENTICATE SERVER 権限が許可されており、呼び出し側のデータベースが信頼可能である場合、そのデータベースで確立した権限借用コンテキストは、データベース所有者を信頼するターゲット スコープ全体で有効になってしまいます。

場合によっては、信頼レベルの粒度を細かくする必要があります。たとえば、EXECUTE AS 句を使用してターゲット リソースにアクセスすることで、ソース データベースのモジュールのうち少数のみを信頼し、ソース データベース全体は信頼しないというビジネス要件があるとします。このとき、SalesDBOGetSalesProjections ストアド プロシージャのみから MarketingExec ユーザーとして SalesStats テーブルにアクセスできるようにし、Marketing データベースで MarketingExec の権限を借用する権限のある全員には Sales データベースのリソースにアクセスさせないものとします。MarketingDBO を信頼し、Marketing データベースを信頼可能に設定するだけでは、この作業を完了できません。この要件を満たすレベルの粒度を得るため、信頼モデルでは認証子として証明書または非対称キーを使用できます。これらを使用すると、署名という技法を実装できます。署名の詳細については、「ADD SIGNATURE (Transact-SQL)」を参照してください。

署名の使用

モジュールに署名を行うと、モジュール内のコードを変更できるのは、モジュールへの署名に使用した秘密キーにアクセスできる個人のみになります。署名に指定されている証明書または非対称キーは、署名プロセスでの保証を考えると信頼可能と見なすことができます。もっと正確にいえば、データベース所有者だけでなく、証明書または非対称キーの所有者を信頼できることになります。

署名されたモジュールを信頼するには、対象のスコープで証明書または非対称キーにマップされるユーザーに AUTHENTICATE 権限または AUTHENTICATE SERVER 権限を許可します。

そうすることで、信頼された証明書を使用して署名したモジュールで確立された実行コンテキストは、その証明書を信頼している対象のスコープでも有効になります。

たとえば、C1 という証明書を使用してプロシージャ GetSalesProjections が署名されているとします。この場合、Sales データベース内に証明書 C1 が存在し、ユーザー (CertUser1 など) が証明書 C1 にマップされている必要があります。CertUser1 には Sales データベースの AUTHENTICATE 権限が与えられます。

プロシージャが呼び出されると、署名日時を基に、改ざんされていないことを確認するため署名が検証されます。署名が妥当であると判断されると、モジュールの EXECUTE AS 句で確立したコンテキストの認証子が証明書 C1 になります。署名が妥当ではないと判断されると、認証子はトークンに追加されず、外部リソースへのアクセスは失敗します。

次の図は、署名したモジュールを使用してソース データベースのスコープ外のリソースへのアクセスを制御する方法を示します。C1 という証明書を使用して Marketing データベースのプロシージャ GetSalesProjections に署名します。証明書 C1Sales データベースに提示され、ユーザー CertUser が証明書にマップされます。CertUser1Sales データベースの AUTHENTICATE 権限を許可します。

データベース アクセスの制限に使用する証明書

この認証子の信頼は、データベース所有者が認証子である場合の信頼と同様の方法で検証されます。つまり、AUTHENTICATE SERVER 権限または AUTHENTICATE 権限が確認されます。ただし、信頼は一定の粒度レベルで確立されていることと、モジュールを変更するには署名の書き換えが必要であることから、データベースの TRUSTWORTHY プロパティを検証する必要はありません。

これにより、悪意のあるコードが埋め込まれたデータベースがアタッチされることに起因する脅威が減少します。攻撃を仕掛けるには、既に信頼されている証明書に対応する秘密キーでモジュールに署名する必要があります。しかし、攻撃者はそのキーにアクセスできません。また、信頼されている既存のモジュールを変更するか、新しいモジュールを作成しても、そのモジュールには信頼された有効な署名がありません。

詳細については、「モジュール署名 (データベース エンジン)」を参照してください。

データベースの権限借用スコープを拡張する場合の規則

要約すると、データベース内で確立したコンテキストの権限借用スコープは、次の条件を満たす場合に限り他のスコープに拡張できます。

  • データベース所有者か、モジュールの署名に使用した証明書または非対称キーかにかかわらず、認証子が対象のスコープで信頼されている必要があります。そのためには、データベース所有者、証明書、または非対称キーにマップされているプリンシパルに、AUTHENTICATE 権限または AUTHENTICATE SERVER 権限を許可します。

  • 認証子がデータベース所有者の場合、ソース データベースが信頼可能としてマークされている必要があります。そのためには、データベースの TRUSTWORTHY プロパティを ON に設定します。

必要に合わせた信頼メカニズムの選択

データベース所有者方式も、署名方式もそれぞれ長所と短所があります。必要に合った最適なメカニズムは、ビジネス要件やビジネス環境によって異なります。

データベース所有者方式

データベース所有者方式で信頼を確立する場合の長所と短所は次のとおりです。

  • 証明書、署名などの暗号化についての概念を理解する必要がありません。

  • 署名方式ほどの粒度がありません。

  • SQL Server インスタンスにデータベースをアタッチすると、データベースの TRUSTWORTHY プロパティが OFF に設定されます。データベース所有者が信頼しているモジュールは、システム管理者が明示的に TRUSTWORTHY プロパティを ON に設定するまで有効になりません。つまり、アタッチしたデータベースが意図したように機能し、他のデータベースにアクセスできるようにするには、システム管理者が介入しなければならない可能性があります。

署名方式

署名方式で信頼を確立する場合の長所と短所は次のとおりです。

  • 信頼レベルの粒度を選択できますが、署名されたモジュール内で行われるコンテキストの切り替え以外には適用されません。

  • 単独のステートメント EXECUTE AS USER および EXECUTE AS LOGIN を使用して確立したコンテキストの切り替えには、署名を適用できません。これらのステートメントを実行する場合、信頼のスコープを拡張するには、データベース所有者方式を使用する必要があります。

  • アプリケーションのベンダまたは開発者が秘密キーでモジュールに署名できます。ただし、モジュールまたはデータベースを配布する前に秘密キーは削除してください。秘密キーはモジュールへの署名のみに使用するものなので、削除してもかまいません。署名を検証するためには、モジュールに対応する公開キーがあれば十分です。

  • データベースをアタッチしても、信頼されているモジュールには署名があるので影響を及ぼしません。モジュールには署名以外の要件は必要ありません。