文書番号: 151082 - 最終更新日: 2003年7月22日 - リビジョン: 2.1

[HOWTO] Windows NT でのパスワード変更のフィルタリングと通知

お知らせお使いのオペレーティング システムには適用しない情報が含まれている場合があります。
この記事は、以前は次の ID で公開されていました: JP151082

目次

すべて展開する | すべて折りたたむ

概要

この資料は、パスワード変更パッケージの機能について記述したものです。このパッケージを使用すると、パスワード変更の通知を受信したり、パスワードの質を管理することが可能になります。

パスワード変更通知を使用すると、外部のアカウント データベースを同期させることができます。 パスワード変更通知の機能は、Windows NT 3.51 以降で利用可能です。

パスワード フィルタを使用すると、新しいパスワードの質や強度を厳格に管理することが可能になります。また、PasswordFilter ルーチンを使って、新しいパスワードが適切なものかどうかを示すことができます。 パスワード フィルタ機能は、Service Pack 2 をインストールした Windows NT 4.0 上でのみ利用可能です。

注 : この機能にはほかの用途も考えられますが、この資料では説明していません。

注意 : クリア テキスト (暗号化されていないテキスト) のパスワードを取り扱う際には十分注意してください。 パスワードをクリア テキストのままネットワーク上に送信すると、ネットワーク上のセキュリティ レベルが低下する可能性があります。これは、そうしたパスワードのトラフィックを監視しているネットワーク "Sniffer" が存在する可能性があるためです。 パスワードの保管に使用したメモリは、解放する前にゼロの値で埋めることが推奨されます。 この資料は、読者がパスワード情報を安全に取り扱う方法を知っていることを前提に書かれています。

この機能へのインターフェイスは、Windows NT の将来のリリースで変更される可能性があります。

詳細

パスワード変更イベントに関する注意点

  1. 通知およびフィルタのルーチンに渡すバッファはすべて、読み取り専用として扱う必要があります。 これらのバッファにデータを書き込むと、動作が不定になる可能性があります。
  2. 通知およびフィルタのルーチンは、スレッドセーフでなければなりません。 必要に応じて、クリティカル セクションやそのほかの同期テクニックを使ってデータを保護してください。
  3. InitializeChangeNotify 関数は、パスワード通知 DLL がロードされると呼び出されます。 この関数が FALSE を返す場合、DLL はアンロードされます。 この関数は、パスワード通知固有の初期化を記述できるように提供されているものです。これにより、パスワード DLL をほかの用途に使用できるようになります。
  4. PasswordFilter 関数は、パスワード変更の要求があったときに呼び出されます。 そのようなパスワード変更イベントは、アカウントの作成、管理者によるパスワードの変更、およびユーザー指定のパスワード変更の際に発生します。 この関数が TRUE を返した場合、そのパスワードは有効と見なされ、システムにインストールされているほかのパスワード変更パッケージを使ったパスワードの評価が続けられます。 この関数が FALSE を返した場合、そのパスワードは無効と見なされ、パスワード変更の要求元に ERROR_ILL_FORMED_PASSWORD (1324) が返されます。
  5. PasswordChangeNotify 関数は、提供されたパスワードがフィルタを通過し、パスワードの保管に成功した後に呼び出されます。 現在のところ、PasswordChangeNotify の戻り値は使われていません。 Windows NT の現在のリリースでは、PasswordChangeNotify は常に STATUS_SUCCESS (0x00000000L) を返します。
  6. 通知やフィルタリングが行われるのは、更新されるアカウントが存在するコンピュータだけです。 ドメイン ユーザーのアカウントを扱うときには、この点に留意してください。 ドメイン アカウントに関する通知は、そのドメインのプライマリ ドメイン コントローラでしか行われません。 通知パッケージは、PDC だけでなく、すべての BDC にもインストールする必要があります。これは、サーバーの役割が変更された場合でも、通知を継続できるようにするためです。
  7. この機能を使用するには、REG_MULTI_SZ の型を持つ、次のレジストリ エントリが正しく設定されている必要があります。
          HKEY_LOCAL_MACHINE\ 
           SYSTEM\ 
           CurrentControlSet\ 
           Control\ 
           Lsa\ 
           Notification Packages (型が REG_MULTI_SZ の値)
    

    Notification Packages には DLL のリストが含まれています。ここに記載される DLL がロードされ、パスワード変更およびパスワード変更の要求が通知されます。 この値がレジストリに存在しない場合は、作成する必要があります。
  8. パスワード変更パッケージは、次の関数から成ります。

    • InitializeChangeNotify
    • PasswordFilter
    • PasswordChangeNotify


    それぞれの関数は省略可能です。また、NTAPI または WINAPI として宣言し、正しい呼び出し規約を保証する必要があります。 使用する関数は、DLL の作成時に使われる .DEF ファイルに記述しておく必要があります。
  9. 処理されない例外がこれらの関数内で発生すると、システム全体に波及するセキュリティ関連の障害の原因となります。必要な場合は、構造化例外処理を使用する必要があります。
  10. パスワード変更関数の呼び出し側は、各関数が完了するまでブロックします。 長い時間を要する処理は、PasswordChangeNotify や PasswordFilter から戻るのを待たずに、適宜別のスレッドで実行するようにしてください。
  11. PasswordChangeNotify、PasswordFilter、および InitializeChangeNotify の各関数は、ローカル システム アカウントのセキュリティ コンテキストで実行されます。
  12. 通知パッケージのローディングは、AuditCategorySystem の "再起動、シャットダウン、およびシステム" 監査イベントの種類を使って監査できるイベントです。
  13. パスワード変更通知とパスワード フィルタは、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 では、次のパスワード ポリシーが実装されています。
  1. パスワードの長さは 6 文字以上である。
  2. 2.パスワードに、次の 4 つの種類のうち少なくとも 3 つの種類の文字を使用する。
       説明                            例
       英大文字                        A, B, C, ... Z
       英小文字                        a, b, c, ... z
       数字                            0, 1, 2, ... 9
       英数字以外の句読点など
    
  3. 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) をもとに作成したものです。

この資料に含まれているサンプル コード/プログラムは英語版を前提に書かれたものをありのままに記述しており、日本語環境での動作は確認されておりません。


この資料は以下の製品について記述したものです。
  • Microsoft Win32 Software Development Kit (SDK) 4.0?を以下の環境でお使いの場合
    • Microsoft Windows NT 4.0
    • Microsoft Windows 2000 Standard Edition
    • Microsoft Windows XP Professional
キーワード:?
4.00 kbapi kbcode kbfaq kbgrpdskernbase kbhowto kbkernbase kbwin32sdkfaq notification password KB151082
"Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。"