ハッカーへの警告
SQL Server 2005 の高度なセキュリティ機能による不正侵入者に対する防衛
Don Kiely
翻訳元: Keep Bad Guys at Bay with the Advanced Security Features in SQL Server 2005 (英語)
この記事は SQL Server 2005 のプレリリース バージョンに基づいています。この記事に含まれるすべての情報は、変更される可能性があります。
この記事で使用する技術: SQL Server 2005、セキュリティ
サンプルコードのダウンロード: SQLServerSecurity.exe (英語) (115KB)
この記事で取り上げる話題:
- きめ細かな権限と最小特権の原則
- メタデータ可視性の制御
- ユーザーとスキーマの分離
- データベースにおける実行コンテキストと暗号化
目次
- 権限
- カタログ ビューとメタデータの可視性
- ユーザーとスキーマの分離
- 実行コンテキスト
- 暗号化
- まとめ
データベースやクライアント アプリケーションを取り巻く環境は日々厳しくなってきています。攻撃者は毎日のように新しい巧妙な攻撃をしかけ、貴重なデータを脅かしています。さいわいなことに、SQL Server 2005 は、縦深防御や最小特権などの原則に直接対処する、強力な新しいセキュリティ機能を備えています。SQL Server Books Online で説明されているように、マイクロソフトは、攻撃表面の減少、SQL Server やデータベースの安全な展開を簡略化するなど、多くのセキュリティ イニシアティブを実装しているだけではなく、変化するセキュリティ環境において高度なセキュリティを維持するために役立つ品質の高いセキュリティ ツールや文書も提供しています。
この記事では、開発者にとって最も興味深い SQL Server 2005 のセキュリティ拡張について説明します。管理セキュリティ機能については、2005 年の春版の『TechNet Magazine』で扱いましたが、エンドポイント認証、サーバーで実行されるマネージ コードのセキュリティ コンテキストのサポートなど、開発固有のセキュリティ拡張も多数あります。ここでは、コアのリレーショナル データベース エンジンのみに焦点を絞って説明します。Reporting Services、Analysis Serivce などのサポート システムには独自のセキュリティ インフラストラクチャがあり、それらについては他の記事で適宜ご紹介します。
1. 権限
SQL Server 2000 およびそれより前のバージョンには、ユーザー、ログイン、およびその他のプリンシパルに権限を割り当てるための使いやすいスキーマが含まれていました。しかし、それらのバージョンの SQL Server をロック ダウンすると、強力なセキュリティの実装に必要な性能のよいツールではなく、若干性能の劣るツールで作業することになります。ユーザーが必要とする権限だけでなく、ユーザーにとって不要な多くの権限を含む固定ロールをユーザーに割り当てなければならないことはよくあります。これは、最小特権の原則を大いに侵害しています。この原則においては、各ユーザーまたはその他のプリンシパルの権限は必要なものだけに限られ、それ以上またはそれ以下にすることはできません。
SQL Server 2005 で付与できる権限は、前のバージョンよりもかなり詳細化されています。ほぼすべてのオブジェクトが、ほとんどのプリンシパルに対して様々な権限を付与することができます。これまでどおり、SQL Server ではサーバーおよびデータベース レベルで多くのロールを使用できますが、ユーザーのすべてのニーズが特定のリソースに対する制限付きアクセスである場合はユーザーをロールに追加する必要はなくなりました。
SQL Server 2005 のセキュリティ用語におけるプリンシパルとは、保護されているリソースへのアクセスを要求したり、そのリソースにアクセスするための権限が許可される個人、グループ (ロール)、またはプロセスを指します。前のバージョンの SQL Server では、プリンシパルは Windows で定義するか、対応する Windows プリンシパルを使用せずに SQL Server ログインに基づくことができます。図 1 は、SQL Server 2005 プリンシパルの階層を表していますが、固定サーバー ロールやデータベース ロールは含まれていません。また、この図には、セキュリティ オブジェクトに対してログインおよびデータベース ユーザーがどのようにマップされるかも示されています。前のバージョンと同様、SQL Server 2005 では、プリンシパルの影響を受けるスコープは、その定義のスコープによって変わります。したがって、Windows レベルのプリンシパルは SQL Server レベルのプリンシパルよりも包括的で、SQL Server レベルのプリンシパルはデータベース レベルのプリンシパルよりも包括的です。すべてのデータベース ユーザーは、自動的に固定パブリック ロールに属します。
図 1 SQL Server 2005 のプリンシパル階層
| Windows レベルのプリンシパル |
| Windows ドメイン ログイン |
| Wondows ローカル ログイン |
| Windows グループ |
| SQL Server レベルのプリンシパル |
| SQL Server ログイン |
| Windows ログインにマップされる SQL Server ログイン |
| 証明書にマップされる SQL Server ログイン |
| 非対称キーにマップされる SQL Server ログイン |
| データベースレベルのプリンシパル |
| データベース ユーザー |
| Windows ログインにマップされるデータベース ユーザー |
| 証明書にマップされるデータベース ユーザー |
| 非対称キーにマップされるデータベース ユーザー |
| データベース ロール |
| アプリケーション ロール |
| パブリック ロール |
また、注目すべきなのは、権限を許可または拒否することによってオブジェクトを保護できるという点です。図 2 は、SQL Server 2005 で保護できるオブジェクトを示しています。サーバー レベルでは、サーバーとやりとりする通信チャネルを制御するためのネットワーク エンドポイントだけでなく、データベース、バインド、ロール、およびログインも保護できます。データベースおよびスキーマ レベルでは、特にデータベース オブジェクトを保存するために使用されるスキーマ オブジェクト内では、作成可能なほぼすべてのオブジェクトを保護できます。
.gif)
図 2 SQL Server 2005 で保護できるオブジェクト
一連の固定サーバー ロールとデータベース ロールは、SQL Server 2000 から変更されていないため、ユーザーまたはアプリケーションが定義済み権限のすべてまたはその多くを必要としている場合は、事前に定義されている権限のセットをそのまま利用することができます。ただし、最小特権の原則の基では、プリンシパルに過剰な数の権限を付与するロールを使用する必要はほとんどありません。プリンシパルに必要な権限を特定し、それらを割り当てるのはやや手間のかかる作業ですが、この作業を行うことでデータベース環境の安全性を大幅に高めることができます。
SQL Server で使用可能な多くの権限を確認するには、次のように builtin_permissions カタログ ビューを表示します。
SELECT * FROM sys.fn_builtin_permissions(default)
April CTPでは、これによって、すべての権限を表す 180 を超える行が返されます。これらの権限の中で重要な権限をいくつか説明します。
CONTROL 権限は付与される側に所有権を与えます。これには、保護できるオブジェクトに対する権限を許可する権限も含まれます。保護できるオブジェクトの階層の 1 レベルにおける CONTROL 権限は、そのレベルに含まれるすべてのオブジェクトに対して同じ権限があることを意味します。
ALTER ANY entity 権限は、エンティティ タイプのオブジェクトを作成、変更、および削除する権限を与えます。たとえば、サーバー レベルの ALTER ANY DATABASE 権限が付与されると、データベースを変更することができます。特定のデータベースのスコープ内の ALTER ANY ASSEMBLY 権限が付与されると、どのアセンブリでも変更することができます。
IMPERSONATE ON login または IMPERSONATE ON user 権限が付与されると、指定されたサーバー ログインまたはデータベース ユーザーを偽装し、偽装されたセキュリティ資格情報を使用してあらゆる操作を実行できます。この権限は、後述する EXECUTE AS 機能にとって重要です。
SQL Server 2005 でも、見慣れた GRANT、DENY、および REVOKE スキーマを使用して保護できるオブジェクトに対する権限を割り当てたり拒否することができます。GRANT ステートメントは大幅に拡張されて、許可のスコープ、およびプリンシパルが他のプリンシパルに権限を許可できるかどうかなどを指定する、新しい権限オプションに対応できるようになりました。複数データベースの権限は使用できません。複数データベースの権限を許可するためには、各データベースで重複ユーザーを作成し、各データベースのユーザーに権限を個別に割り当てる必要があります。前のバージョンの SQL Server と同様に、アプリケーション ロールをアクティブにすると、ロールがアクティブな間は他の権限の使用は中断されます。
特定の権限を許可すると、他の権限も暗黙のうちに提供される場合があります。SQL Server Books Online には、sys.fn_builtin_permissions カタログ ビューから階層リストを組み立てて、階層内の各権限の深さを識別する ImplyingPermissions ユーザー定義関数の T-SQL が示されています。著者は、ImplyingPermissions をマスタ データベースに追加した後に、次のようにこのステートメントを実行して権限の階層リストを生成し、オブジェクトおよび権限の種類を渡してみました。
SELECT * FROM master.dbo.ImplyingPermissions('schema', 'alter')
SQL Server 2005 の権限がどの程度の細かさかを把握するのは最初は難しいかもしれません。サーバーおよび一般的なデータベース内で使用できるプリンシパルの数と種類および確保できるオブジェクトの数を考えてみてください。また、使用可能な権限の純粋な数と、隠されている暗黙的な権限の数も考えてみてください。アプリケーションを作成するには、そのセキュリティ ニーズをこれまでよりもかなり詳しく分析し、すべてのオブジェクトに対する権限を慎重に制御することが必要です。一方で、許可できる権限を持たない操作もあります。たとえば、TRUNCATE TABLE にはテーブルに対する ALTER 権限が必要ですが、この権限でできるのは単にテーブルの行を削除することだけです。
ページのトップへ
2. カタログ ビューとメタデータの可視性
SQL Server 2005 のきめの細かい権限スキームの利点の 1 つに、モデム データベース エンジンに必要なメタデータを十分に保護できるという点があります。SQL Server は、SQL-92 仕様で定義されている INFORMATION_SCHEMA ビュー、サーバー レベルとデータベース レベルのシステム テーブル、および大量の組み込みシステム ストアド プロシージャによる豊富なメタデータの公開を長い間サポートしてきました。システムの安定性に大きく影響するにもかかわらず、これまではシステム テーブルを変更してサーバーおよびそのデータベースの基になる状態を変更することも可能でした。マイクロソフトは常日頃から、基になるシステム テーブルはいつでも変更される可能性があるので、それらを使用することはそれぞれの責任で行うようにということを伝えてきました。
SQL Server 2005 で、マイクロソフトは新しいカタログ ビューのセットを作成し、すべてのメタデータをサーバーを通じて公開するようになりました。新しい sys スキーマは、メタデータ ビューをカプセル化します。カタログ ビューは読み取り専用であるため、前のバージョンの SQL Server で可能であったハッカー行為は排除されます。ビューの多くには、古いシステム テーブルと似たような名前が付いているので、必要な情報を簡単に見つけることができます。たとえば、sysobjects メタデータは sys.objects ビューを通じて公開されます。信頼を保つ為に、ビュー定義は公表されていない場所に物理的に隠し、誰かがサーバーをハッキングして見つけない限りその定義には直接アクセスできないようにします。それにもかかわらず、カタログ ビューを使用してサーバーおよびデータベースのデータを取得し、前のハッカー行為については忘れるということが明らかです。ストアド プロシージャ、T-SQL、および SQL Server を構成および調整するその他の正式な方法さえ守っていれば、セキュリティと安定性を確保できます。
セキュリティという観点から見たビューによるメタデータの公開の利点は、カタログ ビューから返されるデータが、データが要求されているユーザー コンテキストの権限に従ってフィルタされることです。たとえば、従来は、データベース内の sysobjects テーブルにアクセスするための権限を持っているユーザーは、(多くのユーザーが多くのアプリケーションで実行していたことですが) 各オブジェクトへのアクセス権があるかどうかに関係なく、テーブルに対してクエリーを実行し、データベース内のすべての使用可能オブジェクトを参照できました。SQL Server 2005 では、ユーザーがテーブルを参照するためには、SELECT 権限など、テーブルへの最小アクセス権がいくつか必要です。ユーザーにデータベースへのアクセス権があっても、そのオブジェクトへのアクセス権がない場合は、sys.objects に対してクエリーを実行しても行は返されません。
この動作を確認するために、管理者として次のコードを実行してみてください。
USE master
CREATE LOGIN User1 WITH password = 'myPassword'
-- 選択したデータベースを使用します。
USE AdventureWorks
CREATE USER User1
EXECUTE AS LOGIN = 'User1'
SELECT * FROM sys.objects
-- ユーザーはそのデータベースの権限を持っていないため、行は返されません。
REVERT
このコードでは、最初にサーバー上に User1 ログインを作成してから、そのログインにマップされているユーザーをサンプルの AdventureWorks データベースに追加しています。次に、実行コンテキストを User1 に変更し、sys.objects からデータを取得しています。User1 にはデータベースへのアクセス権がありますが、どのオブジェクトに対する権限もないため、カタログ ビューからは何も返されません。REVERT ステートメントによって、実行コンテキストが管理者ユーザーに戻されています。
データを返すためには、ユーザーに 1 組の権限を割り当てる必要があります。次のコードでは、Contact テーブルに対する SELECT 権限および dbo.uspGetBillOfMaterials ストアド プロシージャに対する EXECUTE 権限を割り当てています。
--User1 にテーブルおよびストアド プロシージャに対する権限を割り当てます。
GRANT SELECT ON Person.Contact TO User1
GRANT EXECUTE ON dbo.uspGetBillOfMaterials TO User1
-- User1 に対して実行します。
EXECUTE AS LOGIN = 'User1'
SELECT * FROM sys.objects
REVERT
カタログ ビューを User1 として実行すると、sys.objects カタログ ビューから、Contact テーブルおよび uspGetBillOfMaterials ストアド プロシージャに加え、テーブル制約やトリガのメタデータを含む、9 つの行が返されます。これは、オブジェクト階層の 1 つのレベルで権限を許可すると、子オブジェクトに対する関連の権限も許可されることを示しています。
ご想像どおり、sysadmins および sa は、システム カタログ ビュー内のサーバー上にあるすべてのデータを参照でき、データベース所有者はそのデータベース内のすべてのデータを参照できます。権限に基づくフィルタは、sp_help や sp_helpdb などのさまざまなオブジェクトに関する情報を示すシステム ストアド プロシージャにも適用されます。これらのシステム ストアド プロシージャはシステム カタログ ビューを読み取るため、プロシージャが実行されているプリンシパルの権限に従ってフィルタ処理されます。ただし、メタデータの可視性の制限は OBJECTPROPERTY など、すべてのメタデータ関数に適用されるわけではないので注意が必要です。
古いシステム テーブル、ストアド プロシージャ、およびビューの多くはこれまでどおり使用できますが、それらはすべて読み取り専用ビューとして公開されます。これらは下位互換性のために存在し、SQL Server 2005 のどの新機能も示しません。前のバージョンの古いコードをサポートしていない場合は、新しいシステム カタログ ビューを使用することをお勧めします。
ページのトップへ
3. ユーザーとスキーマの分離
ANSI SQL-99 仕様では、データベース スキーマは、オブジェクトの単一の名前空間を形成する 1 つのプリンシパルが所有するデータベース オブジェクトのコレクションとして定義されています。スキーマには、テーブル、ビュー、ストアド プロシージャ、関数、型、およびトリガなどのデータベース オブジェクトが保存されます。スキーマでは簡単にオブジェクトをグループ分けできるため、データベースはさまざまな所有者のオブジェクト名やグループ オブジェクトを再使用できます。
図 3 の上部分に示されているように、SQL Server 2000 では、所有者スキーマは区別できませんでした。管理者がデータベース内に Fred という名前のユーザーを作成すると、スキーマ Fred も自動的に作成され、ユーザー Fred の下に隠されます。ユーザー Fred が SQL Server にログインしてテーブル Table1 を作成すると、そのテーブルの名前は、Fred.Table1 になります。Fred が作成した他のオブジェクトにも、Fred.StoredProcedure および Fred.View1 などの名前が付けられます。Fred がデータベース所有者である場合、作成されたオブジェクト Fred1 は dbo スキーマの一部になります。
.gif)
図 3 SQL Server のユーザーとスキーマ
問題が発生するのは、たとえば、Fred が会社を退社し、George が Fred のジョブを引き継ぐ場合など、オブジェクトの所有者の変更が必要な場合です。システム管理者は、Fred が所有しているすべてのオブジェクトの所有権を変更する必要があります。George がテーブルの所有権を引き継いだ後に、Fred.Table1 を参照するすべての T-SQL またはクライアント アプリケーション コードを、George.Table1 に変更する必要があります。Fred が所有しているオブジェクトの数と、Fred という名前が埋め込まれているアプリケーションの数によっては、この作業は複雑になる場合があります。
図 3 の下部に示されているように、SQL Server 2005 ではこの問題が解決され、スキーマからユーザーを分離することにより SQL-99 スキーマをより綿密に実装できるようになりました。新しい DDL ステートメントを使用して Fred という名前の新しいユーザーを作成しても、SQL Server では同じ名前のスキーマは自動的に作成されません。代わりに、スキーマを明示的に作成して、所有権を割り当てる必要があります。データベース オブジェクトはすべて、Fred が最初に所有する MySchema スキーマに含まれるので、スキーマの所有権を単純に George に変更するだけで、スキーマのすべてのオブジェクトの所有者を簡単に変更できるようになりました。各ユーザーには既定のスキーマを割り当てることもできるので、スキーマ参照を使用しない、名前で参照されるオブジェクトはすべて既定のスキーマに含まれているものとみなされます。図 3 の下部に示されているように、ユーザー Fred の既定のスキーマが MySchema である場合、Fred はテーブルを MySchemaTable1 または単純に Table1 として参照できます。ユーザー名に関連付けられた既定のスキーマを持っていない可能性が高い George は、テーブルを MySchema.Table1 として参照する必要があります。指定された既定のスキーマを持っていないユーザーは、既定の dbo を持ちます。
図 4 のコードには、ここで説明している内容が示されています。コードの開始部分では、CREATE TABLE 権限を使用して、Pubs データベースに Carol という名前のログインと Carol という名前のユーザーを作成しています。実行コードのセキュリティ コンテキストが Carol に変更され、Carol はテーブルを作成しようとします。この試みは、「指定されたスキーマ名 'dbo' は存在しないか、そのスキーマを使用する権限がありません。」というエラーで失敗します。この場合、問題なのは、Carol が dbo スキーマでオブジェクトを作成する権限を持っていないことです。Carol に既定のスキーマが指定されていないので、CREATE TABLE ステートメントによって dbo.table1 が作成されます。
図 4 ユーザーとスキーマの分離
USE pubs
-- 既定の db を pubs とし、パスワード 'carol5' を使用する'Carol" の、
-- GUI を使用する新しい SQL Server ログインを作成します。
CREATE LOGIN Carol WITH PASSWORD = 'carol5'
CREATE USER Carol FOR LOGIN Carol
GRANT CREATE TABLE TO Carol
EXECUTE AS LOGIN = 'Carol'
GO
CREATE TABLE table1 (tID int)
-- エラー : dbo スキーマでオブジェクトを作成するための権限がありません。
-- 管理者に戻ります。
REVERT
-- スキーマおよびログインへのリンクを作成します。
CREATE SCHEMA CarolSchema AUTHORIZATION Carol
EXECUTE AS LOGIN = 'Carol'
GO
CREATE TABLE table1 (tID int)
-- この場合もエラーです。 スキーマは存在しますが、既定では
-- ないからです。
CREATE TABLE CarolSchema.table1 (tID int)
-- これで成功です。
-- クリーンアップします。
REVERT
DROP TABLE CarolSchema.table1
DROP SCHEMA CarolSchema
DROP USER Carol
DROP LOGIN Carol
その後、このコードを実行するためにサインインした管理ユーザーにコードが戻り、CarolSchema が作成されて、スキーマの所有権が Carol に割り当てられます。次に、Carol のセキュリティ コンテキストでもう一度実行すると、テーブルの作成が再度実行されます。これもまた、同じエラー メッセージで失敗します。これは単に、Carol が独自のスキーマを持っていても、SQL Server ではそのスキーマが既定で使用されないからです。Carol が最終的に CarolSchema.table1 を作成できるのは、そのオブジェクト名と、使用権限があるスキーマを明示的に使用したときです。CarolSchema を作成した後の 2 回目のテーブル作成の失敗は、次のように Carol というユーザーを作成するか、そのユーザーに既定のスキーマを追加して、既定のスキーマ セットを Carol が持つことで成功します。
CREATE USER Carol FOR LOGIN Carol WITH DEFAULT_SCHEMA = CarolSchema
-- または
ALTER USER Carol WITH DEFAULT_SCHEMA = CarolSchema
ページのトップへ
4. 実行コンテキスト
SQL Server は、データにアクセスするコードを実行しているユーザーに適切な権限を割り当てるための組み合わせ所有権を長い間サポートしてきました。たとえば、コードを呼び出しているユーザーに実行権限があり、コードの所有者がアクセス先の 2 つのテーブルとビューの所有者である限り、それ以上の権限はチェックされず、呼び出し元は要求したデータを受け取ります。組み合わせ所有権が壊れた場合は (コードの所有者が参照先ビューを所有していない場合など)、呼び出し元のセキュリティ コンテキストがチェックされます。
呼び出し元にビューにアクセスするための権限がある場合は、データが返されますが、権限がない場合、データは返されません。これは、SQL Server 2000 およびそれよりも前のバージョンの動作です。この動作は、データに対する基になる権限をユーザーが持っていない場合に、ストアド プロシージャまたは関数を使用してユーザーにデータへのアクセス権を付与したい場合は問題ありません。組み合わせ所有権にはいくつかの制限があります。1 つは、組み合わせ所有権はデータ操作処理にのみ適用され、動的 SQL には適用されないという点です。
しかし、呼び出し元の権限を使用してデータへのアクセスを検証することは避けたいはずです。別のユーザーのセキュリティ コンテキストを使用して慎重に設計されたセキュリティ フレームワークの一部として権限をチェックしデータを保護するストアド プロシージャを作成したい場合はどうするのでしょうか。SQL Server 2005 より前のバージョンには簡単なオプションはありませんでした。そこで、SQL Server 2005 より実行コンテキストの概念が導入されました。SQL Server 2005 では、ストアド プロシージャ、データ操作トリガ、およびユーザー定義関数 (インライン テーブル値は除く) を定義するときに、EXECUTE AS 句を使用して、SQL Server がプロシージャで参照されるオブジェクトとデータへのアクセスを検証する際に使用するユーザーの権限を指定できます。たとえば、常にコードの作成者に関連付けられている権限を使用してデータにアクセスすることを指定できます。次に示すコードは、特定のユーザーの権限を使用してコードを実行する例を示しています。この例では、実行コンテキストが ec のコンテキストであるため、ユーザー ec にタイトル テーブルに対する SELECT 権限が必要です。
USE pubs
CREATE LOGIN ec WITH PASSWORD = 'ecpassword'
CREATE USER ec FOR LOGIN ec
CREATE PROCEDURE GetTitlesEC(@Table varchar(40))
WITH EXECUTE AS 'ec'
AS
EXECUTE('SELECT * FROM ' + quotename(@Table))
GO
SQL Server 2005 には、4 つの実行コンテキスト オプションが用意されています。EXECUTE AS CALLER では、コードをモジュールの呼び出し元のコンテキストで実行することを指定します。したがって、呼び出し元には、モジュールの実行権限と、基になるすべてのオブジェクトに対する権限が必要です。SQL Server は、壊れた組み合わせ所有権の権限のみをチェックするため、コードの所有者が基になるオブジェクトの所有者でもある場合は、モジュールの実行権限のみがチェックされます。これは、下位互換性を確保するための既定の実行コンテキストです。
EXECUTE AS 'user_name' では、コードを指定されたユーザーのセキュリティ コンテキストで実行することを指定します。これは、組み合わせ所有権に依存せずに、コードの実行に必要な権限を持つユーザーを作成する場合に便利なオプションです。
EXECUTE AS SELF は、モジュールを作成または変更しているユーザーのセキュリティ コンテキストでモジュールが実行されることを指定するための簡略表記です。SQL Server では、SELF ではなくモジュールに関連付けられている実際のユーザー名が保存されます。
EXECUTE AS OWNER では、セキュリティ コンテキストがモジュールの現在の所有者のセキュリティ コンテキストであることを指定します。所有者が指定されていない場合は、含まれているスキーマの所有者のコンテキストが使用されます。所有者は、ロールではなく、特定のユーザーのシングルトン アカウントであることが必要です。これは、モジュールそのものを変更せずにモジュールの所有者を変更できるようにする場合に便利なオプションです。
コードの実行コンテキストの変更にはいくつかの制限があります。モジュールの作成には、指定されたユーザーの IMPERSONATE 権限が必要です。自分自身を偽装する場合、この権限は必要ありません。また、すべてのモジュールの実行コンテキストが変更されてそのユーザーが使用されなくなるまで、データベースから指定されたユーザーを削除することはできません。組み合わせ所有権は、モジュール内で実行される動的 SQL には適用されません。SQL Server 2000 と同様に、実行コンテキストには、動的 SQL からアクセスする基になるオブジェクトに対する権限が必要です。
ページのトップへ
5. 暗号化
重要なリソースを保護する最良の方法は、セキュリティ レイヤの上にレイヤを重ねることであり、これは縦深制御の原則として知られています。攻撃者は、目的のものを獲得する前に 1 つのレイヤの後にある別のレイヤを突破しなければなりません。多くの場合、ハッカーはネットワーク セキュリティ、マシンのセキュリティ、データベースのセキュリティの順に侵害し、最後に重要なデータに自由にアクセスできるようになります。
SQL Server で暗号化されたデータは、最後の防御ラインです。攻撃者はデータベースにアクセスできたとしても、データを解読する必要があります。現在の強力な暗号アルゴリズムをもってすれば、復号キーがない限り、攻撃者は非常に困難な挑戦を行うことになります。当然、暗号は決して破られません。SQL Server に保存されているすべてのデータ (製品カタログなど一般の人でもアクセスできるデータを含む) を暗号化したい場合があるかもしれませんが、暗号化はプロセッサ集中型であるため、これを行うには非常に優れたパフォーマンスが必要になります。1 つの短い文字列を暗号化または復号化するために必要な処理サイクル数に、テーブル内の 10,000,000 行のデータを掛けると、サーバーはすぐにダウンしてしまいます。必要な保護のレベルを検討し、フィールドの保護がコストに見合う場合にのみ暗号化を使用する必要があります。
SQL Server 2005 には、さまざまな種類のキーと暗号化アルゴリズムが用意されています。対称キーの場合は、RC4、RC2、DES ファミリ、AES ファイル アルゴリズムを使用できます。非対称キーの場合は RSA が提供され、証明書の場合は、Internet Engineering Task Force の X.509 V1 標準が使用されます。
暗号化の中で最も難しい作業は、キー管理、すなわち秘密を守ることです。データの暗号化に使用した対称キーを取得できた攻撃者は、思うがままにデータにアクセスし、データを変更することができます。SQL Server 2005 ではキーをユーザー自身が管理することも、SQL Sever がユーザーの代わりに管理することもできます。この場合は、サーバー内のさまざまなスコープで各種のキーを保護するために暗号化オブジェクトの階層が使用されます (図 5 を参照)。
.gif)
図 5 SQL Server 2005 の暗号化階層
図 5 の一番上には、SQL Server のすべてのキーと証明書の親となるサービス マスタ キーがあります。サービス マスタ キーは、サーバー上のすべてのキーを直接または間接的に暗号化する対称キーであり、SQL Server のインストール時に自動的に作成されます。このキーが破られると、攻撃者は最終的にすべてのデータベースのすべてのキーを解くことができます。そのため、このキーは Windows のデータ保護 API (DPAPI) により保護されます。このキーには、SQL Server を実行するときのサービス アカウント名を使用してアクセスできます。
SQL Server はユーザーに代わってサービス マスタ キーを管理しますが、図 6 に示すように、ユーザーはこのキーの特定のメンテナンス タスクを実行してファイルにダンプしたり、キーを再生成したり、T-SQL ステートメントを使用してファイルからキーを復元したりすることができます。
図 6 サービス マスタ キーのメンテナンス
-- サービス マスタ キーをエクスポートして安全な場所に保存します。
-- ファイルは、指定されたパスワードをキーとして暗号化されます。
DUMP SERVICE MASTER KEY TO FILE = 'c:\servicemasterkey.dat'
PASSWORD = 'S3@fBZir2D^P$x5P&tNr^uR!@wGW'
-- サービス マスタ キーを再読込みします。
LOAD SERVICE MASTER KEY FROM FILE = 'c:\servicemasterkey.dat'
PASSWORD = 'S3@fBZir2D^P$x5P&tNr^uR!@wGW'
-- サービス マスタ キーを再生成します。この場合は注意が必要です。古いマスタ キーで
-- 暗号化されたすべてのキーを復号化してから、新しいキーで暗号化します。
-- この処理には時間がかかる場合があります。
ALTER SERVICE MASTER KEY REGENERATE
ALTER SERVICE MASTER KEY ステートメントには、DPAPI でキーを暗号化するために使用する回復オプションやサービス アカウントを変更するオプションもあります。ただし、このキーを変更する必要はほとんどありません。
データベースのスコープ内では、データベース マスタ キーは、データベース内のすべてのキー、証明書、およびデータのルート暗号化オブジェクトになります。データベースごとに 1 つのマスタ キーを持つことができます。2 つ目のキーを作成しようとすると、エラーになります。
ユーザーが指定したパスワードでデータベース マスタ キーを使用する前に、次のように CREATE MASTER KEY T-SQL でデータベース マスタ キーを作成する必要があります。
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'WeZ#6hv*XHq#akAEaqcr7%CUP3aQ'
作成されたキーは、トリプル DES で暗号化されて 2 回保存されます。1 回は sys.symmetric_keys データベース テーブル内に保存されて、指定されたパスワードで暗号化され、2 回目はマスタ データベース内の sys.database テーブル内に保存されて、サービス マスタ キーで暗号化されます。この二重保存によって、マスタ キーは自動的に開きます。
既存のマスタ キーを使用するデータベースをデタッチし、別のサーバーにそのデータベースを移動すると、新しいサーバーのサービス マスタ キーが異なるために問題が発生する可能性があります。ALTER MASTER KEY には、古いサーバーのサービス マスタ キーによる暗号化を削除してから、新しいサーバーに戻すオプションがあります。それ以外の場合、マスタ キーは使用前に常に明示的に開いておく必要があります。
データベース マスタ キーを作成したら、そのデータベース マスタ キーを使用して次の 3 種類のキーのいずれかを作成できます。作成するキーは必要な暗号化に応じて変わります。
- 非対称キーは、公開キーと秘密キーのペアを使用する公開キー暗号化に使用されます。
- 対称キーは、同じキーでデータの暗号化と復号化の両方を実行する共有シークレットに使用されます。
- 証明書は、基本的には公開キーのラッパーです。
図 5 は、これらのキーと証明書を使用して他のキーとデータを暗号化する方法を示しています。非対称キーは対称キーとデータ、対称キーは他の対称キーとデータ、証明書は対称キーとデータを暗号化できます。キー管理をユーザー自身が処理する場合は、カスタムのパスワードを使用して対称キーを作成することもできます。当然、これらはすべて、最終的にデータベース マスタ キーで暗号化されます。
証明書は、ドキュメント、電子メールまたはファイルの署名について語る場合にデジタル署名のコンテキストで使用されるオブジェクトと同じようなものと考えることができます。証明書オブジェクトは非対称暗号化に使用する公開キーをラップし、その作成方法にはさまざまなオプションがあります。ただし、SQL Server がすべての詳細を管理するため、他の環境では証明書の作成に必要な手順は示されません。
SQL Server で独自に使用する証明書を作成したり、Microsoft Certificate Server または VeniSign などの信頼されている証明機関で作成された証明書をインポートすることができます。秘密キーの暗号化に使用するパスワードを設定したり、SQL Server でデータベース マスタ キーを使用することを指定したり、作成日や有効期限日を設定することもできます。ファイルから証明書をインポートするか、署名付きの実行可能ファイルや読み込んだ .NET アセンブリから証明書を読み込むことができます。次のコードでは、2 つの証明書を作成しています。1 つは User1 に関連し、有効期限が設定されていません。もう 1 つは User2 に関連するもので 2005 年の末に有効期限が切れます。
-- データベース マスタ キーで暗号化する、User1 に関連する証明書を
-- 作成します。 データベース マスタ キーは既に存在している必要があります。
CREATE CERTIFICATE User1Certificate
AUTHORIZATION User1 WITH subject = 'Certificate For User1'
GO
-- 制限付きの、User2 の証明書を作成します。
CREATE CERTIFICATE User2Certificate
AUTHORIZATION User2 WITH subject = 'Certificate For User2',
EXPIRY_DATE = '12/31/2005',
ENCRYPTION_PASSWORD = 'q%dsabciJ&#QZk#wM5G!WB36z5m7'
証明書を作成したら、暗号化をサポートする新しい T-SQL 関数 EncryptByCert のいずれかを使用してデータを暗号化できます。次のように定義された Customer という名前のテーブルがあるとします。
CREATE TABLE Customer (
CustId int,
name nvarchar(30),
City varchar(20),
CreditCardType varbinary(300),
CreditCardNumber varbinary(300),
Notes varbinary(4000))
GO
暗号化されたデータはバイナリであるため、テーブルでは varbinary フィールドを使用してそのデータを保存します。暗号化されたデータにはデジタル署名が含まれているため、"Visa" のようにように簡単な文字列とクレジット カード番号を保存する場合であってもフィールドの長さはかなり長くする必要があります。次のコードでは、データの行をこのテーブルに挿入しています。
INSERT INTO Customer VALUES (1, 'Don Kiely', 'Fairbanks',
EncryptByCert(Cert_ID('User1Certificate'), 'Visa'),
EncryptByCert(Cert_ID('User1Certificate'), '1234-5678-8765-4321'),
EncryptByCert(Cert_ID('User1Certificate'),
'This customer is a real flake. Don''t trust him!'))
EncryptByCert は 3 つのパラメータを取ります。Cert_ID 関数で取得できる認証 ID、証明書に付ける名前、および暗号化するデータです。
テーブルからデータを選択するときに、データ暗号化の利点が理解できます。SQL Server Management Studio で SELECT * FROM Customer を実行すると、図 7 に示すような結果になります。INSERT ステートメントでは Encrypt 関数に対して複数の呼び出しを使用するため、各フィールドはさまざまなメソッドを使用して暗号化できます。
図 7 暗号化フィールドを使用したテーブルでの SELECT の実行
データを SELECT ステートメントの一部として復号化する場合は、次のように DecryptByCert を使用します。
SELECT CustID, Name, City,
CONVERT(VARCHAR,
DecryptByCert(Cert_ID('User1Certificate'),
CreditCardType)) AS CardType,
CONVERT(VARCHAR,
DecryptByCert(Cert_ID('User1Certificate'),
CreditCardNumber)) AS CardNumber,
CONVERT(VARCHAR,
DecryptByCert(Cert_ID('User1Certificate'),Notes)) AS Notes
FROM Customer
DecryptByCert は varbinary 型のデータを返すため、通常はこのデータを他のデータ型 (この例では varchar) に変換する必要があります。これにより、図 8 に示すようなクリア テキストが返されます。
.gif)
図 8 DecryptByCert を使用した SELECT
非対称キーで実行される、非常に一般的なタイプの暗号化を公開キー暗号化と呼びます。SQL Server 2005 の非対称キーでは、キーのサイズが 512、1,024、または 2,047 ビットの RSA アルゴリズムが使用されます。指定したパスワードまたはデータベース マスタ キーで生成された秘密キーを暗号化できます。また、ディスク ファイル、実行可能ファイル、メモリに読み込まれた .NET アセンブリからキーをインポートすることもできます。次のコードは、キーの作成に使用するいくつかの方法を示しています。最初の方法では、ユーザーが管理するシークレットを使用し、2 つ目の方法では SQL Server が管理するデータベース マスタ キーを使用しています。
-- ユーザー指定のパスワードで保護された秘密キーで非対称キーのペアを
-- 作成します。
CREATE ASYMMETRIC KEY User1AsymmetricKey
AUTHORIZATION User1
WITH ALGORITHM = RSA_2048
ENCRYPTION BY PASSWORD = 'AVeryVerySecretPassword'
--データベース マスタ キーで保護される別のキーを作成します。
CREATE ASYMMETRIC KEY User2AsymmetricKey
AUTHORIZATION User1
WITH ALGORITHM = RSA_2048
データベースでキーが使用可能になったら、EncryptByAsymKey 関数を使用してデータを暗号化できます。EncryptByCert 関数と同様に、最初のパラメータは使用するキーの ID です。これは、AsymKey_ID 関数で得ることができます。レコード内の暗号化されたすべてのフィールドで同じキーを使用する必要はありませんが、図 9 ではこの方法を使用しています。
図 9 データの暗号化
INSERT INTO Customer VALUES (2, 'Joe Public', 'North Pole',
EncryptByAsymKey(AsymKey_ID('User1AsymmetricKey'), 'MasterCard'),
EncryptByAsymKey(AsymKey_ID('User1AsymmetricKey'),
'8765-4321-1234-5678'),
EncryptByAsymKey(AsymKey_ID('User1AsymmetricKey'),
'A total sucker. Sell him up!'))
INSERT INTO Customer VALUES (3, 'Jane Doe', 'Ester',
EncryptByAsymKey(AsymKey_ID('User2AsymmetricKey'), 'Discover'),
EncryptByAsymKey(AsymKey_ID('User2AsymmetricKey'),
'9999-8888-7777-6666'),
EncryptByAsymKey(AsymKey_ID('User2AsymmetricKey'),
'Favors shoes of every style and color.'))
DecryptByAsymKey 関数を使用して各列のデータを復号化し、もう一度データの暗号化に使用した非対称キーの名前で AsymKey_ID 関数を使用します。図 10 では、パスワードを使用して User1AsymmetricKey が作成されているため、そのパスワードを DecryptByAsymKey 関数呼び出しの 3 つの目のフィールドとして渡す必要があります。通常は CONVERT 関数を使用して varbinary 型のデータを判読可能なデータに変換する必要があります (図 10 を参照)。
図 10 DecryptByAsymKey による復号化
-- 復号化されたデータを表示します。秘密キーの保護に使用するパスワードを
-- 渡す必要があります。
SELECT CustID, Name, City,
CONVERT(VARCHAR,
DecryptByAsymKey(AsymKey_ID('User1AsymmetricKey'),
CreditCardType, N'AVeryVerySecretPassword')) AS CardType,
CONVERT(VARCHAR,
DecryptByAsymKey(AsymKey_ID('User1AsymmetricKey'),
CreditCardNumber, N'AVeryVerySecretPassword')) AS CardNumber,
CONVERT(VARCHAR,
DecryptByAsymKey(AsymKey_ID('User1AsymmetricKey'),
Notes, N'AVeryVerySecretPassword')) AS Notes
FROM Customer WHERE CustID = 2
データベース マスタ キーで作成され、User2AsymmetricKey で暗号化されたデータの場合 (図 11 を参照)、SQL Server がキーを管理しているため、どの資格情報も渡す必要はありません。これを見れば、SQL Server にキーを管理させた方がはるかに簡単であることがわかってくるはずです。
図 11 証明書を渡さない復号化
-- CustID 3 を表示します。データベース マスタ キーで保護されるため、パスワードを
-- 渡す必要はありません。
SELECT CustID, Name, City,
CONVERT(VARCHAR,
DecryptByAsymKey(AsymKey_ID('User2AsymmetricKey'),
CreditCardType)) AS CardType,
CONVERT(VARCHAR,
DecryptByAsymKey(AsymKey_ID('User2AsymmetricKey'),
CreditCardNumber)) AS CardNumber,
CONVERT(VARCHAR,
DecryptByAsymKey(AsymKey_ID('User2AsymmetricKey'),
Notes)) AS Notes
FROM Customer WHERE CustID = 3
SQL Server で非対称キーのペアを作成すると、sys.asymmetric_keys カタログ ビューで他のユーザーに送信するための公開キーを取得できます。sys.asymmetric_keys カタログ ビューでは公開キーが public_key フィールドで公開されます。次のコードでは、作成した非対称キーの各ペアに関連付けられた公開キーが返されます。
SELECT Name, Public_Key FROM sys.asymmetric_keys
特にデータをデータベースの外に移動し、それを移動中に保護する必要がある場合は、証明書と非対称キーにより SQL Server データを強力に暗号化できます。ただし、サーバー上でデータを保護する必要があるだけで、他の場所では保護する必要がない場合は、対称キーを使用することをお勧めします。これは、データを安全に保管し、サーバー上で復号化して、クライアントに送信してから、許可されたユーザーに表示するという、ごく一般的なデータベースシナリオです。対称キーを使用すると、他の暗号化フォームに比べ必要な処理サイクルの数がかなり少なくなります。これはデータベース アプリケーションにとって好都合であるので、SQL Server での対称キー暗号化は柔軟性に富みます。
対称キーの作成は、証明書や非対称キーの作成と似ています。CREATE SYMMETRIC KEY ステートメントには、いくつかのオプションがあります。1 つは、データベース内に保存するときに、キーそのものを暗号化する方法を指定するオプションです。図 5 に示したとおり、証明書、非対称キー、ユーザー指定のパスワード、または別の対称キーを使用して対称キーを保護することができます。他にも、使用する暗号化アルゴリズム、ユーザー指定のパスフレーズを使用してキーを生成するかどうか、オプションの ID 語句などを指定するオプションがあります。この語句は、一時キーで暗号化したデータをタグ付けするために使用する GUID を生成します。SQL Server は、DES、トリプル DES、AES など、一般的に使用されている対称キー アルゴリズムのほとんどをサポートしています。アルゴリズムは、サーバー上の Windows にインストールする必要があります。
対称キーを作成したり、キーをユーザー自身が管理するか SQL Server に管理させるかを指定するオプションを検討する際に、オプションのパスワードを保護するかどうかを検討することが重要です。キーを暗号化するパスワードを指定すると、作成された対称キーでデータを暗号化する際に使用するアルゴリズムに関係なく、トリプル DES を使用してパスワードからキーを導き出されます。この場合、キーを保護しているパスワードの保護よりも、データの保護により強力な暗号化を使用する可能性が高くなります。
図 12 は、対称キーの作成に関連する多くのオプションの一部を示しています。最初の例では、トリプル DES を使用し、既存の証明書によって保護されるキーを作成し、作成したキーの所有権を User1 に付与しています。対称キーとは異なり、証明書を使用するためには証明書を明示的に開く必要がありません。2 つ目の例でも同じような対称キーを作成していますが、証明書の代わりに、パスワードを指定してキーを管理しています。3 つ目の例では、キーは dbo が所有しているため、AUTHORIZATION 句が省略され、RC4 アルゴリズムが使用されています。この例では、既存の非対称キーを使用して、新しい対称キーを保護しています。最後の例では、dbo が所有する別の対称キーを作成し、DESX を使用してデータを暗号化していますが、キー自体は別の対称キーによって保護されています。既存の対称キーを使用して新しいキーを暗号化する前に、既存のキーを明示的に開いておく必要があります。
図 12 SQL Server 2005 での対称キーの作成
-- 証明書で保護されるキーをトリプル DES を使用して作成し、User1 と
-- 関連付けます。
CREATE SYMMETRIC KEY User1SymmetricKeyCert
AUTHORIZATION User1
WITH ALGORITHM = TRIPLE_DES
ENCRYPTION BY CERTIFICATE User1Certificate
-- パスワードで保護されるキーをトリプル DES を使用して作成し、User2 と
-- 関連付けます。
CREATE SYMMETRIC KEY User2SymmetricKeyPwd
AUTHORIZATION User2
WITH ALGORITHM = TRIPLE_DES
ENCRYPTION BY PASSWORD = 'AGreatPassword'
-- 非対称キーで保護され、dbo が所有するキーを RC4 を使用して作成します。
CREATE SYMMETRIC KEY GenericSymmetricKeyAsym
WITH ALGORITHM = RC4
ENCRYPTION BY ASYMMETRIC KEY User2AsymmetricKey
-- 別の対称キーで保護され、dbo が所有するキーを DESX を使用して
-- 作成します。
OPEN SYMMETRIC KEY User1SymmetricKeyCert
USING CERTIFICATE User1Certificate
CREATE SYMMETRIC KEY GenericSymmetricKeySym
WITH ALGORITHM = DESX
ENCRYPTION BY SYMMETRIC KEY User1SymmetricKeyCert
CLOSE SYMMETRIC KEY User1SymmetricKeyCert
対称キーで暗号化されたデータを挿入および選択する方法は証明書および非対称キーの場合と似ていますが、サンプル コードのダウンロード (MSDN Magazine Web サイトから入手可能) を見ればわかるように、こちらの方が若干手間がかかります。このコードは、データの変換に EncryptByKey および DecryptByKey 関数を使用し、Key_GUID 関数を使用して指定されたキーの ID も取得しています。対称キーを使用する前にそのキーを明示的に開いておかないと、データベース マスタ キーで暗号化されるキーは作成できません。例では、GenericSymmetricKeySym キーを作成および使用しています。このキー自体が User1SymmetricKeycert によって保護されているため、使用するキーを保護する対称キーを最初に開いておく必要があります。これでわかるように、複数の対称キーを、データベースでいつでも開いておくことができることができます。SQL Server はデータの復号化に使用するキーを認識しているので、DecryptByKey 関数でそのキーを指定する必要はありません。
SQL Server 2005 の暗号化実装で最も興味深い利点の 1 つは、ユーザーは自分のデータのみを表示できるという点です。この記事の多くの例でも取り上げた AUTHORIZATION 句を使用して、キーまたは証明書の所有権をユーザーに付与し、そのユーザーは、他のユーザーにそのデータを参照する権限を付与できます。
ページのトップへ
6. まとめ
SQL Server 2005 は、データベース エンジンのセキュリティをこれまでにない新しいレベルでサポートします。SQL Server 2005 には、セキュリティで保護されたサーバーのデータにアクセスできる安全なアプリケーションを作成するための、開発者向け機能が豊富に用意されています。きめの細かい権限により最小特権のセキュリティ原則を順守し、ジョブの実行に必要な権限のみをユーザーに付与することで、攻撃者によって余分な権限が利用されるのを防ぎます。SQL Server 2005 のこれらおよびその他のセキュリティ拡張には、今日の巧妙なデータ攻撃に対処するためのツールがすべて備わっています。
Don Kiely は、MVP (Most Valuable Professional) 、および MCSD (Microsoft Certified Solution Developer) の資格を持つ、分散 Windows フォームおよび ASP.NET アプリケーションの開発におけるセキュリティを専門とするシニア テクノロジ コンサルタント兼開発者です。また、テクノロジに関する著作を執筆したり、講演会や講習会の講師としても活躍しています。Don へのお問い合わせは、donkiely@computer.org (英語) までご連絡ください。
この記事は、MSDN マガジン - 2005 年 6月号からの翻訳です。