如何以编程方式获取强制密码历史组策略设置?
How to programatically get the Enforce Password History group policy setting?
如何以编程方式获取 Enforce Password History 组策略设置?
研究工作
您可以在以下位置找到组策略选项:
**Computer Configuration\Windows Settings\Security Settings\Account Policies\Password Policy**
Enforce password history
This security setting determines the number of unique new passwords that have to be associated with a user account before an old password can be reused. The value must be between 0 and 24 passwords.
This policy enables administrators to enhance security by ensuring that old passwords are not reused continually.
与所有组策略选项一样,它存储在注册表中。不幸的是,它存储在一个未记录的注册表位置:
HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\F
在 undocumented binary blob format.
有是一个WMIclassRSOP_SecuritySettingBoolean,但是没有任何上下文,只是挂个名字而已在那里 - 我不知道如何阅读 COM/native.
NetValidatePasswordPolicy
Windows 确实提供了一个 NetValidatePasswordPolicy
API 来验证您的密码,例如:
- 太多失败的尝试
- 帐户锁定
- 锁定自动重置
- 密码最低使用期限
- 密码最长使用期限
- 密码重用
它会按照计算机上有效的组策略执行所有这些操作。一切都很好,除了密码历史记录。
该函数要求您传递密码哈希列表,例如:
a$mACnM5lzNigHMaf7O1py1OLCBgGL4tYUF0N/4rS9CwDsI7ytwL4D6
a$mACnM5lzNigHMaf7O1py1O3vlf6.BA8k8x3IoJ.Tq3IB/2e7g61Km
a$.TtQJ4Jr6isd4Hp.mVfZeuh6Gws4rOQ/vdBczhDx.19NFK0Y84Dle
a$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
以及新候选密码的哈希值,例如:
aJsBs47iuMNsV166PKV.u.56hlT5/tRe9V5t5FIdfA0axpDSQuNN
这将导致 NetValidatePasswordPolicy 检查您当前的哈希值是否与任何现有哈希值匹配。不幸的是,检查以前的密码哈希值的整个概念只有在您使用弱密码算法 (such as PBKDF2 that Windows uses) 时才有效。
因为我使用现代的,昂贵的,salted,密码散列算法(BCrypt/SCrypt),散列不能确定性地单独从密码生成 - 我不能简单地检查旧列表。我将不得不根据 每个 以前存储的盐重新散列用户的新密码。
- 这不仅是一项昂贵的操作;可能需要 12 秒来检查所有 24 个存储的哈希值
- 我不知道什么时候停止,因为我不知道密码历史组策略值(例如,我将检查所有 24 个存储的哈希,而我只需要检查零)。
我考虑过使用包含 24 个已存储密码哈希值的虚拟列表来调用 NetValidatePasswordPolicy
,例如:
a
b
c
d
- ...
v
w
x
然后 API 会告诉我它的密码与 n
历史记录中的任何密码都不匹配。但是 API 也被设计为 return 给你你必须保留的东西。它 可能 然后 return:
aJsBs47iuMNsV166PKV.u.56hlT5/tRe9V5t5FIdfA0axpDSQuNN
a
b
c
据此我可能可以推断出密码历史长度为 四。
但我还没到那里。
我已经三天了,已经失去耐心了。
- 为什么 Microsoft 混淆了组策略?
- 为什么 Microsoft 不允许人们阅读它?
- 为什么没有记录?
- 我怎样才能得到它们?
事实证明,使用 RSOP_SecuritySettingBoolean(策略的结果集)是个坏主意;因为它只适用于加入域的机器。
同样,查询 Active Directory 仅适用于加入域的计算机;并且适用于能够查询域控制器的用户(这是可以取消授权的)。
真正的解决方案是使用 NetUserModalsGet
,它可以 return 你的结构如下:
struct USER_MODALS_INFO_0
{
DWORD usrmod0_min_passwd_len;
DWORD usrmod0_max_passwd_age;
DWORD usrmod0_min_passwd_age
DWORD usrmod0_force_logoff;
DWORD usrmod0_password_hist_len; //Specifies the length of password history maintained.
//A new password cannot match any of the previous usrmod0_password_hist_len passwords.
//Valid values for this element are zero through DEF_MAX_PWHIST.
}
和
struct USER_MODALS_INFO_3
{
DWORD usrmod3_lockout_duration;
DWORD usrmod3_lockout_observation_window;
DWORD usrmod3_lockout_threshold;
}
示例代码为:
Int32 GetPasswordHistoryLength()
{
PUSER_MODALS_INFO_0 info0;
NET_API_STATUS res = NetUserModalsGet(nil, 0, out info0);
if (res <> NERR_Success)
RaiseWin32Error(res);
try
{
return info0.usrmod0_password_hist_len;
}
finally
{
NetApiBufferFree(info0);
}
}
文档说最大值是DEF_MAX_PWHIST
,在Lmaccess.h中定义为:
//
// user modals related defaults
//
#define MAX_PASSWD_LEN PWLEN
#define DEF_MIN_PWLEN 6
#define DEF_PWUNIQUENESS 5
#define DEF_MAX_PWHIST 8
#define DEF_MAX_PWAGE TIMEQ_FOREVER // forever
#define DEF_MIN_PWAGE (unsigned long) 0L // 0 days
#define DEF_FORCE_LOGOFF (unsigned long) 0xffffffff // never
#define DEF_MAX_BADPW 0 // no limit
#define ONE_DAY (unsigned long) 01*24*3600 // 01 day
但事实并非如此。该策略允许用户最多设置 24 个。
Note: Any code released into public domain. No attribution required.
如何以编程方式获取 Enforce Password History 组策略设置?
研究工作
您可以在以下位置找到组策略选项:
**Computer Configuration\Windows Settings\Security Settings\Account Policies\Password Policy**
Enforce password history
This security setting determines the number of unique new passwords that have to be associated with a user account before an old password can be reused. The value must be between 0 and 24 passwords.
This policy enables administrators to enhance security by ensuring that old passwords are not reused continually.
与所有组策略选项一样,它存储在注册表中。不幸的是,它存储在一个未记录的注册表位置:
HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\F
在 undocumented binary blob format.
有是一个WMIclassRSOP_SecuritySettingBoolean,但是没有任何上下文,只是挂个名字而已在那里 - 我不知道如何阅读 COM/native.
NetValidatePasswordPolicy
Windows 确实提供了一个 NetValidatePasswordPolicy
API 来验证您的密码,例如:
- 太多失败的尝试
- 帐户锁定
- 锁定自动重置
- 密码最低使用期限
- 密码最长使用期限
- 密码重用
它会按照计算机上有效的组策略执行所有这些操作。一切都很好,除了密码历史记录。
该函数要求您传递密码哈希列表,例如:
a$mACnM5lzNigHMaf7O1py1OLCBgGL4tYUF0N/4rS9CwDsI7ytwL4D6
a$mACnM5lzNigHMaf7O1py1O3vlf6.BA8k8x3IoJ.Tq3IB/2e7g61Km
a$.TtQJ4Jr6isd4Hp.mVfZeuh6Gws4rOQ/vdBczhDx.19NFK0Y84Dle
a$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm
以及新候选密码的哈希值,例如:
aJsBs47iuMNsV166PKV.u.56hlT5/tRe9V5t5FIdfA0axpDSQuNN
这将导致 NetValidatePasswordPolicy 检查您当前的哈希值是否与任何现有哈希值匹配。不幸的是,检查以前的密码哈希值的整个概念只有在您使用弱密码算法 (such as PBKDF2 that Windows uses) 时才有效。
因为我使用现代的,昂贵的,salted,密码散列算法(BCrypt/SCrypt),散列不能确定性地单独从密码生成 - 我不能简单地检查旧列表。我将不得不根据 每个 以前存储的盐重新散列用户的新密码。
- 这不仅是一项昂贵的操作;可能需要 12 秒来检查所有 24 个存储的哈希值
- 我不知道什么时候停止,因为我不知道密码历史组策略值(例如,我将检查所有 24 个存储的哈希,而我只需要检查零)。
我考虑过使用包含 24 个已存储密码哈希值的虚拟列表来调用 NetValidatePasswordPolicy
,例如:
a
b
c
d
- ...
v
w
x
然后 API 会告诉我它的密码与 n
历史记录中的任何密码都不匹配。但是 API 也被设计为 return 给你你必须保留的东西。它 可能 然后 return:
aJsBs47iuMNsV166PKV.u.56hlT5/tRe9V5t5FIdfA0axpDSQuNN
a
b
c
据此我可能可以推断出密码历史长度为 四。
但我还没到那里。
我已经三天了,已经失去耐心了。
- 为什么 Microsoft 混淆了组策略?
- 为什么 Microsoft 不允许人们阅读它?
- 为什么没有记录?
- 我怎样才能得到它们?
事实证明,使用 RSOP_SecuritySettingBoolean(策略的结果集)是个坏主意;因为它只适用于加入域的机器。
同样,查询 Active Directory 仅适用于加入域的计算机;并且适用于能够查询域控制器的用户(这是可以取消授权的)。
真正的解决方案是使用 NetUserModalsGet
,它可以 return 你的结构如下:
struct USER_MODALS_INFO_0
{
DWORD usrmod0_min_passwd_len;
DWORD usrmod0_max_passwd_age;
DWORD usrmod0_min_passwd_age
DWORD usrmod0_force_logoff;
DWORD usrmod0_password_hist_len; //Specifies the length of password history maintained.
//A new password cannot match any of the previous usrmod0_password_hist_len passwords.
//Valid values for this element are zero through DEF_MAX_PWHIST.
}
和
struct USER_MODALS_INFO_3
{
DWORD usrmod3_lockout_duration;
DWORD usrmod3_lockout_observation_window;
DWORD usrmod3_lockout_threshold;
}
示例代码为:
Int32 GetPasswordHistoryLength()
{
PUSER_MODALS_INFO_0 info0;
NET_API_STATUS res = NetUserModalsGet(nil, 0, out info0);
if (res <> NERR_Success)
RaiseWin32Error(res);
try
{
return info0.usrmod0_password_hist_len;
}
finally
{
NetApiBufferFree(info0);
}
}
文档说最大值是DEF_MAX_PWHIST
,在Lmaccess.h中定义为:
//
// user modals related defaults
//
#define MAX_PASSWD_LEN PWLEN
#define DEF_MIN_PWLEN 6
#define DEF_PWUNIQUENESS 5
#define DEF_MAX_PWHIST 8
#define DEF_MAX_PWAGE TIMEQ_FOREVER // forever
#define DEF_MIN_PWAGE (unsigned long) 0L // 0 days
#define DEF_FORCE_LOGOFF (unsigned long) 0xffffffff // never
#define DEF_MAX_BADPW 0 // no limit
#define ONE_DAY (unsigned long) 01*24*3600 // 01 day
但事实并非如此。该策略允许用户最多设置 24 个。
Note: Any code released into public domain. No attribution required.