先日紹介したAzure ADの新機能「Azure AD Password Protection for Windows Server Active Directory」を使うとブラックリストに載っているパスワードを使うことを禁止することは出来る様になりますが、特定の文字だけを禁止することは今のところ出来なさそうです。
エンタープライズのレガシーなID管理のシナリオだと未だにCSV万能説な文化なので、パスワードに特定の文字を使えなくしたい、というニーズがそこそこあります。
例えば、「,」(カンマ)とか「”」(ダブルクォート)とか「’」(シングルクォート)とかですね。なぜなら、平文パスワードをCSVに載せてFTPで送りつける、ということをしようとすると、この辺りの記号が邪魔をするんですよね・・・。
この辺りに起因する不具合を防止するために、CTRL+ALT+DELを使ったパスワード変更をグループポリシーで禁止して、ID管理パッケージの持つパスワード管理画面からしかパスワードを変更させない様に構成、ID管理システムではパスワードに利用できない文字を定義する、というのが従来の王道パターンでした。
しかし、やはりWindowsの標準の仕組みでパスワード変更を許可したい、というニーズは根強く、各社パスワード・フック用のモジュールをリリースしていたり、という状況です。
当ブログでもほぼ10年前に紹介した「Active Directoryのパスワード変更をフックする」という記事へのアクセスが以外と息が長く、今でもアクセス数トップ3くらいには入っていたりして、何とかしてADのパスワードを引っこ抜いてやろう、という人々が数多く存在するんだな~(違)と感じている今日この頃です。
最近も某所でCSVにパスワードを出力したいからカンマを使えない様にしたい、と言う雑談をしていたりしたので、良し悪しはおいておいてちょっと書いてみました。
この辺りにおいてあります。
https://github.com/fujie/pwdpol
Visual Studio 2017でC++のDLLを書く、というのも最近は中々無い経験なので新鮮な感じです。
ちゃちゃっと書いたので、エラーハンドリングやログ出力などもありませんし、Visual Studio 2017 on Windows 10 Proで作って、Windows Server 2012 R2で動作確認をしたので、VC++のランタイムのバージョンを合わせるのが面倒だったので、必要なDLL(msvcp140d.dll、vcruntime140d.dll、ucrtbased.dllの3つ)をC:\Windows\System32へコピーするとか強引なことをしてますが、皆さんはちゃんと必要なランタイムの再配布用パッケージをダウンロードして使ってください。
使い方は、ドメインコントローラ上で
・必要なDLLをC:\Windows\System32へ配置
・レジストリへの登録
・再起動
という3ステップですが、こちらは昔の記事と何も変わらないので、こちらをご参照ください。
https://idmlab.eidentity.jp/2018/06/azure-ad-ngad.html
こんなコードです。
<本体:pwdpol.cpp>
#include "stdafx.h"
#include <ntsecapi.h>
#include <regex>
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
using namespace std;
// initialize
BOOLEAN NTAPI InitializeChangeNotify(void) {
return TRUE;
}
// evaluate filter
BOOLEAN NTAPI PasswordFilter(
PUNICODE_STRING AccountName,
PUNICODE_STRING FullName,
PUNICODE_STRING Password,
BOOLEAN SetOperation) {
BOOLEAN ret;
// filter in regular expression
const wchar_t* pattern = LR"([\"\',])";
// convert PUNICODE_STRING to wstring
std::wstring pwd(Password->Buffer, Password->Length / sizeof(WCHAR));
// search filtered charactors
regex_search(pwd, wregex(pattern)) ? ret = FALSE : ret = TRUE;
// clear buffer
SecureZeroMemory((PVOID)pwd.c_str(), pwd.size());
return ret;
}
// notify change
NTSTATUS NTAPI PasswordChangeNotify(
PUNICODE_STRING UserName,
ULONG RelativeId,
PUNICODE_STRING NewPassword) {
// nop
return STATUS_SUCCESS;
}
LIBRARY "pwdpol"
EXPORTS
InitializeChangeNotify
PasswordFilter
PasswordChangeNotify
DLLの配置をして再起動すると上手くいけばポリシーが有効になります。
管理者がカンマを含むパスワードでリセットしようとしても
ユーザが自分でしようとしても、
ダメです。弾かれます。
良い子はマネしちゃいけませんよ。