適用対象:SQL Server
Azure SQL Database
Azure SQL Managed Instance
この記事では、SQL Server がセキュリティ キャッシュを使用して、プリンシパルがセキュリティ保護可能なリソースにアクセスするために必要なアクセス許可を検証する方法について説明します。
目的
データベース エンジンは、セキュリティ保護可能なエンティティ (セキュリティ保護可能なエンティティと呼ばれます) の階層コレクションを整理します。これは、アクセス許可で保護できます。 最も目立つセキュリティ保護可能なリソースはサーバーとデータベースですが、アクセス許可は細かいレベルで設定することもできます。 SQL Server は、セキュリティ保護可能なリソースに対するプリンシパルのアクションを、適切なアクセス許可を持っていることを確認することによって制御します。
次の図は、ユーザー Alice がサーバー レベルでログインし、3 人の異なるユーザーが各データベースで同じログインにマップされていることを示しています。
認証プロセスを最適化するために、SQL Server はセキュリティ キャッシュを使用します。
キャッシュ ワークフローなし
セキュリティ キャッシュが無効な場合、SQL Server はキャッシュなしワークフローに従ってアクセス許可を検証します。 このセクションでは、キャッシュなしワークフローについて説明します。
示すには、次のクエリを検討してください。
SELECT t1.Column1,
t2.Column1
FROM Schema1.Table1 AS t1
INNER JOIN Schema2.Table2 AS t2
ON t1.Column1 = t2.Column2;
セキュリティ キャッシュが無効な場合、サービスはクエリを解決する前に、次のワークフローで説明されている手順を完了します。
SQL Server の場合、セキュリティ キャッシュのないタスクは次のとおりです。
- インスタンスに接続します。
- ログイン検証を実行します。
- セキュリティ コンテキスト トークンとログイン トークンを作成します。 これらのトークンの詳細については、次のセクションで説明します。
- データベースに接続します。
- データベース内にデータベース ユーザー トークンを作成します。
- データベース ロールのメンバーシップを確認します。 たとえば、db_datareader、db_datawriter、db_ownerなどです。
-
t1.Column1
とt2.Column1
に対するユーザーのアクセス許可など、すべての列に対するユーザーのアクセス許可を確認します。 -
table1
やtable2
など、すべてのテーブルに対するユーザーのアクセス許可と、Schema1
とSchema2
に対するスキーマのアクセス許可を確認します。 - データベースのアクセス許可を確認します。
SQL Server は、ユーザーが属するすべてのロールに対してプロセスを繰り返します。 すべてのアクセス許可が取得されると、サーバーはチェックを実行して、ユーザーがチェーン内で 1 つの拒否ではなく、必要なすべての許可をチェーンに持っていることを確認します。 アクセス許可チェックが完了すると、クエリの実行が開始されます。
詳細については、 アクセス許可チェック アルゴリズムの概要を確認してください。
検証を簡略化するために、SQL Server はセキュリティ キャッシュを使用します。
セキュリティ キャッシュの定義
セキュリティ キャッシュには、データベースまたはサーバー内のさまざまなセキュリティ保護可能なオブジェクトに対するユーザーまたはログインのアクセス許可が格納されます。 利点の 1 つは、クエリの実行速度が向上することです。 SQL Server は、クエリを実行する前に、スキーマ レベルのアクセス許可、テーブル レベルのアクセス許可、列のアクセス許可など、さまざまなデータベース セキュリティ保護可能なリソースに必要なアクセス許可をユーザーが持っているかどうかを確認します。
セキュリティ キャッシュ オブジェクト
前のセクションで説明したワークフローをより速くするために、SQL Server はセキュリティ キャッシュ内にさまざまなオブジェクトをキャッシュします。 キャッシュされるオブジェクトには、次のようなものがあります。
トークン | 説明 |
---|---|
SecContextToken |
プリンシパルのサーバー全体のセキュリティ コンテキストは、この構造体内に保持されます。 これにはユーザー トークンのハッシュテーブルが含まれており、他のすべてのキャッシュの開始点またはベースとして機能します。 ログイン トークン、ユーザー トークン、監査キャッシュ、および TokenPerm キャッシュへの参照が含まれます。 さらに、サーバー レベルでのログインの基本トークンとして機能します。 |
LoginToken |
セキュリティ コンテキスト トークンと同様です。 サーバー レベルのプリンシパルの詳細が含まれています。 ログイン トークンには、SID、ログイン ID、ログインの種類、ログイン名、isDisabled 状態、サーバー固定ロール メンバーシップなどのさまざまな要素が含まれます。 さらに、sysadmin やセキュリティ管理者など、サーバー レベルの特別な役割も含まれます。 |
UserToken |
この構造は、データベース レベルのプリンシパルに関連しています。 これには、ユーザー名、データベース ロール、SID、既定の言語、既定のスキーマ、ID、ロール、名前などの詳細が含まれます。 ログイン用に、データベースごとに 1 つのユーザー トークンがあります。 |
TokenPerm |
UserToken または SecContextToken のセキュリティ保護可能なオブジェクトのすべてのアクセス許可を記録します。 |
TokenAudit |
キーは、セキュリティ保護可能なオブジェクトのクラスと ID です。 エントリは、オブジェクトに対する監査可能な各操作の監査 ID を含む一連のリストです。 サーバー監査は、特定のユーザーが特定のオブジェクトに対して行う監査可能な各操作の詳細を示すアクセス許可チェックに基づいています。 |
TokenAccessResult |
このキャッシュには、クエリ プランごとに 1 つのエントリを含む、個々のクエリのクエリ アクセス許可チェックの結果が格納されます。 これは、クエリの実行中に最初にチェックされるため、最も重要で一般的に使用されるキャッシュです。 アドホック クエリでキャッシュがあふれないようにするために、クエリが 3 回実行された場合にのみクエリアクセス許可チェックの結果が格納されます。 |
ObjectPerm |
これにより、データベース内のすべてのユーザーに対するデータベース内のオブジェクトに対するすべてのアクセス許可が記録されます。 TokenPerm と ObjectPerm の違いは、TokenPerm が特定のユーザーに対するものであるのに対し、ObjectPerm はデータベース内のすべてのユーザーに対して使用できることです。 |
セキュリティ キャッシュ ストア
トークンは、異なるキャッシュ ストア内に格納されます。
ストア | 説明 |
---|---|
TokenAndPermUserStore |
次のすべてのオブジェクトを含む 1 つの大きなストア: - SecContextToken - LoginToken - UserToken - TokenPerm - TokenAudit |
SecCtxtACRUserStore |
アクセス チェック結果 (ACR) ストア。 すべてのログインには、独自のセキュリティ コンテキスト ユーザー ストアがあります。 |
ACRUserStore |
アクセス チェック結果を保存するストア<unique id> - <db id> - <user id> すべてのユーザーには、個別の ACR ユーザー ストアがあります。 たとえば、2 つの異なるデータベースに 5 人のユーザーが含まれる 2 つのログインは、2 つの SecCtxtACRUserStore と 10 個の異なる ACRUserStore に相当します。 |
ObjectPerm |
各データベースにつき ObjPerm トークン 1 つ。 データベース内のすべての異なるセキュリティ対象。 |
既知の問題
このセクションでは、セキュリティ キャッシュに関する問題について説明します。
セキュリティ キャッシュの無効化
さまざまなシナリオで、データベース レベルまたはサーバー レベルでセキュリティ キャッシュの無効化をトリガーできます。 無効化が発生すると、現在のすべてのキャッシュ エントリが無効になります。 今後のすべてのクエリとアクセス許可チェックは、キャッシュが再作成されるまで、完全な "キャッシュなし" ワークフローに従います。 無効化は、キャッシュされたエントリを再構築する必要があるアクティブな接続がすべて必要な場合に、特に負荷が高い場合に、サーバーのパフォーマンスに大きな影響を与える可能性があります。 キャッシュの無効化を繰り返し実行すると、この影響が悪化する可能性があります。
master
データベースの無効化はサーバー全体の無効化として扱われ、インスタンス上のすべてのデータベースのキャッシュに影響します。
SQL Server 2025 では、特定のログインに対してのみキャッシュを無効にする機能が導入されています。 つまり、セキュリティ キャッシュ エントリが無効になると、影響を受けるログインに属するエントリのみが影響を受けます。 たとえば、ログイン L1 に新しいアクセス許可を付与した場合、ログイン L2 のトークンは影響を受けません。
最初の手順として、この機能は、CREATE、ALTER、DROP ログインのシナリオ、および個々のログインのアクセス許可の変更に適用されます。 グループ ログインでは、サーバー レベルの無効化が引き続き発生します。
次の表に、セキュリティ キャッシュを無効にするすべてのセキュリティ データ定義言語 (DDL) アクションを示します。
アクション | サブジェクト | 範囲 |
---|---|---|
CREATE/ALTER/DROP |
APPLICATION ROLE SYMMETRIC KEY ASYMMETRIC KEY AUTHORIZATION CERTIFICATE ROLE SCHEMA USER |
指定されたデータベース |
DROP |
sys.all_objectsに表示されるオブジェクト、またはデータベースまたはスキーマ スコープのセキュリティ保護可能なリストにリストされているセキュリティ保護可能なオブジェクト。 | 指定されたデータベース |
GRANT/DENY/REVOKE |
任意のセキュリティ保護可能なリソースへのアクセス権限がデータベースまたはスキーマに含まれています。 | 指定されたデータベース |
CREATE/ALTER/DROP |
LOGIN ( SERVICE ) MASTER KEY |
SQL Server インスタンス |
ALTER |
DATABASE |
指定されたデータベース |
TokenAndPermUserStore のサイズが大きくなるときのクエリ パフォーマンス
高い CPU 使用率やメモリ消費量の増加などのパフォーマンスの問題は、TokenAndPermUserStore キャッシュ内のエントリが過剰に発生する可能性があります。 既定では、SQL Server は、内部メモリ不足を検出した場合にのみ、このキャッシュ内のエントリをクリーンアップします。 ただし、RAM が十分なサーバーでは、内部メモリの負荷が頻繁に発生しない可能性があります。 キャッシュが大きくなると、再利用するために既存のエントリを検索するのに必要な時間が長くなります。 このキャッシュはスピンロックによって管理され、一度に検索を実行できるスレッドは 1 つだけです。 その結果、この動作によって、クエリのパフォーマンスが低下し、CPU 使用率が高くなる可能性があります。
対処法
SQL Server には、TokenAndPermUserStore キャッシュのクォータを設定するために使用できる 2 つのトレース フラグ (TF) が用意されています。 既定では、クォータはありません。つまり、キャッシュは無制限の数のエントリを保持できます。
- TF 4618: TokenAndPermUserStore のエントリ数を 1024 に制限します。
- TF 4618 および TF 4610: TokenAndPermUserStore のエントリ数を 8192 に制限します。 TF 4618 のエントリ数の制限が低い場合は、他のパフォーマンスの問題が発生する場合は、トレース フラグ 4610 と 4618 を一緒に使用することをお勧めします。 詳細については、「 DBCC TRACEON - トレース フラグ (Transact-SQL)」を参照してください。
詳細については、TokenAndPermUserStore キャッシュ内の過剰なエントリが原因で発生する可能性があるパフォーマンスの問題に関する記事を参照してください。
ベスト プラクティス
このセクションでは、セキュリティ ワークフローを最適化するためのベスト プラクティスを示します。
ピーク時以外のユーザー管理
セキュリティ キャッシュの高レベルの無効化の性質 (データベース/サーバー レベル) を考えると、サーバーの負荷が低い非ビジネス時間帯にセキュリティ DFL を実行します。 負荷の高いワークロード中にセキュリティ キャッシュの無効化が発生した場合、セキュリティ キャッシュが再入力されるため、サーバー全体のパフォーマンスに大きな影響を与える可能性があります。
アクセス許可の変更に 1 つのトランザクションを使用する
同じトランザクション内で複数のセキュリティ データ定義言語 (DDL) 操作を実行すると、他のアクティブな接続でデッドロックが発生する可能性が大幅に高まる可能性があります。このリスクを軽減するには、1 つのトランザクションで複数のセキュリティ DDL を実行しないようにすることをお勧めします。 代わりに、セキュリティ関連の DDL 操作を個別のトランザクションで実行して、ロックの競合を最小限に抑えます。