この資料は、パスワード変更パッケージの機能について記述したものです。このパッケージを使用すると、パスワード変更の通知を受信したり、パスワードの質を管理することが可能になります。
パスワード変更通知を使用すると、外部のアカウント データベースを同期させることができます。 パスワード変更通知の機能は、Windows NT 3.51 以降で利用可能です。
パスワード フィルタを使用すると、新しいパスワードの質や強度を厳格に管理することが可能になります。また、PasswordFilter ルーチンを使って、新しいパスワードが適切なものかどうかを示すことができます。 パスワード フィルタ機能は、Service Pack 2 をインストールした Windows NT 4.0 上でのみ利用可能です。
注 : この機能にはほかの用途も考えられますが、この資料では説明していません。
注意 : クリア テキスト (暗号化されていないテキスト) のパスワードを取り扱う際には十分注意してください。 パスワードをクリア テキストのままネットワーク上に送信すると、ネットワーク上のセキュリティ レベルが低下する可能性があります。これは、そうしたパスワードのトラフィックを監視しているネットワーク "Sniffer" が存在する可能性があるためです。 パスワードの保管に使用したメモリは、解放する前にゼロの値で埋めることが推奨されます。 この資料は、読者がパスワード情報を安全に取り扱う方法を知っていることを前提に書かれています。
この機能へのインターフェイスは、Windows NT の将来のリリースで変更される可能性があります。
パスワード変更イベントに関する注意点
-
通知およびフィルタのルーチンに渡すバッファはすべて、読み取り専用として扱う必要があります。 これらのバッファにデータを書き込むと、動作が不定になる可能性があります。
-
通知およびフィルタのルーチンは、スレッドセーフでなければなりません。 必要に応じて、クリティカル セクションやそのほかの同期テクニックを使ってデータを保護してください。
-
InitializeChangeNotify 関数は、パスワード通知 DLL がロードされると呼び出されます。 この関数が FALSE を返す場合、DLL はアンロードされます。 この関数は、パスワード通知固有の初期化を記述できるように提供されているものです。これにより、パスワード DLL をほかの用途に使用できるようになります。
-
PasswordFilter 関数は、パスワード変更の要求があったときに呼び出されます。 そのようなパスワード変更イベントは、アカウントの作成、管理者によるパスワードの変更、およびユーザー指定のパスワード変更の際に発生します。 この関数が TRUE を返した場合、そのパスワードは有効と見なされ、システムにインストールされているほかのパスワード変更パッケージを使ったパスワードの評価が続けられます。 この関数が FALSE を返した場合、そのパスワードは無効と見なされ、パスワード変更の要求元に ERROR_ILL_FORMED_PASSWORD (1324) が返されます。
-
PasswordChangeNotify 関数は、提供されたパスワードがフィルタを通過し、パスワードの保管に成功した後に呼び出されます。 現在のところ、PasswordChangeNotify の戻り値は使われていません。 Windows NT の現在のリリースでは、PasswordChangeNotify は常に STATUS_SUCCESS (0x00000000L) を返します。
-
通知やフィルタリングが行われるのは、更新されるアカウントが存在するコンピュータだけです。 ドメイン ユーザーのアカウントを扱うときには、この点に留意してください。 ドメイン アカウントに関する通知は、そのドメインのプライマリ ドメイン コントローラでしか行われません。 通知パッケージは、PDC だけでなく、すべての BDC にもインストールする必要があります。これは、サーバーの役割が変更された場合でも、通知を継続できるようにするためです。
-
この機能を使用するには、REG_MULTI_SZ の型を持つ、次のレジストリ エントリが正しく設定されている必要があります。
HKEY_LOCAL_MACHINE\
SYSTEM\
CurrentControlSet\
Control\
Lsa\
Notification Packages (型が REG_MULTI_SZ の値)
Notification Packages には DLL のリストが含まれています。ここに記載される DLL がロードされ、パスワード変更およびパスワード変更の要求が通知されます。 この値がレジストリに存在しない場合は、作成する必要があります。
-
パスワード変更パッケージは、次の関数から成ります。
-
InitializeChangeNotify
-
PasswordFilter
-
PasswordChangeNotify
それぞれの関数は省略可能です。また、NTAPI または WINAPI として宣言し、正しい呼び出し規約を保証する必要があります。 使用する関数は、DLL の作成時に使われる .DEF ファイルに記述しておく必要があります。
-
処理されない例外がこれらの関数内で発生すると、システム全体に波及するセキュリティ関連の障害の原因となります。必要な場合は、構造化例外処理を使用する必要があります。
-
パスワード変更関数の呼び出し側は、各関数が完了するまでブロックします。 長い時間を要する処理は、PasswordChangeNotify や PasswordFilter から戻るのを待たずに、適宜別のスレッドで実行するようにしてください。
-
PasswordChangeNotify、PasswordFilter、および InitializeChangeNotify の各関数は、ローカル システム アカウントのセキュリティ コンテキストで実行されます。
-
通知パッケージのローディングは、AuditCategorySystem の "再起動、シャットダウン、およびシステム" 監査イベントの種類を使って監査できるイベントです。
-
パスワード変更通知とパスワード フィルタは、Windows 95 と Windows NT のクライアントから開始されたパスワード変更にしか対応していません。 16 ビットの Windows クライアントでは、パスワード変更通知に対応できない別のパスワード変更プロトコルが使われているため、これらのクライアントによって開始されたパスワード変更では、パスワード変更イベントが生成されません。
マイクロソフトが提供するパスワード フィルタ DLL
システムの管理者が、独自のフィルタを記述せずにパスワードを強化したい場合は、マイクロソフトによって Windows NT 4.0 の Service Pack 2 で提供されるパスワード フィルタを使用することもできます。 このフィルタ (PASSFILT.DLL) は、システムに Service Pack 2 をインストールした後、%system root%\SYSTEM32 にコピーする必要があります。 フィルタを有効にするには、上記の手順 6. 〜 7. に従って操作してください。
PASSFILT.DLL では、次のパスワード ポリシーが実装されています。
-
パスワードの長さは 6 文字以上である。
-
2.パスワードに、次の 4 つの種類のうち少なくとも 3 つの種類の文字を使用する。
説明 例
英大文字 A, B, C, ... Z
英小文字 a, b, c, ... z
数字 0, 1, 2, ... 9
英数字以外の句読点など
-
3.パスワードにユーザー名や氏名の一部を含めない。
Windows 2000 に含まれている強力なパスワード機能
上記の Windows NT 4.0 の機能は、Windows 2000 では、オペレーティング システムのセキュリティ コンポーネントに移されました。 強力なパスワードの強制は、Windows 2000 でローカル コンピュータ ポリシー MMC スナップインを開き、[コンピュータの構成\Windows の設定\セキュリティの設定\アカウント ポリシー\パスワードのポリシー] の "パスワードは要求する複雑さを満たす" の設定を使って有効にすることができます。
サンプル コード
/*++
Copyright (c) 1995, 1996 Microsoft Corporation
モジュール名 :
pswdntfy.c
概要 :
このモジュールは、パスワード変更通知およびパスワードのフィルタリングを
Windows NT 4.0 で実装する方法を示したものです。
パスワード変更通知は、Windows NT 以外のアカウント データベースを
同期させる場合に便利です。
パスワード変更フィルタリングは、Windows NT アカウント データベースで
パスワードの強度や品質を強化する場合に便利です。
このサンプルは、さらに高品質のパスワードを強制する方法を
示したものです。
作者 :
Scott Field (sfield) 1996/05/14
--*/
#include <windows.h>
#include "ntsecapi.h" // \mstools\samples\win32\winnt\security\include\
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
NTSTATUS
NTAPI
PasswordChangeNotify(
PUNICODE_STRING UserName,
ULONG RelativeId,
PUNICODE_STRING Password
)
/*++
ルーチンの説明 :
この (省略可能な) ルーチンは、パスワードの変更を通知するために呼び出されます。
引数 :
UserName - パスワードを変更したユーザー名
RelativeId - パスワードを変更したユーザーの RID
NewPassword - そのユーザーの新しいクリアテキストのパスワード
戻り値 :
STATUS_SUCCESS のみ - パッケージからのエラーは無視します。
--*/
{
#ifdef DEBUG
LPWSTR String;
String = HeapAlloc(GetProcessHeap(), 0,
Password->Length + UserName->Length + (256*sizeof(WCHAR)));
swprintf(String,
L"Password for account %.*ls (rid 0x%x) changed to %.*ls\n",
UserName->Length / sizeof(WCHAR),
UserName->Buffer,
RelativeId,
Password->Length / sizeof(WCHAR),
Password->Buffer
);
OutputDebugStringW( String );
ZeroMemory(String,
Password->Length + UserName->Length + (256*sizeof(WCHAR)));
HeapFree(GetProcessHeap(), 0, String);
#endif
return STATUS_SUCCESS;
}
BOOL
NTAPI
PasswordFilter(
PUNICODE_STRING UserName,
PUNICODE_STRING FullName,
PUNICODE_STRING Password,
BOOL SetOperation
)
/*++
ルーチンの説明 :
この (オプション) ルーチンは、パスワードの変更を通知するために呼び出されます。
引数 :
UserName - パスワードを変更したユーザー名
FullName - パスワードを変更したユーザーのフルネーム
NewPassword - そのユーザーの新しいクリアテキストのパスワード
SetOperation - パスワードが変更ではなく設定された場合に TRUE を指定
戻り値 :
指定されたパスワードが適切な場合 (複雑さ、長さなど) は TRUE を返します。
システムは、ほかのインストール済みパスワード変更パッケージを使って、
パスワード更新の評価を継続します。
指定されたパスワードが適切でない場合は、FALSE を返します。 指定されたアカウントの
パスワード変更は失敗します。
--*/
{
BOOL bComplex = FALSE; // パスワードの複雑さが不十分と仮定
DWORD cchPassword;
PWORD CharType;
DWORD i;
DWORD dwNum = 0;
DWORD dwUpper = 0;
DWORD dwLower = 0;
//
// 4 種類の文字のうち、少なくとも 2 種類が使われているかどうかを
// チェックすることで、パスワードの複雑さが十分かどうかを
// チェックします。
//
CharType = HeapAlloc(GetProcessHeap(), 0, Password->Length);
if(CharType == NULL) return FALSE;
cchPassword = Password->Length / sizeof(WCHAR);
if(GetStringTypeW(
CT_CTYPE1,
Password->Buffer,
cchPassword,
CharType
)) {
for(i = 0 ; i < cchPassword ; i++) {
//
// 出現する文字の種類を追跡
//
if(CharType[i] & C1_DIGIT) {
dwNum = 1;
continue;
}
if(CharType[i] & C1_UPPER) {
dwUpper = 1;
continue;
}
if(CharType[i] & C1_LOWER) {
dwLower = 1;
continue;
}
if(!(CharType[i] & (C1_ALPHA | C1_DIGIT) )) {
//
// そのほかの種類の文字が使われていれば複雑なパスワード
//
dwNum = 2;
break;
}
} // for
//
// パスワードの複雑さが十分かどうかの結果
//
if( (dwNum + dwUpper + dwLower) >= 2 )
bComplex = TRUE;
ZeroMemory( CharType, Password->Length );
} // if
HeapFree(GetProcessHeap(), 0, CharType);
return bComplex;
}
BOOL
NTAPI
InitializeChangeNotify(
void
)
/*++
ルーチンの説明 :
この (省略可能な) ルーチンは、パスワード変更パッケージがロードされると
呼び出されます。
引数 :
戻り値 :
初期化に成功すると TRUE を返します。
初期化に失敗すると FALSE を返します。 この DLL はシステムによってアンロード
されます。
--*/
{
#ifdef DEBUG
OutputDebugString( TEXT("Initialize Change Notify called!\n") );
#endif
//
// パスワード変更、イベントなどに対応するクリティカル セクションを
// 初期化します。
//
return TRUE;
}
/********
pswdntfy.def
------------
LIBRARY pswdntfy
EXPORTS
InitializeChangeNotify
PasswordChangeNotify
PasswordFilter
********/
この資料は米国 Microsoft Corporation から提供されている Knowledge Base の Article ID
151082?
(http://support.microsoft.com/kb/151082/EN-US/
)
(最終更新日 2001-10-05) をもとに作成したものです。
この資料に含まれているサンプル コード/プログラムは英語版を前提に書かれたものをありのままに記述しており、日本語環境での動作は確認されておりません。