Článkov o tom, ako nakonfigurovať synchronizáciu hesiel z vnútrofiremného Active Directory do Azure AD / Office 365, či už pomocou pôvodného nástroja DirSync, alebo jeho novšej verzie s názvom Azure AD Connect, nájdete na internete hromadu a nie je to žiadna veda. Čo sa však nikde nedočítate, je to, ako presne táto synchronizácia funguje. A to je otázka, ktorú si určite položí každý správca, ktorému bezpečnosť nie je cudzia. Rozhodol som sa teda, že to preskúmam a podelím sa s Vami o výsledky svojho bádania.

Ako získava DirSync heslá z AD

Niekoho by mohlo napadnúť, že to DirSync rieši odchytávaním zmeny hesiel pomocou Password Filters, ale nie j tomu tak. Toto riešenie by totiž vyžadovalo zmenu hesiel všetkých používateľov a prítomnosť synchronizačného agenta na všetkých doménových kontroléroch, čo by nebolo veľmi pohodlné. DirSync preto z Active Directory získava existujúce heslá cez protokol MS-DRSR, čo je technológia, pomocou ktorej si medzi sebou štandardne replikujú dáta doménové kontroléry. Jediný citlivý údaj, ktorý si DirSync z AD načítava, je atribút unicodePwd, ktorý obsahuje MD4 hash (nazývaný tiež NT Hash) používateľského hesla. DirSync sa tak v žiadnom prípade nedostane k plaintextovej podobe hesla.

Táto funkcionalita DirSyncu je implementovaná v knižnici Microsoft.Online.PasswordSynchronization.Rpc.dll.

V akej podobe posiela DirSync heslá do Azure AD

Je celkom známe, že MD4 hash sa používa v autentizačných protokoloch NTLM a Kerberos a je v podstate ekvivalentom hesla. Navyše sa z dnešného pohľadu jedná o zastaralú hashovaciu funkciu, ktorá sa pri heslách do 10 znakov dá efektívne prelomiť pomocou rainbow tables aj brute-force útoku. Z týchto dôvodov by nebolo veľmi bezpečné, keby DirSync posielal do cloudu priamo MD4 hashe. Preto s nimi spraví ešte túto transformáciu:

Hashe, ktoré majú 16B, sú najprv skonvertované do kapitálkovej textovej hexadecimálnej reprezentácie, čím sa zväčšia na 32B. Ďalej sú prekódované do UTF-16 kódovania, čo ich roztiahne na 64B. Následne sa vygeneruje 10B náhodných dát, ktoré budú slúžiť ako tzv. soľ. Na to je na záver aplikovaná štandardná funkcia PBKDF2 (Password-based Key Derivation Function 2) so 100 iteráciami hashu HMAC-SHA256, ktorej výstupom je hash dlhý 32B. Tento hash je interne nazývaný OrgId Hash a až v jeho podobe sú heslá odosielané na servery Microsoftu.

Schematicky vyzerá výpočet OrgId hashu nasledovne:

OrgId Hash(NTHash) := PBKDF2(UTF-16(ToUpper(ToHex(NTHash)))), RND(10), 100, HMAC-SHA256, 32)

NT hash sa pri nastavení hesla v Active Directory vypočíta takto:

NTHash(plaintext) := MD4(UTF-16(plaintext))

Po dosadení NT hashu do predošlého vzorca dostaneme kompletnú transformáciu, ktorá je aplikovaná na heslo, od jeho nastavenia až po odoslanie do Azure AD:

OrgId Hash(plaintext) := PBKDF2(UTF-16(ToUpper(ToHex(MD4(UTF-16(plaintext))))), RND(10), 100, HMAC-SHA256, 32)

Príklad: MD4 hash hesla „Pa$$w0rd” je v kapitálkovej hexadecimálnej reprezentácii nasledovný:

92937945B518814341DE3F726500D4FF

Ak by k nemu DirSync vygeneroval soľ “317ee9d1dec6508fa510”, do Azure AD by bol odoslaný presne tento reťazec:

v1;PPH1_MD4,317ee9d1dec6508fa510,100, f4a257ffec53809081a605ce8ddedfbc9df9777b80256763bc0a6dd895ef404f;

Vidíme, že reťazec obsahuje nielen OrgId hash vygenerovaný pomocou PBKDF2, ale aj číslo verzie hashu, soľ a počet iterácií. Z toho sa dá usúdiť, že už súčasná implementácia je pripravená na budúcu zmenu algoritmu, napríklad zvýšenie počtu iterácií či použitie inej hashovacej funkcie.

DirSync generuje OrgId hashe pomocou knižnice Microsoft.Online.PasswordSynchronization.Cryptography.dll.

Súlad s FIPS

Pokiaľ by ste na serveri, kde beží DirSync, vypli podporu algoritmov, ktoré nie sú v súlade so štandardom FIPS 140-2, nebude Vám DirSync bez nastavenia patričnej výnimky fungovať. Príčinou je samotný protokol MS-DRSR, ktorý prenáša MD4 hashe zašifrované kombináciou algoritmov RC4, MD5 a DES. Aby mohol DirSync tieto hashe dešifrovať, musí zákonite uvedené algoritmy použiť.

Bezpečnostná analýza

Popísanému algoritmu by sa dalo z bezpečnostného hľadiska vytknúť len jediné: V príslušnom RFC dokumente z roku 2000 sa odporúča použiť PBKDF2 s aspoň 1000 iteráciami, kým DirSync ich používa iba 100. To je zvláštne rozhodnutie, pretože už vo Windows Vista bola interne používaná funkcia PBKDF2 s 10240 iteráciami. Argumentom by snáď mohla byť snaha znížiť záťaž autentizačných serverov. No rádovo 100-násobné zvýšenie počtu iterácií podľa nemá až tak drastický dopad na výkon: Môj rýchly a neobjektívny test ukázal, že kým 100 iterácií trvá na procesore Core i5 cca. 10ms, 10240 iterácií predĺži čas potrebný k výpočtu na stále prijateľných 60 ms. Tieto čísla treba brať s veľkou rezervou, ale na vytvorenie si obrazu stačia. Ako sme si už ale naznačili, počet iterácií s pravdepodobne časom zmení.

Druhé odporúčanie z RFC, dĺžku soli minimálne 8B, už DirSync použitím 10B spĺňa. Nekonvenčný je ešte spôsob natiahnutia MD4 hashu zo 16B na 64B, ale na bezpečnosť to nemá žiaden vplyv. Vďaka použitiu náhodnej soli sa nebudú zhodovať hashe prípadných duplicitných hesiel. To je obzvlášť dôležité u cloudovej služby, kde je možné predpokladať milióny účtov a tým pádom vyššiu pravdepodobnosť výskytu totožných hesiel v jednej databáze.

Funkcia PBKDF2 je dnes pri použití rozumného hesla považovaná za bezpečnú. Aj keby sa k OrgId hashu dostala nepovolaná osoba, nepodarilo by sa jej ho zneužiť k preniknutiu do vnútrofiremnej siete. Preto z posielania hesiel v tejto podobe do Azure Active Directory zrejme neplynie bezpečnostné riziko.

Ukážková implementácia

Pre demonštračné účely som si naprogramoval moju vlastnú implementáciu OrgId hashu. Je sprístupnená cez PowerShell cmdlet ConvertTo-OrgIdHashmodule DSInternals. Tu je ukážka jeho použitia:

PowerShell OrgId Hash Calculation