Zmienianie hasła użytkownika usługi Windows Active Directory i LDS za pomocą protokołu LDAP

W tym artykule opisano sposób zmiany hasła użytkownika usługi Windows Active Directory i LDS za pośrednictwem protokołu LDAP.

Dotyczy: Windows Active Directory
Oryginalny numer KB: 269190

Podsumowanie

Na podstawie pewnych ograniczeń można ustawić hasło usługi Active Directory i Lightweight Directory Services (LDS) systemu Windows za pomocą protokołu Lightweight Directory Access Protocol (LDAP). W tym artykule opisano sposób ustawiania lub zmieniania atrybutu hasła.

Te kroki mają również zastosowanie do użytkowników trybu aplikacji usługi Active Directory (ADAM) i użytkowników LDS oraz obiektów userProxy w taki sam sposób, jak w przypadku użytkowników usługi AD. Aby uzyskać szczegółowe informacje, zobacz dodatkowe wskazówki na końcu artykułu.

Więcej informacji

Hasło jest przechowywane w bazie danych usług AD i LDS w obiekcie użytkownika w atrybucie unicodePwd . Ten atrybut można zapisać w ograniczonych warunkach, ale nie można go odczytać. Atrybut można modyfikować tylko; nie można go dodać podczas tworzenia obiektu ani wykonywania zapytań przez wyszukiwanie.

Aby zmodyfikować ten atrybut, klient musi mieć 128-bitowe połączenie TLS (Transport Layer Security)/Secure Socket Layer (SSL) z serwerem. Sesja szyfrowana przy użyciu kluczy sesji utworzonych przez dostawcy usług SSP przy użyciu menedżera NTLM (Windows New Technology LAN Manager) lub Protokołu Kerberos jest również dopuszczalna, o ile zostanie osiągnięta minimalna długość klucza.

Aby to połączenie było możliwe przy użyciu protokołu TLS/SSL:

  • Serwer musi mieć certyfikat serwera dla 128-bitowego połączenia RSA.
  • Klient musi ufać urzędowi certyfikacji, który wygenerował certyfikat serwera.
  • Zarówno klient, jak i serwer muszą mieć możliwość szyfrowania 128-bitowego.

Składnia atrybutu unicodePwd to oktet-ciąg; Jednak usługa katalogowa oczekuje, że ciąg oktetu będzie zawierać ciąg UNICODE (jak wskazuje nazwa atrybutu). Oznacza to, że wszystkie wartości dla tego atrybutu przekazywane w LDAP muszą być ciągami UNICODE zakodowanymi w kodzie BER (Podstawowe reguły kodowania) jako ciąg oktetu. Ponadto ciąg UNICODE musi zaczynać się i kończyć cudzysłowami, które nie są częścią żądanego hasła.

Istnieją dwa możliwe sposoby modyfikowania atrybutu unicodePwd . Pierwsza z nich jest podobna do zwykłej operacji zmiany hasła przez użytkownika. W takim przypadku żądanie modyfikacji musi zawierać operację usuwania i dodawania. Operacja usuwania musi zawierać bieżące hasło z cudzysłowami wokół niej. Operacja dodawania musi zawierać żądane nowe hasło z cudzysłowami wokół niego.

Drugi sposób modyfikowania tego atrybutu jest analogiczny do resetowania hasła użytkownika przez administratora. W tym celu klient musi powiązać się jako użytkownik z wystarczającymi uprawnieniami, aby zmodyfikować hasło innego użytkownika. To żądanie modyfikacji powinno zawierać pojedynczą operację zastępowania nowym żądanym hasłem otoczonym cudzysłowami. Jeśli klient ma wystarczające uprawnienia, to hasło staje się nowym hasłem, niezależnie od tego, jakie było stare hasło.

Następujące dwie funkcje zawierają przykłady tych operacji:

ULONG ChangeUserPassword(WCHAR* pszUserDN, WCHAR* pszOldPassword,WCHAR* pszNewPassword)
{
    ULONG err = 1;
    LDAPMod modNewPassword;
    LDAPMod modOldPassword;
    LDAPMod *modEntry[3];
    BERVAL newPwdBerVal;
    BERVAL oldPwdBerVal;
    BERVAL *newPwd_attr[2];
    BERVAL *oldPwd_attr[2];
    WCHAR pszNewPasswordWithQuotes[1024];
    WCHAR pszOldPasswordWithQuotes[1024];
    
    // Build an array of LDAPMod.
    
    // For setting unicodePwd, this MUST be a double op.
    modEntry[0] = &modOldPassword;
    modEntry[1] = &modNewPassword;
    modEntry[2] = NULL;
    
    // Build mod struct for unicodePwd Add.
    modNewPassword.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
    modNewPassword.mod_type =L"unicodePwd";
    modNewPassword.mod_vals.modv_bvals = newPwd_attr;
    
    // Build mod struct for unicodePwd Delete.
    modOldPassword.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
    modOldPassword.mod_type =L"unicodePwd";
    modOldPassword.mod_vals.modv_bvals = oldPwd_attr;
    
    // Password will be single valued, so we only have one element.
    newPwd_attr[0] = &newPwdBerVal;
    newPwd_attr[1]= NULL;
    oldPwd_attr[0] = &oldPwdBerVal;
    oldPwd_attr[1]= NULL;
    
    // Surround the passwords in quotes.
    wsprintf(pszNewPasswordWithQuotes,L"\"%s\"",pszNewPassword);
    wsprintf(pszOldPasswordWithQuotes,L"\"%s\"",pszOldPassword);
    
    // Build the BER structures with the UNICODE passwords w/quotes.
    newPwdBerVal.bv_len = wcslen(pszNewPasswordWithQuotes) * sizeof(WCHAR);
    newPwdBerVal.bv_val = (char*)pszNewPasswordWithQuotes;
    oldPwdBerVal.bv_len = wcslen(pszOldPasswordWithQuotes) * sizeof(WCHAR);
    oldPwdBerVal.bv_val = (char*)pszOldPasswordWithQuotes;
    
    // Perform single modify.
    err = ldap_modify_s(ldapConnection,
    pszUserDN,
    modEntry
    );
    
    if (err == LDAP_SUCCESS )
    wprintf(L"\nPassword successfully changed!\n");
    else
    wprintf(L"\nPassword change failed!\n");
    
    return err;
}
    
ULONG SetUserPassword(WCHAR* pszUserDN, WCHAR* pszPassword)
{
    ULONG err = 1;
    LDAPMod modPassword;
    LDAPMod *modEntry[2];
    BERVAL pwdBerVal;
    BERVAL *pwd_attr[2];
    WCHAR pszPasswordWithQuotes[1024];
    
    // Build an array of LDAPMod.
    // For setting unicodePwd, this MUST be a single op.
    modEntry[0] = &modPassword;
    modEntry[1] = NULL;
    
    // Build mod struct for unicodePwd. 
    modPassword.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
    modPassword.mod_type =L"unicodePwd";
    modPassword.mod_vals.modv_bvals = pwd_attr;
    
    // Password will be single valued, so we only have one element.
    pwd_attr[0] = &pwdBerVal;
    pwd_attr[1]= NULL;
    
    // Surround the password in quotes.
    wsprintf(pszPasswordWithQuotes,L"\"%s\"",pszPassword);
    
    // Build the BER structure with the UNICODE password.
    pwdBerVal.bv_len = wcslen(pszPasswordWithQuotes) * sizeof(WCHAR);
    pwdBerVal.bv_val = (char*)pszPasswordWithQuotes;
    
    // Perform single modify.
    err = ldap_modify_s(ldapConnection,
    pszUserDN,
    modEntry
    );
    
    if (err == LDAP_SUCCESS )
    wprintf(L"\nPassword succesfully set!\n");
    else
    wprintf(L"\nPassword set failed!\n");
    
    return err;
}

Wskazówka

  • Aby skonfigurować wystąpienia usług LDS przy użyciu obiektów UserProxy na potrzeby resetowania haseł, należy zezwolić na ograniczone delegowanie konta usługi LDS (domyślnie: konto komputera LDS) do kontrolerów domeny w przypadku, gdy użytkownik loguje się przy użyciu protokołu Kerberos.
  • Jeśli używasz prostego powiązania LDAP, musisz użyć systemu Windows Server 2022 lub nowszej wersji i ustawić wpis rejestru, aby przekazać poświadczenia sesji LDAP administratora do kontrolera domena usługi Active Directory:
    Klucz rejestru: HKLM\system\currentcontrolset\services<LDS Instance>\Parameters
    Wpis rejestru: zezwalaj na typ logowania cleartext
    Typ: REG_DWORD
    Dane: 0: Nie zezwalaj na przekazywanie poświadczeń (ustawienie domyślne)
              1: Zezwalaj na przekazywanie poświadczeń na potrzeby resetowania hasła
  • Należy pamiętać, że zmiana w obu przypadkach oznacza, że serwer LDS należy uznać za urządzenie warstwy 0, ponieważ może uruchamiać zadania wrażliwe na zabezpieczenia na kontrolerze domeny.

Informacje zawarte w tym artykule dotyczą

  • Windows Server 2012 Datacenter
  • Windows Server 2012 standardowy
  • Windows Server 2012 R2 Datacenter
  • Windows Server 2012 R2 standardowy
  • System Windows Server 2016
  • Windows Server 2019
  • Windows Server 2022
  • Windows 8.1 Enterprise
  • Windows 8.1 Pro
  • Windows 10
  • Windows 11