如何以编程方式获取强制密码历史组策略设置?

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 来验证您的密码,例如:

它会按照计算机上有效的组策略执行所有这些操作。一切都很好,除了密码历史记录。

该函数要求您传递密码哈希列表,例如:

以及新候选密码的哈希值,例如:

这将导致 NetValidatePasswordPolicy 检查您当前的哈希值是否与任何现有哈希值匹配。不幸的是,检查以前的密码哈希值的整个概念只有在您使用弱密码算法 (such as PBKDF2 that Windows uses) 时才有效。

因为我使用现代的,昂贵的salted,密码散列算法(BCrypt/SCrypt),散列不能确定性地单独从密码生成 - 我不能简单地检查旧列表。我将不得不根据 每个 以前存储的盐重新散列用户的新密码。

我考虑过使用包含 24 个已存储密码哈希值的虚拟列表来调用 NetValidatePasswordPolicy,例如:

然后 API 会告诉我它的密码与 n 历史记录中的任何密码都不匹配。但是 API 也被设计为 return 给你你必须保留的东西。它 可能 然后 return:

据此我可能可以推断出密码历史长度为

但我还没到那里。

我已经三天了,已经失去耐心了。

事实证明,使用 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.