セキュリティに関する考慮事項: Windows ユーザー インターフェイス
このトピックでは、Windows ユーザー インターフェイスでのセキュリティに関する考慮事項について説明します。 このトピックは、セキュリティの問題について知る必要があるすべてのことを提供するものではありません。 そうではなく、この技術分野の開始点および参照として使用してください。
コンピューターの相互接続が増えるのに伴い、開発者はアプリケーションのセキュリティに関心を持つ必要があります。 ただし、セキュリティによりアプリケーションの一般的な安全性と堅牢性も向上するので、開発者が優れたユーザー エクスペリエンスを提供できるもう 1 つの方法です。 以下のトピックでは、Windows のユーザー インターフェイスを使用するときの潜在的なセキュリティ上の問題について説明します。
文字列に関する考慮事項
多くの関数、メッセージ、マクロでは、パラメーターで文字列が使われます。 ただし、多くの場合、文字列で null 終端または長さのチェックは行われません。 関連する問題は、文字列またはバッファーの長さの計算の誤りです。 どちらの場合も、バッファー オーバーフローやデータの切り詰めにつながる可能性があり、アプリケーションに悪影響を及ぼす場合があります。 バッファー オーバーランとその他のセキュリティ上の問題について詳しくは、Microsoft Press 2002 の Michael Howard と David Leblanc による "安全なコードの記述" に関する記事をご覧ください。
文字列を安全に処理するには、次のようにする必要があります。
- 状況に応じて、文字列で null 終端または適切な長さを調べます。
- 文字列またはバッファーの長さの決定に特に注意します (特に、TCHAR 値が含まれる場合)。
- 文字列を作成する場合、または前に使われた文字列を使う場合は、状況に応じてゼロに初期化するか、null 終端記号を挿入します。
さらに、文字列を処理するときは、StrSafe 関数を使うことを検討します。 これらの関数は、文字列を安全に処理するように設計されています。
ユーザー入力
Windows ユーザー インターフェイスは、ユーザーからの情報の取得と応答に関係しています。 ただし、ユーザーは、意図的か否かに関わらず、正しくないデータを入力してアプリケーションを中断させる可能性があります。 したがって、すべての入力を検証するのが鉄則です。
主な懸念事項は文字列データであり、「文字列に関する考慮事項」で説明されています。 ただし、すべての種類の入力を、アプリケーションで使う前に検証する必要があります。 もう 1 つの懸念事項は、データが検証されてから使われるまでの間に変更される場合です (たとえば、テキストの長さを示すメッセージを受信したとき)。 そのため、データが変更される可能性がある場合は、使う直前にデータをチェックする必要があります。
セキュリティのアラート
次の表は、誤って使うとアプリケーションのセキュリティを侵害する可能性がある機能です。
機能 | 対応策 |
---|---|
GetAtomName | バッファーのサイズを指定するときは注意してください。 |
GlobalGetAtomName | グローバル文字列アトムは、すべてのアプリケーションからアクセスできます。 ただし、別のアプリケーションが不注意な場合は、参照カウントを誤って処理して削除する可能性があります。 代わりにグローバル整数アトムの使用を検討する必要があります。 |
ImpersonateDdeClientWindow | 関数が失敗した場合、後続のクライアント要求は呼び出し元プロセスのセキュリティ コンテキストで行われます。 これは、呼び出し元プロセスが高い特権アカウントとして実行されている場合、問題になる可能性があります。 したがって、呼び出しが失敗した場合やエラーが発生した場合は、クライアント要求の実行を続けないでください。 |
DdeImpersonateClient | 関数が失敗した場合、後続のクライアント要求は呼び出し元プロセスのセキュリティ コンテキストで行われます。 これは、呼び出し元プロセスが高い特権アカウントとして実行されている場合、問題になる可能性があります。 したがって、呼び出しが失敗した場合やエラーが発生した場合は、クライアント要求の実行を続けないでください。 |
GetClipboardFormatName | lpszFormatName バッファーの適切なサイズの計算を間違うと、特にアプリケーションが ANSI と Unicode の両方のバージョンで使われている場合、バッファー オーバーフローが発生する可能性があります。 また、文字列が cchMaxCount パラメーターより長いと切り詰められ、情報が失われる可能性があることに注意してください。 |
GetMenuString | lpString パラメーターは TCHAR バッファーであり、nMaxCount はメニュー文字列の TCHAR 数での長さです。 メニュー文字列の文字数での長さです。 これらのパラメーターのサイズ指定が正しくないと、文字列が切り詰められて、データが失われる可能性があります。 |
GetStringTypeA、GetStringTypeEx、GetStringTypeW | バッファー オーバーフローを避けるには、lpCharType バッファーのサイズを正しく設定します。 |
LoadLibrary | LoadLibrary を誤って使用すると、間違った DLL を読み込むことで、アプリケーションのセキュリティが損なわれる可能性があります。 |
LoadString | 不適切な使用には、nBufferMax パラメーターでの間違ったサイズの指定が含まれます。 たとえば、sizeof(lpBuffer) からはバッファーのサイズがバイト数で返されるので、Unicode バージョンの関数ではバッファー オーバーフローにつながる可能性があります。 バッファー オーバーフローの状況は、アプリケーションでのセキュリティに関する多くの問題の原因になります。 この場合、sizeof(lpBuffer)/sizeof(TCHAR) を使うと、バッファーの適切なサイズが得られます。 |
lstrcat | この関数は、構造化例外処理 (SEH) を使って、アクセス違反や他のエラーをキャッチします。 この関数は、SEH エラーをキャッチすると、文字列を null で終了せずに NULL を返し、エラーを呼び出し元に通知しません。 呼び出し元でエラー状態が不十分なスペースであると想定するのは安全ではありません。 最初の引数 lpString1 は、lpString2 と終了の "\0" を保持するのに十分な大きさである必要があり、そうでないとバッファー オーバーランが発生する可能性があります。 アクセス違反が発生した場合、バッファー オーバーランはアプリケーションに対するサービス拒否攻撃につながる可能性があります。 最悪の場合、バッファー オーバーランにより攻撃者が実行可能コードをプロセスに挿入できるようになる可能性があります (特に、lpString1 がスタック ベースのバッファーの場合)。 代わりに次のいずれかを使うことを検討してください。 StringCbCat または StringCchCat。 |
lstrcpy | この関数は、構造化例外処理 (SEH) を使って、アクセス違反や他のエラーをキャッチします。 この関数は、SEH エラーをキャッチすると、文字列を null で終了せずに NULL を返し、エラーを呼び出し元に通知しません。 呼び出し元でエラー状態が不十分なスペースであると想定するのは安全ではありません。 最初の引数 lpString1 は、lpString2 と終了の "\0" を保持するのに十分な大きさである必要があり、そうでないとバッファー オーバーランが発生する可能性があります。 アクセス違反が発生した場合、バッファー オーバーランはアプリケーションに対するサービス拒否攻撃につながる可能性があります。 最悪の場合、バッファー オーバーランにより攻撃者が実行可能コードをプロセスに挿入できるようになる可能性があります (特に、lpString1 がスタック ベースのバッファーの場合)。 代わりに、StringCchCopy を使うことを検討してください。 |
lstrcpyn | この関数は、構造化例外処理 (SEH) を使って、アクセス違反や他のエラーをキャッチします。 この関数は、SEH エラーをキャッチすると、文字列を null で終了せずに NULL を返し、エラーを呼び出し元に通知しません。 呼び出し元でエラー状態が不十分なスペースであると想定するのは安全ではありません。 lpString1 がコピーされた文字列を格納するのに十分な大きさでない場合、バッファー オーバーランが発生する可能性があります。 また、文字列全体をコピーする場合、sizeof は WCHAR ではなくバイトの数を返し、これはこの関数の Unicode バージョンでは正しくないことに注意してください。 アクセス違反が発生した場合、バッファー オーバーランはアプリケーションに対するサービス拒否攻撃の原因になる可能性があります。 最悪の場合、バッファー オーバーランにより攻撃者が実行可能コードをプロセスに挿入できるようになる可能性があります (特に、lpString1 がスタック ベースのバッファーの場合)。 代わりに、StringCchCopy を使うことを検討してください。 |
lstrlen | lstrlen では、lpString が null で終わる文字列であることが想定されています。 そうでない場合は、バッファー オーバーランやアプリケーションに対するサービス拒否攻撃につながる可能性があります。 代わりに次のいずれかを使うことを検討してください。 StringCbLength または StringCchLength。 |
wsprintf | lpOut で返される文字列は、null で終わっている保証はありません。 また、%s 形式はバッファー オーバーランが発生する可能性があるため、使わないでください。 アクセス違反が発生すると、アプリケーションに対するサービス拒否の原因になります。 さらに悪いケースでは、攻撃者が実行可能コードを挿入する可能性があります。 代わりに次のいずれかを使うことを検討してください。 StringCbPrintf、StringCbPrintfEx、StringCbVPrintf、StringCbVPrintfEx、StringCchPrintf、StringCchPrintfEx、StringCchVPrintf、StringCchVPrintfEx。 |
wvsprintf | lpOutput で返される文字列は、null で終わっている保証はありません。 また、%s 形式を使うとバッファー オーバーランが発生する可能性があるため、使わないでください。 これにより、アクセス違反が発生するとサービス拒否につながる場合があり、攻撃者が実行可能コードを挿入する可能性もあります。 代わりに次のいずれかを使うことを検討してください。 StringCbPrintf、StringCbPrintfEx、StringCbVPrintf、StringCbVPrintfEx、StringCchPrintf、StringCchPrintfEx、StringCchVPrintf、StringCchVPrintfEx。 |
関連トピック