ゲーム開発でのベスト セキュリティ プラクティス

XNA デベロッパー コネクション (XDC)

2007 年 2 月

はじめに

オンライン ゲームやユーザーがコンテンツを作成したゲームを利用する人が増えています。これに加えて Microsoft® Windows® オペレーティング システムのセキュリティが強化されたことから、ゲームが狙いやすい標的として攻撃者に悪用されることが増えてきました。ゲーム開発者は、自らがリリースするゲームが攻撃者に悪用される新たなセキュリティ ホールを作り出していないことを十分に確認する必要があります。顧客のコンピューターが悪質なネットワーク データ、ユーザーによる改造、改ざんなどによってハッキングされないようにすることは、ゲーム開発者の責任であり、利害にも関係します。脆弱性が悪用されると、結果的に顧客を失い、金銭的な損失を被ることになりかねません。この記事では、開発時間を増大させずにコードのセキュリティを強化するための一般的な方法とツールについて説明します。

開発チームが製品をリリースする際に最もよく犯す 3 つのミスがあります。

  1. 管理者権限を要求している。ゲームでは管理者権限を要求しないようにする必要があります。詳細については、「ゲーム開発者向けのユーザー アカウント制御」を参照してください。
  2. 保護を自動化していない。一般に、開発者は /GS/SAFESEH、または /NX を使用しません。このようなコンパイル/リンク フラグを使用すると、作業量をそれほど増やすことなく基本的なセキュリティ ホールを数多く見つけて解消することができます。これらのフラグについては、後で説明します。
  3. 禁止された API を使用している。プログラマ エラーを起こしやすく、セキュリティ ホールを簡単に作り出す API (strcpystrncpy など) が数多くあります。開発者は、このような API を安全なバージョンに置き換える必要があります。Visual Studio 2005 にはバイナリ ファイルを分析するツールが付属しており、安全でない API を参照しているオブジェクト ファイルを自動的にチェックできます。このツールで生成される情報の利用方法の詳細については、Martyn Lovell による「Repel Attacks on Your Code with the Visual Studio 2005 Safe C and C++ Libraries (Visual Studio 2005 の安全な C/C++ ライブラリを使用してコードへの攻撃を撃退する)」を参照してください。

ここに挙げたミスは、よく起きるだけではなく、開発作業量、コーディング標準、または機能性を大きく変えることなく簡単に修正できます。

安全でないコードの例

攻撃者によるバッファー オーバーラン攻撃の実行を可能にする単純な例を次に示します。

void GetPlayerName(char *pDatafromNet)
{
    char playername[256]; 
    strncpy(playername, pDatafromNet, strlen(pDatafromNet));

    // ...
}

このコードは、安全な関数を呼び出しており、表面上は問題がないように見えます。ネットワークからのデータは、256 バイトのバッファーにコピーされます。strncpy 関数は、ソース文字列の NULL 終端文字列の検出に依存するか、指定されたバッファー数によって制限されます。問題は、バッファー サイズが間違っていることです。ネットワークからのデータが検証されなかったり、この例のようにバッファー サイズが間違っていたりすると、バッファーが終了した後に、攻撃者が大きなバッファーを供給してネットワーク パケット内のデータでスタック データを上書きすることが可能となります。これにより攻撃者は、命令ポインターを上書きし、リターン アドレスを変更して、任意のコードを実行できるようになります。この例の最も根本的な教訓は、検証されるまで入力を信頼してはならないということです。

データが最初にネットワークから取得されたものではない場合でも、潜在的なリスクがあります。最近のゲーム開発では、多数の人員が同じコード ベースの設計、開発、テストに携わります。関数が後からどのように呼び出されるかを知る術はありません。データがどこから取得されたものか、攻撃者に制御されそうな箇所がないかを常に意識してください。最も多いのはネットワークベースの攻撃ですが、セキュリティ ホールを作り出す方法はそれだけではありません。攻撃者がセキュリティ ホールを突いて保存されたファイルを変更または編集する可能性はないでしょうか。ユーザーから提供された画像ファイルや音声ファイルはどうでしょうか。この種のファイルの悪質なものがインターネット上に投稿され、顧客に危険なセキュリティ リスクをもたらすおそれがあります。

補足すると、この例を修正するには、strncpy の代わりに strsafe.h または Safe CRT を使用します。Safe CRT は、C ランタイムのセキュリティを全面的に見直したもので、Visual Studio 2005 に付属しています。Safe CRT の詳細については、Michael Howard による「CRT のセキュリティ強化」を参照してください。

セキュリティを強化する方法

開発サイクルでセキュリティを強化する方法がいくつかあります。ここでは、最も効果的な方法の一部を紹介します。

  1. セキュリティに関する書籍を読む。

    Michael Howard と David LeBlanc による『Writing Secure Code, Second Edition』(日本語版は『Writing Secure Code 第 2 版 - プログラマのためのセキュリティ対策テクニック』(日経 BP ソフトウェアプレス発行)) には、攻撃を防止し、悪用を抑制するための戦略と方法が詳細かつ明解に説明されています。この書籍には、セキュリティを設計してリリースに組み込む方法から、ネットワーク アプリケーションをセキュリティで保護するテクニックに至る、ゲーム開発者が開発者自身、製品、顧客を攻撃者から保護するために必要となるすべての要素が盛り込まれています。この書籍を使用して、開発の現場にセキュリティの文化を浸透させることができます。コード セキュリティは、開発者やテスターだけの問題ではありません。セキュリティは、プログラム マネージャーからデザイナー、開発者、テスターに至るチーム全体が、プロジェクトに取り組む際に考えなければならない問題です。レビュー プロセスに関わる人数が多いほど、リリース前にセキュリティ ホールを発見できる可能性が高くなります。

    『Writing Secure Code 第2版 - プログラマのためのセキュリティ対策テクニック』は、Microsoft Learningで紹介されています。セキュリティに関する全般的な情報については、Michael Howard による「Fending Off Future Attacks by Reducing Attack Surface (攻撃対象領域を縮小して攻撃を回避する)」を参照してください。

    Michael Howard、David LeBlanc、John Viega がこの話題を一般的なオペレーティング システムとプログラミング言語に広げて書いたもう 1 冊の書籍が『19 Deadly Sins of Software Security』です。

    ゲームに焦点を絞ったセキュリティ関連のプレゼンテーションについては、「Microsoft XNA Developer Presentations (Microsoft XNA デベロッパー プレゼンテーション)」ダウンロード ページにアクセスしてください。

  2. 脅威モデリングの分析

    脅威モデリングの分析は、特定の言語やツールを使用するのではなく、数回のミーティングで完了する幅広いエンド ツー エンド方式でシステム セキュリティを評価できる優れた方法です。スレッド モデルを適切に実装すれば、プロジェクトの作業量やミーティングの時間を大幅に増やすことなく、システムの強みと弱点をすべて突き止められます。また、脅威モデリングでは、開発プロセスの実行前と実行中にシステム セキュリティを評価するという考えを重視して、包括的な評価を行いながら、最もリスクの高い機能を絞り込みます。この方法は、セキュリティのプロファイラーと考えることもできます。脅威モデリングは特定の言語やツールに基づいていないので、あらゆるジャンルのあらゆるプロジェクトに携わるあらゆる開発現場で使用できます。脅威モデリングは、セキュリティが他人の問題ではなく全員の責任であるという考えを強調している点でも優れています。

    脅威モデリングでは、次の要素に特に注意する必要があります。

    • UDP データ ソース
    • 認証を必要としないデータ ソース
    • 通常は大規模な情報収集の一環として検査されることが多いデータ ソース
    • クライアント間で直接データを送信する機能

    ここに挙げたのは、セキュリティの脆弱性が高いと思われる領域です。

    脅威モデリングについては、MSDN Security Development Center の「Threat Modeling (脅威モデリング)」および Frank Swiderski と Window Snyder による『Threat Modeling』(日本語版は『脅威モデル - セキュアなアプリケーション構築』(日経 BP 出版センター出版)) で詳しく説明されています。

  3. データ実行防止 (/NX)

    さまざまな悪用を抑制する最新のツールがデータ実行防止 (DEP) です。ビルド コマンドに /NX スイッチを組み込むと、Visual Studio で、コードに実行権限があるかどうかを示すフラグを使ってメモリー ページがマークされます。EXECUTE 権限のフラグが設定されていないメモリー ページでプログラムを実行しようとすると、プログラムが強制終了されます。実行防止はプロセッサ レベルで実施され、自身で改造したコードまたはネイティブ JIT 言語コンパイラを使用している開発者に影響を与えます。現時点では、AMD の Athlon64 と Opteron の両プロセッサ、Intel の Itanium プロセッサと最新の Pentium 4 プロセッサのみが実行防止をサポートしていますが、将来的にはすべての 32 ビット プロセッサと 64 ビット プロセッサが実行防止をサポートすると見込まれています(開発者が使用するコピー防止スキームが実行防止の影響を受ける可能性がありますが、Microsoft ではコピー防止機能のベンダーとこの影響を最小限に抑えるように取り組んできました)。DEP を習慣的に使用することをお勧めします。

    DEP の詳細については、「Data Execution Prevention (データ実行防止)」を参照してください。

  4. バッファー セキュリティ チェック (/GS) と安全な例外ハンドラーがあるイメージ (/SAFESEH)

    コンパイラ フラグ /GS で指定されるバッファー セキュリティ チェック、およびリンカー フラグ /SAFESEH で指定される安全な例外ハンドラーがあるイメージ (Visual Studio .NET 2003 で導入) を使用すると、開発者がコードをセキュリティで保護する作業が少し楽になります。

    /GS フラグを使用すると、関数のリターン アドレスを上書きする目的で悪用されるある種のスタックベースのバッファー オーバーランに対するチェックがコンパイラによって構築されます。/GS を使用してもあらゆるバッファー オーバーランを検出できるわけではないので万全の対策と見なすことはできませんが、多層防御技術として優れています。

    /SAFESEH フラグを使用すると、安全な例外ハンドラーのテーブルを生成できる実行可能ファイルまたは DLL のみをリンカーが生成するようになります。安全な構造化例外処理 (SafeSEH) では、バッファー オーバーラン攻撃の対象としての例外処理を排除するために、例外がディスパッチされる前に、例外ハンドラーがイメージ ファイル内の関数テーブルに登録されているかどうかが確認されます。この保護を利用できるのは、Windows XP SP2、Windows Server 2003、および Windows Vista です。また、/SAFESEH を適切に機能させるには、このフラグをオール オア ナッシングの方式で使用する必要があります。つまり、実行可能ファイルまたは DLL にバインドされているコードを含んでいるすべてのライブラリを /SAFESEH でコンパイルしないと、テーブルは生成されません。

    バッファー セキュリティ チェック (/GS) および 安全な例外ハンドラーがあるイメージ (/SAFESEH) の詳細については、MSDN を参照してください。

  5. PREfast

    PREfast は Microsoft が提供するフリー ツールで、コンパイルされた C または C++ の実行パスを分析してランタイム バグの検出を支援します。PREfast はすべての関数のすべての実行パスを調べ、各パスに問題がないかを判定します。このツールは、元々はドライバーやその他のカーネル コードの開発に使用されていましたが、一部の見つかりにくいバグやコンパイラで無視されるバグを除去することから、ゲーム開発者の時間節約にも役立ちます。PREfast を使用することで、効果的に作業量を削減し、開発チームとテスト チーム双方の作業を集中化することができます。PREfast は、Visual Studio Team Suite および Visual Studio Team Edition for Software Developers でコード分析として提供されており、コンパイラ スイッチ /analyze によって使用可能になります(このオプションは、Windows Software Development Kit 付属のフリー版コンパイラでも提供されています)。

    PREfast では、ヘッダー注釈を使用することで (特にバッファー ポインター引数に対して)、メモリー上書きバグ、クラッシュの共通原因、潜在的なセキュリティの脆弱性などの別の問題も検出できます。そのためには、Standard Annotation Language (SAL) を使用します。SAL は、必要なポインター引数のセマンティクスと相関関係に関する追加情報を、長さのパラメーターや宣言されたバッファー サイズなどで提供する C/C++ 関数プロトタイプに対する一種のマークアップです。Windows オペレーティング システムのすべてのヘッダーには注釈が付けられており、ユーザー独自のライブラリ内でパブリック API ヘッダーに SAL マークアップを追加すると、PREfast によってクライアント コード内でこのような API に対する詳細かつ強力なチェックが実行されます。SAL の概要および詳細情報へのリンクについては、Michael Howard のブログの記事「A Brief Introduction to the Standard Annotation Language (SAL) (Standard Annotation Language (SAL) の概要)」を参照してください。

  6. Windows Application Verifier

    Windows Application Verifier (AppVerifier) は、テスター向けの複数の機能を 1 つのツールにまとめたものです。AppVerifier は、よくあるプログラミング エラーを簡単にテストできるようにするために開発されたツールです。AppVerifier では、API 呼び出しに渡されたパラメーターをチェックし、間違った入力を与えてエラー処理機能を確認し、さらにレジストリとファイル システムに対する変更をログに記録することができます。また、AppVerifier はヒープでのバッファー オーバーランを検出し、アクセス制御リスト (ACL) が正しく定義されていることをチェックし、ソケット API が安全に使用されるようにします。AppVerifier は包括的なツールではありませんが、テスターのツールボックスに入れておけば、開発現場から良質の製品をリリースするために役立ちます。

    Windows Application Verifier の詳細については、Michael Howard による「Analyzing Your Applications with Windows Application Verifier (Windows Application Verifier を使用したアプリケーションの分析)」を参照してください。

  7. ファジー テスト

    ファジー テストは、現在のテスト手法を強化する半自動化されたテスト方法です。ファジー テストの中心的な意図は、ランダムなデータを入力することですべての入力を完全に評価して問題を特定することです。これには、あらゆるネットワーク データ、変更箇所、保存されたゲームなどが含まれます。ファジー テストはきわめて簡単に実行できます。ランダムなバイトの挿入、隣接するバイトの反転、数値の無効化によって、適格なファイルまたはネットワーク データを変更するだけです。ファジー テストでセキュリティ ホールを突き止めるには、0xff、0xffff、0xffffffff、0x00、0x0000、0x00000000、0x80000000 の各値が役立ちます。結果として生じるインタラクションの組み合わせは、AppVerifier を使用して確認できます。ファジー テストは包括的ではありませんが、実装と自動化が容易であり、見つかりにくいバグや予想不可能なバグを検出することができます。

    ファジー テストの詳細については、「Gamefest 2007 Presentations」の「Practical Steps in Game Security (ゲーム セキュリティの具体的なステップ)」を参照してください。

  8. Authenticode 署名

    Authenticode は、ユーザーが受け取る実行可能ファイル、DLL ファイル、および Windows インストーラー パッケージ (.msi ファイル) が、リリース後に改造されていないことを保証する方法です。Authenticode では、暗号化の原則、信頼された団体、および業界標準を使用することで、実行可能コンテンツの完全性を検証します。Microsoft では、署名されたコードの改ざんを自動検出するための CryptoAPI という暗号化 API を提供しています。リリース後にセキュリティ リークが発生した場合は、証明書が失効し、その証明書で署名されたすべてのコードの認証が停止されます。証明書が失効すると、その証明書で署名されているすべてのタイトルの検証が無効になります。Windows は Authenticode 署名と連携するように設計されており、特定の状況で、署名されていないコードのユーザーに対して PC が攻撃を受ける可能性があることを警告します。

    Authenticode は、セキュリティの不備を解消する方法ではなく、実行可能ファイルがリリースされた後の改ざんを検出する方法です。悪用可能なセキュリティの不備がある実行可能ファイルや DLL は、Authenticode を使用して署名して検証することはできても、新たなシステムにセキュリティの不備をもたらします。製品またはアップデートが安全であると検証されるまでは、リリースが改ざんされていないことをユーザーに保証する署名をコードに対して行わないでください。

    リリースが改造されるおそれはないと開発者が思っていても、他のテクノロジやサービスは Authenticode を信頼しています。コード署名は簡単に統合して自動化できるので、開発者がリリースに署名しない理由はありません。

    Authenticode 署名の詳細については、「ゲーム開発者のための Authenticode 署名」を参照してください。

  9. 権限の最小化

    一般にプロセスは、動作に必要な最小限の権限で実行する必要があります。Windows Vista では、ユーザー アカウント制御を使用して、ゲームを管理者ではなく標準ユーザーとして実行できるようにすることで、これを実現します。Windows XP では、一般にゲームが常に管理者として実行されます。Windows Vista でも、一部の操作で完全な管理者権限への昇格が必要になることがあります。

    プロセスが完全な管理者権限で実行されているケースでは、標準ユーザー セットを超える権限のうち、実際に必要なものはごくわずかである場合がほとんどです。管理者のアクセス権には、正規のコードには不要で、それどころかプロセスの脆弱性を突いて攻撃者に利用される可能性がある権限が多数含まれています。このような権限の例として、SE_TAKE_OWNERSHIP、SE_DEBUG、SE_CREATE_TOKEN、SE_ASSIGNPRIMARYTOKEN、SE_TCB、SE_SECURITY、SE_LOAD_DRIVER、SE_SYSTEMTIME、SE_BACKUP、SE_RESTORE、SE_SHUTDOWN、SE_AUDIT などがあります (「Priviledge Constants (権限の定数)」を参照)。

    一度開始されたプロセスは権限を追加で取得できませんが、権限を放棄することは簡単にできます。起動時に、プロセスで直ちに Win32 API を使用して不要な権限を削除することができます。このコード例が、Gamefest 2006Hardening the Box プレゼンテーションのスライド 10 とノートに掲載されています。

  10. Windows Vista のセキュリティ機能の利用

    Windows Vista には、コード セキュリティを強化する多数の新機能があります。ユーザー アカウント制御は最も重要な機能として内容を理解して取り入れる必要がありますが、他にも機能はあります。Windows Vista でも提供されている Windows ファイアウォール、データ実行防止、バッファー セキュリティ チェック、安全な例外ハンドラーなどの Windows XP SP2 のテクノロジに加えて、3 つの新たなセキュリティ機能が検討の対象となります。

    • Address Space Layout Randomization という新しいオプトイン機能があります。この機能を使用するには、Visual Studio 2005 Service Pack 1 以降で /DYNAMICBASE にリンクします。これにより、重要なシステム DLL の多くがプロセス空間内でランダムに配置されるようになるため、インターネット経由で広範囲に広がる悪用可能な攻撃プログラムを作成することが非常に難しくなります。このリンカー フラグは、Windows XP 以前の Windows では無視されます。
    • ヒープの破壊はあらゆる種類のセキュリティの悪用につながるため、Windows Vista のメモリー システムではヒープの破壊が検出された場合にプロセスを終了するモードがサポートされるようになりました。この動作を選択するには、HeapSetInformation を呼び出す際に HeapEnableTermianteOnCorruption を指定します。Windows XP 以前のバージョンの Windows では、この呼び出しは失敗します。
    • サービスを作成する際に、Windows Vista の新機能を使用して、実際に必要な権限を指定し、リソースへのアクセスを特定の SID に制限するようにサービスを構成できます。そのためには、ChangeSeviceConfig2 API で SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO および SERVICE_CONFIG_SERVICE_SID_INFO を指定します。

まとめ

現在そして将来の市場に向けたゲームの開発には、費用と時間がかかります。セキュリティに不備があるゲームをリリースすると、最終的にはその修正のためにより多くの費用と時間がかかることになります。このため、リリース前にセキュリティの悪用を抑制するためのツールと技法を取り入れることは、ゲーム開発者にとって利益となります。

この記事の内容は、開発元とその顧客のために開発現場でできることについての概要です。全般的なセキュリティ業務とセキュリティ情報の詳細については、Microsoft セキュリティ デベロッパー センターを参照してください。