セキュリティに関するブリーフィング
脅威モデルによりセキュリティ プロセスを強化する
Michael Howard

目次
このコラムでは、脅威モデルを使用して主にコード レビュー、ファジー テスト、攻撃対象領域分析タスクの優先順位を付けるために役立てることで、セキュリティ エンジニアリング プロセスを促進し、より全体論的な観点から安全な設計について検討する方法を紹介します。
このコラムの準備として、まずは SDL (セキュリティ開発ライフサイクル) のブログにある Jeremy Dallman の「
'Crawling' Toward SDL (SDL をゆっくり開始する)」をお読みになることをお勧めします。このコラムで扱っている概念が Jeremy の考えと非常に一致していることにお気付きになるでしょう。そして、SDL を使ってゆっくり動き出し、歩き出すことから始めて、最終的に疾走できるようになるにつれ、セキュリティへの取り組みに秩序と正確さがもたらされるようになります。
ここで紹介するのは、脅威モデルを使用して、主にコード レビューとファジー テストの優先順位付けや攻撃対象領域の削減など、SDL の他のセキュリティ要件の促進を図ることです。必要な作業はこれだけです。では、そろそろ説明に移って、それぞれについて詳しく見ていきます。脅威のモデル化から始めましょう。
脅威のモデル化
MSDN Magazine の多くの読者は脅威のモデル化という概念をよく理解しています。Adam Shostack は 2008 年 7 月号の (「
脅威のモデル化プロセスをよみがえらせる」) でこのテーマに関する優れた記事を書いており、
脅威のモデル化プロセスの未来について SDL ブログで詳しく紹介しています。
これは筆者の考えですが、セキュリティの脆弱性について考えるとき、ほとんどの人は実装バグを思い浮かべるようです。SDL は実装バグをやや重視しすぎたのではないかという意見もあるようですが、これは従来マイクロソフトが訂正してきた脆弱性の大部分が実装バグに由来していたためです。ところが、ここ数年は安全な設計に重点を置くために多くのリソースを確保するようになってきており、これは SDL のおかげで実装バグが減ってきたためでもあります。
脅威のモデル化は、開発チームが構造化された手法で安全な設計について検討することを可能にするため、SDL の基礎となります。脅威のモデル化プロセスは、効率的に、以下のタスクに簡素化されます。
- ソフトウェアのデータ フローを図示する。
- "要素ごとの STRIDE" 手法を使用して、設計に該当する脅威を見つける。
- 各脅威に対処する。
- ソフトウェアのモデル化が十分に行われていること、各脅威を考慮していること、および検出されたすべての脅威に対処していることを確認する。
脅威モデルの中心的な要素は、アプリケーションのエントリ ポイントの描写です。脅威モデルでは、"図の描写" フェーズ中にエントリ ポイントを信頼できる境界として取り込みます。たとえば、ネットワーキング エントリ ポイントや、ファイルとレジストリのエントリ ポイントなどがあります。
優れた脅威モデルでは、ネットワーク アクセシビリティとインターフェイスの認証または承認要件についても取り込む必要があります。これには、IP アドレスを介したネットワーク アクセシビリティが含まれます (ローカルおよびリモート、ローカル サブネット、およびローカルのみのアクセス)。さらに、認証と承認のレベル、匿名アクセス、ユーザー アクセス、および管理者のみのアクセスも含まれます。Windows アクセス制御リスト (ACL) では承認レベルがより詳細に分類されますが、詳細になり過ぎる必要はありません (ACL の詳細な説明については、今月号の John Michener の記事「
Windows のファイルとレジストリのアクセス許可について」をお読みください)。単純さを維持します。
脅威モデルで取り込まれるもう 1 つの重要なデータは、プロセス ID です。エントリ ポイントとは単にプロセスで実行されるコード部分へのインターフェイスであり、高い特権を持つプロセスは侵害された場合に非常に危険です。Windows の場合、最も特権が高いプロセスは SYSTEM または管理者として実行するプロセスです。Linux または Mac OS X の場合、ルートとして実行するプロセスが最も高い特権を持ちます。
アプリケーションの各エントリ ポイントでは、以下のデータを記録する必要があります。
- エントリ ポイント名
- ネットワーク アクセシビリティ
- 認証と承認
- プロセス名とプロセス ID
- コメント (必要に応じて)
図 1 に、例をいくつか示します。最初のネットワーク ポートは、地球上のすべての人に公開されているため、最も公開度が高いということが明らかです。公開度が最も高いエントリ ポイントは、攻撃を受ける危険性が最も高いエントリ ポイントとなります。これは、リモート アクセスが可能であり、同じネットワーク (この場合はインターネット) 上のコンピュータを使うすべての人がアクセスできるためです。匿名ユーザーによるアクセスが可能であることは、認証または承認なしでアクセスできることを意味します。そのため、匿名ユーザーによるリモート アクセスが可能なエントリポイントには実際にだれもがアクセスすることができ、その中には悪意を持った多数の人々が含まれます。

図 1 プロセスのエントリ ポイント
| エントリ ポイント |
ネットワーク アクセシビリティ |
認証と承認 |
プロセス |
コメント |
| TCP/1234 |
リモート |
匿名 |
App.exe (SYSTEM) |
メインの要求/応答 |
| \\.\pipe\admin |
リモート |
管理者 |
App.exe (SYSTEM) |
管理の名前付きパイプ |
| ncacn_ip_tcp 609b954b-4fb6-11d1-9971-00c04fbbb345 |
リモート |
認証済みユーザー |
User.exe (Network Service) |
ユーザーのアカウント情報 RPC インターフェイス |
| Config.xml |
ローカル |
管理者 |
App.exe (SYSTEM) |
アプリケーション構成ファイル |
管理の名前付きパイプにはリモート (およびローカル) 管理者のみアクセスすることができ、これは ACL を使用して適切に実施されます。名前付きパイプを含む Windows のすべての名前付きオブジェクトに対して ACL を検証することが重要です。
また、SYSTEM として実行するコード内に多数のエントリ ポイントがあることにもお気付きでしょう。認証されていないリモート アクセスが可能なエントリ ポイントと、SYSTEM として実行するプロセスの組み合わせは、Windows で可能な限り最も大きい公開ポイントとなります。このコード内にセキュリティ バグが存在していた場合、何者かがどこからでもコードを失敗させることができます。悪用されたコードは SYSTEM として実行するため、コンピュータが完全に乗っ取られます。これについては、後で詳しく述べます。
公開の程度に応じて、コード レビューとファジー テストに優先順位が付けられます。これについては、次で説明します。
コード レビューとファジー テストの優先順位
多くのコードがレビューとテストを必要としていることについて考えてみます。しかし、今後 10 年間起きている時間をすべてコードのレビューに費やすことはできず、ある時点で製品を顧客に納入する必要があります。このため、セキュリティの取り組みに優先順位を付けて、最も危険なコンポーネントから先に最も丹念に取り組む必要があります (最も危険なコンポーネントを探すためのヒントとして、「悪意のある攻撃者はだれか」のリンクを参照することをお勧めします)。したがって、最も危険なコードからレビューとファジー テストを開始します。
手動によるコードのレビューでは、最も公開度が高いコードから先にレビューすることが重要です。たとえば、図 2 に、TCP/1234 ソケットのコード例を示します。recv の呼び出しでは認証されていないリモート ネットワーク ポートからの読み取りを行っているため、検証が済むまで buf を有害なものとして扱う必要があります。セキュリティの分野では、このデータはたいてい汚染されていると見なされ、精度や構造に依存することはできません。

図 2 問題の可能性のあるバッファ
SOCKET remoteSocket = accept(listenSocket,NULL, NULL);
if (remoteSocket == INVALID_SOCKET) {
PRINTERROR("accept()");
closesocket(listenSocket);
return;
}
// Receive data from the client
char szBuf[256];
memset(buf, 0, sizeof(buf));
nRet = recv(remoteSocket,
buf, // Danger!
sizeof(buf),
0);
if (nRet == INVALID_SOCKET) {
PRINTERROR("recv()");
closesocket(listenSocket);
closesocket(remoteSocket);
return;
}
// process data in buf
コード レビューを少し簡単にするために、ソース コードの場所と、エントリ ポイントの API 呼び出しとデータが含まれている表を作成します (図 3 を参照)。これに基づき、エントリ ポイントの API から受信データを検証または浄化するコードまでデータを追跡します。データの整合性を検証するコードが存在せず、受信データに対して危険を伴う可能性のある操作を実行している場合は、良くてコーディング バグですが、最悪の場合は深刻な脆弱性が生じる場合があります。コードの動作にかかわらず、データの形式が適切であると想定してはなりません。

図 3 エントリ ポイントの分析
| エントリ ポイント |
ソース ファイル |
API とデータ |
| TCP/1234 |
Readfromsocket.cpp |
recv(,buf,) |
| \\.\pipe\admin |
AdminConsole.cpp |
ReadFile(,bCommand) |
| ncacn_ip_tcp 609b954b-4fb6-11d1-9971-00c04fbbb345 |
UserInfo_i.c and UserInfo.idl |
さまざま |
| Config.xml |
Config.cpp |
ReadFile(,bFileContents) |
ファジー テスト
最後の行の "データの形式が適切であると想定してはなりません" に戻って考えてみます。ファジー テストの目標は、この想定が可能であるかどうかを判断し、これが可能な場合は、こうした想定に違反する何者かがアプリケーションを失敗に導くことができるかどうかを判断することです。ファジー テストについては MSDN Magazine で何度も取り上げられて来たためここでは説明しませんが (たとえば、
Dan Griffin の記事「ファジー テスト: チーム システム向けにカスタム テスト インターフェイス プロバイダを作成する」を参照してください)、ファジー テストをどのように使うことができるかについて説明します。
コード レビューと同様、すべての可能なコード パスでファジー テストを実施することはできないため、公開の程度に応じて優先順位を付ける必要があります。したがって、最も公開度が高いエントリ ポイントから先にファジー テストを実施します。ここに挙げた単純な例では、TCP/1234 エントリ ポイントから先に、何度も厳しくテストすることになります。実際、筆者は常にこのエントリ ポイントのファジー テストを実行しています。ともあれ、CPU 時間はかなり安価です。
ここでもう少し踏み込んで、なぜこのインターフェイスがこれほど広く公開されているのかを考えたいと思います。この公開を既定で絞り込むことは可能でしょうか。そこで、攻撃対象領域の削減という手法を使います。
攻撃対象領域の削減
これまでに何度も言いましたが、もう一度言わせてください。完璧に正しいコードを作成することは決してできないため、正しいコードを作成するよう努めると同時に、攻撃対象領域を削減することが重要です。この呪文については、2004 年 11 月号の筆者の記事「
攻撃対象領域: 信頼されていないユーザーに公開されるコードの最小化によりセキュリティ リスクを緩和する」で詳しく述べています。この記事について簡単に説明します。顧客に被害が及ぶ可能性を減らすためには、攻撃対象領域を削減しなくてはなりません。結局、あらゆる攻撃者に公開されているインターフェイスはローカル サブネット上の攻撃者のみに公開されているインターフェイスに比べて危険度が高くなります。これは単に、後者のシナリオでは潜在的な攻撃者が少ないためです。
ここに挙げた例では、TCP/1234 エントリ ポイントでの認証を既定で行い、認証されたユーザーのみがアクセスできるようにします。これは基本認証 (問題のある認証方法であることはわかっています) または Kerberos などのより複雑な認証方法を使用して、簡単に行えます。これは既定の方法ですが、システム管理者は匿名アクセスに変更しようと思えば変更できます。管理者はこれについて決断する必要があります。
アプリケーションに認証を追加した場合は、認証プロセスと認証資格情報データベースがシステムに追加されるため、脅威モデルの更新が必要となることに注意してください。
特権を低く抑える
攻撃対象領域を削減するためのもう 1 つの要素とは、アプリケーションの特権を低く抑えることです。これについて、次に説明します。SYSTEM として実行するプロセスを覚えているでしょうか。侵害がもたらす被害の可能性を減らすには、特権が低いアカウントの使用を検討する必要があります。これは、攻撃対象領域の削減におけるもう 1 つの重要な点です。
最も公開度が高いエントリ ポイントから開始します。この記事の例で、TCP/1234 の匿名アクセスを既定で許可するように決定した場合は、そのポートでリスンしているプロセスがなぜ SYSTEM として実行する必要があるのかを確かめる必要があります。アカウントの特権を低く抑えることは可能でしょうか。
また、2 つのネットワーク エントリ ポイントと 1 つのファイル エントリ ポイントがすべて同じプロセスで実行していることに注意してください。これは適切でしょうか。エントリ ポイントの 2 つは管理者用であり、1 つは匿名ユーザー用です。特権が低いプロセス ID を利用するために、このプロセスから 2 つの個別のプロセスへの分割を検討する必要があります。
IIS 6.0 および IIS 7.0 アーキテクチャを調べると、匿名要求およびリモート ユーザー要求を処理するプロセス (w3wp.exe) は Network Service として実行し、メインの管理プロセス (inetinfo.exe) は SYSTEM として実行していることに気付きます。後者のプロセスは管理者用に制限されています。IIS 4.0 および IIS 5.0 では、たいていの場合、プロセス処理と管理アクセスは特権の高い 1 つのプロセスによって実行されていました。
興味深いことに、攻撃対象領域の削減のいくつかの要素は従来的に知られているものです。それらは伝統的な Saltzer と Schroeder による安全な設計原則の一部であり、最小特権および最小共通性のメカニズムが含まれています。
最小共通性のメカニズムという 2 番目の概念については、少し説明が必要です。これは、複数のユーザーまたはユーザー タイプで共有されるコードの量を削減する必要があることを意味します。この記事の例では、管理タスクと匿名ユーザー要求を実行している単一プロセスで危険が生じる可能性があります。この対策としては、IIS の動作に従い、単独の ID として個別のタスクを実行する 2 つのプロセスにアプリケーションを分割します。
まとめ
正直に言うと、このコラムで定義している新しい手法や概念はありません。すべては SDL に含まれています。しかし、このコラムでは、SDL で定義、説明、および要求されているセキュリティの多くの規律の間にある暗黙的な関係について説明し、顧客に納入する製品の安全性をより高めるために必要な多くのセキュリティの取り組みが、優れた脅威モデルによってどのように簡素化されるかについて示しています。
優れた脅威モデルを作成し、公開する場所を決定し、公開度で順位付けされたエントリ ポイントの一覧を使用して、コード レビューとファジー テストに優先順位を付け、最終的に攻撃対象領域を削減するために役立ててください。これは、ソフトウェアの安全性の向上につながります。
セキュリティについてのあなたの理解度を試してみませんか。今月号の興味深い
セキュリティ IQ のテストに挑戦してください。
Michael Howard は、マイクロソフトのプリンシパル セキュリティ プログラム マネージャとして、セキュリティを向上させるためのプロセスの改善とベスト プラクティスに取り組んでいます。また、『Writing Secure Code for Windows Vista』、『The Security Development Lifecycle』、『Writing Secure Code』、『19 Deadly Sins of Software Security』など、セキュリティに関する多数の書籍を共同執筆しています。