マイケル・ハワードとキース・ブラウン
この記事は、C++、C#、SQL に精通していることを前提としています。
概要: セキュリティの問題に関しては、トラブルにつながる可能性のある状況が数多くあります。おそらく、ネットワーク上で実行されているすべてのコードを信頼し、すべてのユーザーに重要なファイルへのアクセスを許可し、マシン上のコードが変更されたかどうかをわざわざチェックする必要はありません。また、ウイルス対策ソフトウェアがインストールされていない、独自のコードを保護できていない、アカウントに多すぎる権限を与えている可能性もあります。悪意のある侵入を許可する多数の組み込み機能を不注意で使用し、監視せずにサーバー ポートを開いたままにしてしまう可能性もあります。明らかに、さらに多くの例を挙げることができます。本当に重要な問題 (つまり、データやシステムの侵害を避けるために直ちに注意を払う必要がある最も危険なエラー) は何ですか?セキュリティ専門家の Michael Howard と Keith Brown が、役立つ 10 のヒントを提供します。
-------------------------------------------------- ----------------------------------
セキュリティの問題には多くの側面が関係します。セキュリティリスクはどこからでも発生する可能性があります。非効果的なエラー処理コードを作成したか、アクセス許可を与えるときに寛大すぎた可能性があります。サーバー上でどのようなサービスが実行されているかを忘れてしまった可能性があります。すべてのユーザー入力を受け入れることができます。等々。コンピューター、ネットワーク、コードの保護をいち早く始めるために、より安全なネットワーク戦略を立てるために従うべき 10 のヒントをここに示します。
1. ユーザー入力を信頼すると危険にさらされます。
たとえ残りを読まなくても、「ユーザー入力を信頼しないでください」ということを覚えておいてください。データが有効であり、悪意のあるものではないと常に想定している場合に問題が発生します。セキュリティ上の脆弱性のほとんどは、攻撃者が悪意を持って書き込まれたデータをサーバーに送信することに関係しています。
入力の正しさを信頼すると、バッファ オーバーフロー、クロスサイト スクリプティング攻撃、SQL 挿入コード攻撃などが発生する可能性があります。
これらの潜在的な攻撃ベクトルについて詳しく説明します。
2. バッファ オーバーフローの防止
攻撃者がアプリケーションの想定よりも長いデータ長を提供すると、バッファ オーバーフローが発生し、データが内部メモリ空間に溢れます。バッファ オーバーフローは主に C/C++ の問題です。これらは脅威ですが、通常は簡単に修正できます。明らかではなく修正が困難なバッファ オーバーフローは 2 件だけ確認されました。開発者は、外部から提供されたデータが内部バッファーよりも大きくなるとは予想していませんでした。オーバーフローはメモリ内の他のデータ構造の破損を引き起こし、攻撃者が悪意のあるコードを実行するために悪用することがよくあります。配列インデックスのエラーもバッファのアンダーフローやオーバーランを引き起こす可能性がありますが、これはそれほど一般的ではありません。
次の C++ コード スニペットを見てください。
void DoSomething(char *cBuffSrc, DWORD cbBuffSrc) {
char cBuffDest[32];
memcpy(cBuffDest,cBuffSrc,cbBuffSrc);
何
が問題なのでしょうか?実際、cBuffSrc と cbBuffSrc が信頼できるソースからのものである場合 (データを信頼しないため、その有効性とサイズを検証するコードなど)、このコードには何も問題はありません。ただし、データが信頼できないソースからのもので検証されていない場合、攻撃者 (信頼できないソース) は簡単に cBuffSrc を cBuffDest よりも大きくし、さらに cbBuffSrc を cBuffDest よりも大きく設定することができます。 memcpy がデータを cBuffDest にコピーすると、DoSomething からの戻りアドレスが変更されます。cBuffDest は関数のスタック フレーム上の戻りアドレスに隣接しているため、攻撃者はコードを通じて悪意のある操作を実行できます。
これを補う方法は、ユーザーの入力を信頼せず、cBuffSrc および cbBuffSrc に含まれるデータを信頼しないことです。
void DoSomething(char *cBuffSrc, DWORD cbBuffSrc) {
const DWORD cbBuffDest = 32;
char cBuffDest[cbBuffDest];
#ifdef _DEBUG
memset(cBuffDest, 0x33, cbBuffSrc);
#endif
memcpy(cBuffDest, cBuffSrc, min(cbBuffDest, cbBuffSrc));
、
バッファ オーバーフローを軽減できる適切に作成された関数の 3 つの特性を示します。まず、呼び出し元はバッファの長さを提供する必要があります。もちろん、この値を盲目的に信頼することはできません。次に、デバッグ ビルドで、コードはバッファーが実際にソース バッファーを保持するのに十分な大きさであるかどうかを検出します。そうでない場合、アクセス違反がトリガーされ、コードがデバッガーに読み込まれる可能性があります。デバッグすると、驚くほど多くのバグが見つかるでしょう。最後に、そして最も重要なことですが、memcpy への呼び出しは、ターゲット バッファーが保持できる以上のデータをコピーしないという点で防御的です。
Microsoft の Windows® セキュリティ プッシュの一環として、C プログラマ向けに安全な文字列処理関数のリストを作成しました。これらは Strsafe.h: C での安全な文字列処理 (英語) にあります。
3. クロスサイト スクリプティングの防止
クロスサイト スクリプティング攻撃は、単一の Web ページの隠れた脆弱性を通じてクライアント データに損害を与える可能性がある、Web 特有の問題です。次の ASP.NET コード スニペットの結果を想像してください:
同様のコードを見た人は何人いますか?しかし、驚くべきことに問題もあります!通常、ユーザーは次のような URL を使用してこのコードにアクセスします。
http://explorationair.com/welcome.aspx?name=Michael
C# コードでは、データが常に有効であり、名前のみが含まれていることを前提としています。ただし、攻撃者はスクリプトと HTML コードを名前として指定することで、このコードを悪用する可能性があります。以下のURLを入力すると
http://northwindtraders.com/welcome.aspx?name=
「Hello!」というダイアログボックスが表示された Web ページが表示されます。 「だから何?」と思われるかもしれませんが、攻撃者がユーザーを騙してこのようなリンクをクリックさせ、そのクエリ文字列に非常に危険なスクリプトと HTML が含まれており、それによってユーザーの Cookie が取得され、それが所有する Web サイトに送信されるということを想像してみてください。攻撃者はあなたの個人的な Cookie 情報、あるいはさらに悪いことにアクセスできるようになります。
これを回避するには、2 つの方法があります。 1 つ目は、入力を信頼せず、ユーザー名に含まれる内容を厳密に制限することです。たとえば、正規表現を使用して、名前に共通の文字のサブセットのみが含まれていて、名前が大きすぎないことを確認できます。次の C# コード スニペットは、この手順を実行する方法を示しています。
Regex r = new Regex(@"^[w]{1,40}$")
if (r.Match(strName).Success) {
// 良い!文字列は大丈夫です
} それ以外 {
// 良くない!無効な文字列
、
文字列に 1 ~ 40 個の文字または数字のみが含まれていることを確認します。これは、値が正しいかどうかを判断する唯一の安全な方法です。
HTML やスクリプトがこの正規表現をだますことはできません。何かを見逃しやすいため、正規表現を使用して無効な文字を検索したり、そのような無効な文字が見つかった場合にリクエストを拒否したりしないでください。
2 番目の予防策は、すべての入力を出力として HTML エンコードすることです。これにより、危険な HTML タグがより安全なエスケープ文字に減ります。 ASP.NET の HttpServerUtility.HtmlEncode または ASP の Server.HTMLEncode を使用して、問題のある可能性のある文字列をエスケープできます。
4. sa 権限を要求しない
最後に説明する入力信頼攻撃は、SQL コードの挿入です。多くの開発者は、入力を受け取り、その入力を使用して Microsoft® SQL Server™ や Oracle などのバックエンド データ ストアと通信する SQL クエリを構築するコードを作成します。
次のコード スニペットを見てください。
void DoQuery(string Id) {
SqlConnection sql=new SqlConnection(@"データ ソース=ローカルホスト;" +
"ユーザーID=sa;パスワード=パスワード;");
SQL.Open();
sqlstring= "SELECT が出荷されました" +
" FROM Shipping WHERE id='" + Id + "'";
SqlCommand cmd = new SqlCommand(sqlstring,sql);
•••
このコードには 3 つの重大な欠陥があります。まず、システム管理者アカウント sa として Web サービスから SQL Server への接続を確立します。この落とし穴はすぐにわかります。 2 番目のポイントは、sa アカウントのパスワードとして「パスワード」を使用する賢い習慣に注意してください。
しかし、本当の懸念は、SQL ステートメントを構築する文字列の連結です。ユーザーが ID として 1001 を入力すると、次の SQL ステートメントが得られますが、これは完全に有効です。
SELECT hasshipped FROM Shipping WHERE id = '1001'
しかし、攻撃者はそれよりもはるかに創造的です。 ID として「'1001' DROP table Shipping --」と入力すると、次のようなクエリが実行されます。
SELECT が FROM から送信されました
配送先ID = '1001'
DROP テーブルの配送 -- ';
これにより、クエリの動作方法が変わります。このコードは、何かが出荷されたかどうかを判断するだけでなく、出荷テーブルの削除 (削除) も行います。演算子 -- SQL のコメント演算子であり、攻撃者が一連の有効だが危険な SQL ステートメントを簡単に構築できるようにします。
この時点で、ユーザーがどのようにして SQL Server データベース内のテーブルを削除できるのか疑問に思うかもしれません。もちろんおっしゃる通りです。そのような仕事は管理者だけが行うことができます。ただし、ここでは sa としてデータベースに接続しており、sa は SQL Server データベース上で必要なことを何でも行うことができます。どのアプリケーションからも sa として SQL Server に接続しないでください。正しい方法は、必要に応じて Windows 統合認証を使用するか、適切なアクセス許可を持つ事前定義されたアカウントとして接続することです。
SQL 挿入コードの問題を修正するのは簡単です。次のコードは、SQL ストアド プロシージャとパラメータを使用して、そのようなクエリを作成する方法と、トランザクションでは出荷 ID が 4 ~ 10 桁のみであると指定されているため、正規表現を使用して入力が有効であることを確認する方法を示しています。
正規表現 r = new Regex(@"^d{4,10}$");
if (!r.Match(Id).Success)
throw new Exception("無効な ID");
SqlConnection sqlConn= new SqlConnection(strConn);
文字列 str="sp_出荷済み";
SqlCommand cmd = new SqlCommand(str,sqlConn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@ID",Id);
バッファ オーバーフロー、クロスサイト スクリプティング、SQL 挿入コード攻撃はすべて、信頼できる入力の問題の例です。これらの攻撃はすべて、そうでないことが証明されない限り、すべての入力が有害であると見なすメカニズムによって軽減されます。
5. 暗号化コードに注意してください!
私たちを驚かせるかもしれないものを見てみましょう。私たちが調査したセキュリティ コードの 30% 以上にセキュリティ上の脆弱性があることがわかりました。おそらく最も一般的な脆弱性は、脆弱になる可能性が高い独自の暗号化コードです。独自の暗号化コードを決して作成しないでください。それは愚かな用事です。独自の暗号化アルゴリズムを持っているからといって、他の人がそれを解読できないとは考えないでください。攻撃者はデバッガにアクセスでき、システムがどのように動作するかを判断するための時間と知識も持っており、多くの場合、数時間以内にシステムを破壊します。 Win32® CryptoAPI を使用する必要があります。System.Security.Cryptography 名前空間には、テスト済みの優れた暗号化アルゴリズムが多数提供されています。
6. 攻撃を受ける可能性を減らす。90
% 以上のユーザーが要求しない場合は、デフォルトで機能をインストールしないでください。インターネット インフォメーション サービス (IIS) 6.0 は、このインストール推奨事項に従っています。これについては、今月リリースされた Wayne Berry の記事「インターネット インフォメーション サービスのイノベーションにより、安全なデータとサーバー プロセスをしっかりと保護できます」を参照してください。このインストール戦略の背後にある考え方は、使用していないサービスには注意を払わず、それらのサービスが実行されている場合、他の人によって悪用される可能性があるということです。機能がデフォルトでインストールされている場合、その機能は最小認可の原則に基づいて実行される必要があります。つまり、必要な場合を除き、管理者権限でアプリケーションを実行できるようにしないでください。このアドバイスに従うのが最善です。
7. 最小認可の原則を使用する
オペレーティング システムと共通言語ランタイムには、いくつかの理由からセキュリティ ポリシーがあります。多くの人は、このセキュリティ ポリシーが存在する主な理由は、ユーザーがアクセスを許可されていないファイルにアクセスしたり、ユーザーのニーズに合わせてネットワークを再構成したり、その他の悪質な行為など、ユーザーが意図的に害を及ぼすことを防ぐためであると考えています。確かに、この種の内部関係者攻撃はよくあることなので、警戒する必要がありますが、このセキュリティ戦略に固執する理由はもう 1 つあります。つまり、ユーザーが意図的または (よくあることですが) 非意図的なアクションによってネットワークに大混乱を引き起こすことを防ぐために、コードの周囲に防御障壁を構築します。たとえば、電子メール経由でダウンロードされた添付ファイルは、Alice のマシンで実行されると、Alice がアクセスできるリソースに制限されます。添付ファイルにトロイの木馬が含まれている場合、適切なセキュリティ戦略は、それによる被害を制限することです。
サーバー アプリケーションを設計、構築、展開する場合、すべてのリクエストが正当なユーザーからのものであると想定することはできません。悪意のある人が悪意のあるリクエストを送信し (そうでないことを願いますが)、コードの動作が悪くなった場合、被害を最小限に抑えるためにアプリケーションに可能な限りの防御を講じる必要があります。したがって、貴社がセキュリティ ポリシーを導入しているのは、貴社や貴社のコードを信頼していないからだけではなく、悪意のある外部コードから自社を守るためでもあると考えられます。
最小認可の原則では、コードに必要な最小限のアクセス許可は最小限の時間で付与されるべきであると考えられます。ただし、常にコードの周囲にできるだけ多くの保護壁を構築してください。マーフィーの法則が保証しているように、何か悪いことが起こったとき、防護壁が設置されていることを嬉しく思うでしょう。したがって、最小認可の原則を使用してコードを実行するための具体的な方法をいくつか紹介します。
サーバー コードには、そのジョブの実行に必要なリソースへのアクセスのみを許可する安全な環境を選択してください。コードの一部に高い権限が必要な場合は、コードのその部分を分離し、より高い権限で個別に実行することを検討してください。異なるオペレーティング システムの認証情報で実行されるこのコードを安全に分離するには、このコードを別のプロセス (より高い権限を持つ安全な環境で実行する) で実行することが最善です。これは、プロセス間通信 (COM や Microsoft .NET リモート処理など) が必要となり、ラウンドトリップを最小限に抑えるためにそのコードへのインターフェイスを設計する必要があることを意味します。
.NET Framework 環境でコードをアセンブリに分割する場合は、コードの各部分に必要なアクセス許可レベルを考慮してください。これは簡単なプロセスであることがわかります。高い特権を必要とするコードを、より高い特権を与える別のアセンブリに分離し、残りのアセンブリのほとんどは低い特権で実行したままにし、コードの周りにさらにガードを追加できるようにします。 これを行うときは、コード アクセス セキュリティ (CAS) スタックにより、自分のアセンブリだけでなく、呼び出すアセンブリのアクセス許可も制限されることを忘れないでください。
多くの人は独自のアプリケーションを構築し、テストされて顧客に提供された後に新しいコンポーネントを製品に組み込むことができます。このタイプのアプリケーションをセキュリティで保護することは、考えられるすべてのコード パスをテストしてバグやセキュリティ ホールを見つけることはできないため、非常に困難です。ただし、アプリケーションがホストされている場合、CLR はこれらの拡張ポイントを閉じるために使用できる優れた機能を提供します。アクセス許可オブジェクトまたはアクセス許可セットを宣言し、PermitOnly または Deny を呼び出すと、呼び出すコードへのアクセス許可の付与をブロックするマークがスタックに追加されます。プラグインを呼び出す前にこれを行うことで、プラグインが実行できるタスクを制限できます。たとえば、分割払いを計算するプラグインは、ファイル システムへのアクセスを必要としません。これは、事前に自分自身を保護する最小特権のもう 1 つの例です。これらの制限に必ず注意し、より高い権限を持つプラグインは Assert ステートメントを使用してこれらの制限を回避できることに注意してください。
8. 失敗パターンを認識し
、それを受け入れます。あなたと同じようにエラー処理コードを書くことを嫌う人もいます。コードが失敗する理由はたくさんあり、考えるだけでイライラしてしまうかもしれません。私たちを含むほとんどのプログラマは、通常の実行パスに重点を置くことを好みます。ここからが本当の仕事の始まりです。これらのエラー処理をできるだけ早く簡単に実行してから、実際のコードの次の行に進みましょう。
残念ながら、この感情は安全ではありません。代わりに、コード内の失敗パターンに細心の注意を払う必要があります。このコードは、あまり深く注意せずに書かれていることが多く、十分にテストされていないことがよくあります。最後に、関数内のすべてのコード行 (関数内のすべての小さなエラー ハンドラーも含む) を確実にデバッグしたときのことを覚えていますか?
テストされていないコードは、多くの場合、セキュリティ上の脆弱性につながります。この問題を軽減するために役立つことが 3 つあります。まず、これらの小さなエラー ハンドラーに通常のコードと同じ注意を払います。エラー処理コードが実行されるときのシステムの状態を考慮してください。システムは効率的かつ安全な状態にありますか?次に、関数を作成したら、それをステップ実行して数回徹底的にデバッグし、すべてのエラー ハンドラーを必ずテストします。このような手法を使用しても、非常に微妙なタイミング エラーは検出できない場合があることに注意してください。エラー パラメーターを関数に渡すか、何らかの方法でシステムの状態を調整してエラー ハンドラーを実行できるようにする必要がある場合があります。時間をかけてコードをステップ実行することで、速度を落とし、コードと実行中のシステムの状態を確認するのに十分な時間を確保できます。デバッガーでコードを注意深くステップ実行することで、プログラミング ロジックに多くの欠陥があることがわかりました。これは実績のある技術です。ぜひこのテクニックを使ってみてください。最後に、テスト スイートが関数の失敗の原因であることを確認します。関数内のコードのすべての行を検査するテスト スイートを用意するようにしてください。これは、特にテストを自動化し、コードをビルドするたびにテストを実行する場合に、パターンを特定するのに役立ちます。
故障モードに関して、非常に重要なことが 1 つあります。コードが失敗したときにシステムが可能な限り安全な状態にあることを確認してください。問題のあるコードの一部を以下に示します。
bool accessGranted = true; // 楽観的すぎます。
試す {
// c:test.txt にアクセスできるかどうかを確認します
new FileStream(@"c:test.txt",
ファイルモード.オープン、
FileAccess.Read).Close();
}
catch (SecurityException x) {
// アクセスが拒否されました
accessGranted = false;
}
キャッチ (...) {
// 他に何かが起こった
CLR
を使用しているにもかかわらず、ファイルへのアクセスは許可されています。この場合、SecurityException はスローされません。しかし、たとえば、ファイルの随意アクセス制御リスト (DACL) によってアクセスが許可されていない場合はどうなるでしょうか?このとき、別の種類の例外がスローされます。しかし、コードの最初の行には楽観的な仮定があるため、これを知ることはできません。
このコードは慎重に記述することをお勧めします。
bool accessGranted = false; // 注意してください。
試す {
// c:test.txt にアクセスできるかどうかを確認します
new FileStream(@"c:test.txt",
ファイルモード.オープン、
FileAccess.Read).Close();
// まだここにいるなら、素晴らしいです!
accessGranted = true;
}
catch (...) {}
これは、どのように失敗しても常に最も安全なモードにフォールバックするため、より安定します。
9. 偽装は非常に脆弱です
サーバー アプリケーションを作成するとき、偽装と呼ばれる Windows の便利な機能を直接または間接的に使用することがよくあります。偽装により、プロセス内の各スレッドを異なるセキュリティ環境 (通常はクライアントの環境) で実行できます。たとえば、ファイル システム リダイレクタは、ネットワーク経由でファイル要求を受信すると、リモート クライアントを認証し、クライアントの要求が共有上の DACL に違反していないことを確認してから、要求を処理するスレッドにクライアントのフラグを付加します。 .クライアントをシミュレートします。このスレッドは、クライアントのセキュリティ環境を使用してサーバー上のローカル ファイル システムにアクセスできるようになります。ローカル ファイル システムはすでに安全であるため、これは便利です。要求されたアクセスのタイプ、ファイルの DACL、スレッドの偽装フラグを考慮してアクセス チェックを実行します。アクセス チェックが失敗した場合、ローカル ファイル システムはファイル システム リダイレクタにそれを報告し、ファイル システム リダイレクタはリモート クライアントにエラーを送信します。これはファイル システム リダイレクタにとって間違いなく便利です。クライアントがローカルにあるかのように、リクエストをローカル ファイル システムに渡し、独自のアクセス チェックを実行できるからです。
ファイル リダイレクターのような単純なゲートウェイではこれで十分です。ただし、シミュレーションは他のより複雑なアプリケーションでもよく使用されます。 Web アプリケーションを例に挙げます。従来のアンマネージ ASP プログラム、ISAPI 拡張機能、または ASP.NET アプリケーションを作成し、その Web.config ファイル
、実行環境には 2 つの異なるセキュリティ環境が存在します。 process タグと thread タグ。一般的に、スレッド タグはアクセス チェックに使用されます (図 3 を参照)。 Web サーバー プロセスで実行される ISAPI アプリケーションを作成していて、ほとんどのリクエストが認証されていないと仮定すると、スレッド タグは IUSR_MACHINE ですが、プロセス タグは SYSTEM になる可能性があります。コードがバッファ オーバーフローを介して悪意のある攻撃者によって悪用される可能性があるとします。 IUSR_MACHINE として実行するだけで満足すると思いますか?もちろん違います。彼の攻撃コードは、特権レベルを上げることを期待して、RevertToSelf を呼び出して偽装フラグを削除している可能性があります。この場合、彼は簡単に成功するでしょう。 CreateProcess を呼び出すこともできます。新しいプロセスのタグは偽装タグからコピーされるのではなく、新しいプロセスが SYSTEM として実行できるようにプロセス タグからコピーされます。
では、この小さな問題をどうやって解決すればよいでしょうか?そもそもバッファ オーバーフローが発生しないようにすることに加えて、最小認可の原則を忘れないでください。コードに SYSTEM ほどの権限が必要ない場合は、Web アプリケーションを Web サーバー プロセスで実行するように構成しないでください。 Web アプリケーションを中程度または高分離環境で実行するように単純に構成した場合、プロセス タグは IWAM_MACHINE になります。実際には権限がないため、この攻撃はほとんど効果がありません。 IIS 6.0 (まもなく Windows .NET Server のコンポーネントとなる予定) では、ユーザーが作成したコードはデフォルトでは SYSTEM として実行されないことに注意してください。開発者は間違いを犯すものであるという理解に基づいて、コードにセキュリティ上の問題が発生した場合に、コードに与えられるアクセス許可を減らすために Web サーバーが提供できるあらゆる支援が役に立ちます。
ここに、COM プログラマが遭遇する可能性のあるもう 1 つの落とし穴があります。 COM にはスレッドを無視する悪い傾向があります。インプロセス COM サーバーを呼び出し、そのスレッド モデルが呼び出し側スレッドのモデルと一致しない場合、COM は別のスレッドで呼び出しを実行します。 COM は呼び出し元スレッドに偽装フラグを伝達しないため、呼び出しは呼び出し元スレッドのセキュリティ コンテキストではなく、プロセスのセキュリティ コンテキストで実行されます。なんと驚きました!
ここにシミュレーションの落とし穴の別の例を示します。サーバーが名前付きパイプ、DCOM、または RPC 経由で送信されたリクエストを受け入れると仮定します。クライアントを認証して偽装し、偽装を通じてクライアントに代わってカーネル オブジェクトを開きます。また、クライアントが切断されたときに、オブジェクト (ファイルなど) の 1 つを閉じるのを忘れていました。次のクライアントが入ってきたときに、認証してそのクライアントになりすますと、何が起こると思いますか?新しいクライアントがファイルにアクセスできなかった場合でも、前のクライアントが「見逃した」ファイルには引き続きアクセスできます。パフォーマンス上の理由から、カーネルはオブジェクトを初めて開いたときにのみ、オブジェクトに対するアクセス チェックを実行します。別のユーザーになりすましているため、後でセキュリティ環境を変更した場合でも、引き続きこのファイルにアクセスできます。
上記の状況はすべて、シミュレーションがサーバー開発者に利便性をもたらしますが、この利便性には大きな危険が隠れていることを思い出させるものです。モック フラグを使用してプログラムを実行するときは、コードに細心の注意を払うようにしてください。
10. 管理者以外のユーザーが実際に使用できるアプリケーションを作成する
これは実際、最小権限の原則から必然的に得られるものです。 Windows 上で適切に実行するために管理者を必要とするコードをプログラマーが開発し続けると、システムのセキュリティの向上は期待できません。 Windows には非常に強固なセキュリティ機能が備わっていますが、それらを操作するのに管理者でなければユーザーはそれらの機能を利用できません。
どうすれば改善できますか?まず、管理者として実行せずに、自分で試してください。セキュリティを考慮して設計されていないプログラムを使用することの苦痛をすぐに知ることになるでしょう。ある日、私 (キース) は、デスクトップ コンピュータとハンドヘルド デバイスの間でデータを同期する、ハンドヘルド デバイスの製造元が提供するソフトウェアをインストールしました。いつものように、通常のユーザー アカウントからログアウトし、組み込みの管理者アカウントを使用して再度ログインし、ソフトウェアをインストールしてから、通常のアカウントに再度ログインして、ソフトウェアを実行しようとしました。その結果、アプリケーションは必要なデータ ファイルにアクセスできないことを示すダイアログ ボックスを表示し、アクセス違反のメッセージを表示します。皆さん、これは大手携帯機器メーカーのソフトウェア製品です。この間違いに言い訳はありますか?
http://sysinternals.com (英語) から FILEMON を実行すると、アプリケーションが、アプリケーションの実行可能ファイルの中間と同じディレクトリにインストールされたデータ ファイルを書き込みアクセスで開こうとしていることがすぐにわかりました。アプリケーションが予期したとおりに Program Files ディレクトリにインストールされている場合、そのディレクトリにデータを書き込もうとすることはできません。 Program Files がこのように制限的なアクセス制御ポリシーを採用しているのには理由があります。ユーザーがこれらのディレクトリに書き込むことは望ましくありません。これは、あるユーザーが別のユーザーが実行できるトロイの木馬を残しておくことが容易になるためです。実際、この規則は、Windos XP の基本的な署名要件の 1 つです ( http://www.microsoft.com/winlogo [英語] を参照)。
コードを開発するときに管理者として実行することを選択した理由について言い訳をするプログラマーが多すぎると聞きます。この問題を無視し続ければ、事態はさらに悪化するだけです。テキスト ファイルを編集するのに管理者権限は必要ありません。プログラムの編集やデバッグにも管理者権限は必要ありません。管理者権限が必要な場合は、オペレーティング システムの RunAs 機能を使用して、「玎com.asp?TARGET=/winlogo/">http://www.microsoft.com/winlogo [英語]) を実行してください。
プログラマーが言い訳をするこのことはよく聞きます。コードを開発するときに管理者として実行することを選択する理由は、この問題を無視し続けると、テキスト ファイルの編集に管理者権限が必要ないことや、プログラムのデバッグに管理者権限が必要ないことです。特権を必要とする場合は、オペレーティング システムの RunAs 機能を使用して、昇格された特権で別のプログラムを実行します (2001 年 11 月のセキュリティ ブリーフ [英語] コラムを参照)。開発者向けのツールを作成している場合は、このグループに対する追加の責任が必要です。管理者としてのみ実行できるコードを作成するという悪循環を止めるには、
開発者が管理者以外でも簡単に実行できるようにする方法の詳細については、Keith の Web サイト(http://www.develop)を参照してください。 com/kbrown (英語) を参照してください。Michael の著書『Writing Secure Code』 (Microsoft Press、2001 年) には、管理者以外の環境で適切に動作するアプリケーションを作成する方法に関するヒントが記載されています。