在 Win2008 域中啟用對 Apache 的 AES 加密單點登錄
我可以找到的所有關於使用 Active Directory 身份驗證設置單點登錄到 Apache 託管網站的教程都是通過使用不安全設置配置 Kerberos 來實現的。一段時間以來,在 Active Directory 中禁用 Kerberos 的 RC4-HMAC 加密一直是最佳實踐,但是很多教程都要求覆蓋 krb5.conf 的預設值並讓一切都與 RC4-HMAC 一起工作。
我想嘗試使用 AES256 加密設置單點登錄,並且我設法讓它工作,所以我正在記錄這個問題和答案,以供其他任何希望為他們的網站提供更好安全性的人使用。
從 RC4-HMAC 開始
我們將首先讓它與 RC4-HMAC 一起工作,因為這更容易。設置 SSO 的標準步驟從創建具有關聯 SPN 的域帳戶開始,瀏覽器將使用該帳戶獲取加密憑據以發送到伺服器。對於這個例子,我的使用者是 REALM\HostServiceAccount:
- UPN:HostServiceAccount@realm.com(因此 Kerberos 主體名稱為 HostServiceAccount@REALM.COM)
- servicePrincipalName 屬性(也可由 setspn 設置):HTTP/host.example.com;HTTP/主機(Kerberos:HTTP/host.example.com@REALM.COM)
- 不理會加密設置;預設情況下,這使 RC4-HMAC 成為允許的最強加密,因此來自域的票證將具有此加密
我們將以下條目添加到目標伺服器上的 /etc/krb5.conf 中:
[libdefaults] default_realm = REALM.COM [domain_realm] .realm.com = REALM.COM realm.com = REALM.COM
我們創建 keytab 並讓伺服器讀取它:
# ktutil ktutil: add_entry -password -p HTTP/host.example.com@REALM.COM -k 1 -e rc4-hmac Password for HTTP/host.example.com@REALM.COM: <enter password here> ktutil: write_kt /etc/apache2/service.keytab ktutil: q # chown -v www-data:root /etc/apache2/service.keytab # chmod -v 440 /etc/apache2/service.keytab
(此時,當然,您會想要使用
kinit -kt service.keytab -S HTTP/host.example.com@REALM.COM HostServiceAccount@REALM.COM
來測試密鑰表。)最後,我們將 Apache 設置為使用我們的 keytab 對使用者進行身份驗證:
KrbDelegateBasic off KrbAuthoritative on KrbMethodK5Passwd off Krb5Keytab /etc/apache2/service.keytab KrbAuthRealms REALM.COM LogLevel debug
重啟 Apache 後,如果一切順利,我們會從我們的 Windows 域機器向伺服器發出請求,並在 Apache 的錯誤日誌中看到以下內容:
[debug] src/mod_auth_kerb.c(1641): [client ****] kerb_authenticate_user entered with user (NULL) and auth_type Kerberos, referer: **** [debug] src/mod_auth_kerb.c(1395): [client ****] Verifying client data using KRB5 GSS-API , referer: **** [debug] src/mod_auth_kerb.c(1411): [client ****] Client didn't delegate us their credential, referer: **** [debug] src/mod_auth_kerb.c(1430): [client ****] GSS-API token of length 185 bytes will be sent back, ****
在我們的客戶端機器上執行 klist(或 Wireshark 以查看請求中的票證),我們看到確實使用了 RC4-HMAC 票證進行身份驗證:
#4> Client: fluggo @ REALM.COM Server: HTTP/host.example.com @ REALM.COM KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
升級到更好的加密
一切都很好,但同樣,這不是我們的目標。RC4-HMAC 被認為是不安全的,所以讓我們禁用它並嘗試使相同的設置適用於 AES256。
首先,我們將要求我們友好的鄰居域管理員在 REALM\HostServiceAccount 上啟用高級加密,這將是兩個標記為的複選框:
- 此帳戶支持 Kerberos AES 128 位加密
- 此帳戶支持 Kerberos AES 256 位加密
根據您使用的工具,它們出現在不同的地方;最終結果應該是 LDAP 屬性 msDS-SupportedEncryptionTypes 應該是 0x18 或十進制 24,表示僅支持 AES128 和 AES256。
為了使其有效,我們將殺死我們的本地客戶票證:
C:>klist purge Current LogonId is 0:0xdeadbeef Deleting all tickets: Ticket(s) purged!
如果我們再次執行我們的請求,我們會看到請求失敗,但我們有一個更新的票:
C:>klist ... #3> Client: fluggo @ REALM.COM Server: HTTP/host.example.com @ REALM.COM KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
現在我們應該只需要用新算法更新我們的 keytab,我們應該是黃金:
# mv /etc/apache2/service.keytab ~/old.keytab # ktutil ktutil: add_entry -password -p HTTP/host.example.com@REALM.COM -k 1 -e aes256-cts-hmac-sha1-96 Password for HTTP/host.example.com@REALM.COM: <enter password here> ktutil: add_entry -password -p HTTP/host.example.com@REALM.COM -k 1 -e aes128-cts-hmac-sha1-96 Password for HTTP/host.example.com@REALM.COM: <enter password here> ktutil: write_kt /etc/apache2/service.keytab ktutil: q # chown -v www-data:root /etc/apache2/service.keytab # chmod -v 440 /etc/apache2/service.keytab
我們甚至不需要重新啟動 Apache。只需重新送出請求。
糟糕……它不起作用。如果我們查看 Apache 的錯誤日誌,我們會看到:
[debug] src/mod_auth_kerb.c(1641): [client ****] kerb_authenticate_user entered with user (NULL) and auth_type Kerberos [debug] src/mod_auth_kerb.c(1249): [client ****] Acquiring creds for HTTP@host.example.com [debug] src/mod_auth_kerb.c(1395): [client ****] Verifying client data using KRB5 GSS-API [debug] src/mod_auth_kerb.c(1411): [client ****] Client didn't delegate us their credential [debug] src/mod_auth_kerb.c(1430): [client ****] GSS-API token of length 9 bytes will be sent back [debug] src/mod_auth_kerb.c(1110): [client ****] GSS-API major_status:000d0000, minor_status:000186a5 [error] [client ****] gss_accept_sec_context() failed: Unspecified GSS failure. Minor code may provide more information (, )
好吧,這是一個非常無用的錯誤消息,但出了什麼問題?答案和一個解決方案,要遵循!
事實證明,這裡的主要問題是 AES256 旨在解決的問題之一。
TL;DR:keytab 中的主體名稱現在需要與帳戶名稱匹配。
問題
如果我們
KRB5_TRACE=/dev/stderr kinit HostServiceAccount@REALM.COM
在帳戶僅啟用 RC4-HMAC 加密時返回,我們會在輸出中看到這一行:[8192] 1441829478.537451: Selected etype info: etype rc4-hmac, salt "", params ""
但是,現在我們啟用了 AES256,該行如下所示:
[8200] 1441829508.947208: Selected etype info: etype aes256-cts, salt "REALM.COMHostServiceAccount", params ""
當從 NTLM 身份驗證切換到 Kerberos 時,指定了 RC4-HMAC 算法以重用 NTLM 雜湊。微軟拒絕在雜湊中添加鹽,以使現有系統更容易與 Kerberos 進行互操作。現在使用者有機會升級了,為AES256和AES128算法指定了一個salt,salt就是使用者名。
如果我們使用不同的使用者名為 RC4-HMAC 和 AES256 生成密鑰表,我們可以看到這一點。使用 RC4-HMAC:
fluggo@host:~$ ktutil ktutil: add_entry -password -p HTTP/host.example.com@REALM.COM -k 1 -e rc4-hmac Password for HTTP/host.example.com@REALM.COM: 12345 ktutil: add_entry -password -p HostServiceAccount@REALM.COM -k 1 -e rc4-hmac Password for HostServiceAccount@REALM.COM: 12345 ktutil: write_kt rc4.keytab ktutil: q fluggo@host:~$ klist -Kek rc4.keytab Keytab name: FILE:rc4.keytab KVNO Principal ---- -------------------------------------------------------------------------- 1 HTTP/host.example.com@REALM.COM (arcfour-hmac) (0x7a21990fcd3d759941e45c490f143d5f) 1 HostServiceAccount@REALM.COM (arcfour-hmac) (0x7a21990fcd3d759941e45c490f143d5f)
…雜湊是相同的,所以這兩個條目是等價的。但是使用 AES256:
fluggo@host:~$ ktutil ktutil: add_entry -password -p HTTP/host.example.com@REALM.COM -k 1 -e aes256-cts-hmac-sha1-96 Password for HTTP/host.example.com@REALM.COM: 12345 ktutil: add_entry -password -p HostServiceAccount@REALM.COM -k 1 -e aes256-cts-hmac-sha1-96 Password for HostServiceAccount@REALM.COM: 12345 ktutil: write_kt aes.keytab ktutil: q fluggo@host:~$ klist -Kek aes.keytab Keytab name: FILE:aes.keytab KVNO Principal ---- -------------------------------------------------------------------------- 1 HTTP/host.example.com@REALM.COM (aes256-cts-hmac-sha1-96) (0x5746fa6f9b0c990ba7fb20acd85065040d66e843a043508569841768ef2b7917) 1 HostServiceAccount@REALM.COM (aes256-cts-hmac-sha1-96) (0x6a98fdccbce4db77f40192f4e916e0900a1b9cba2f6ca8bc737d968e4b961c25)
…雜湊值不同。主體名稱很重要,它需要與帳戶的 UPN 匹配。
一個辦法
由於使用者名必須正確才能使 keytab 正常工作,因此我們生成一個新的 keytab,其主體名稱為 Active Directory 在票證上使用的名稱:
# rm /etc/apache2/service.keytab # ktutil ktutil: add_entry -password -p HostServiceAccount@REALM.COM -k 1 -e aes256-cts-hmac-sha1-96 Password for HostServiceAccount@REALM.COM: <enter password here> ktutil: add_entry -password -p HostServiceAccount@REALM.COM -k 1 -e aes128-cts-hmac-sha1-96 Password for HostServiceAccount@REALM.COM: <enter password here> ktutil: write_kt /etc/apache2/service.keytab ktutil: q # chown -v www-data:root /etc/apache2/service.keytab # chmod -v 440 /etc/apache2/service.keytab
Apache 關心 keytab 中的主體名稱,因此它不會自行找到這些條目。相反,我們只是指示 Apache 使用它可以找到的任何工作原理:
KrbServiceName Any
我希望 Apache 通過正確的名稱找到主體,但這並不重要,因為我們的主體是 keytab 中唯一的主體。
重新啟動 Apache,刷新頁面,現在應該可以進行身份驗證了。