Applies ToWindows Server 2008 Windows Server 2008 R2 Windows Server 2012 Windows Server 2012 R2 Windows Server 2016 Windows Server 2019, all editions

摘要

樹系信任為 Active Directory 樹系中的資源提供信任來自另一個樹系的識別的方法。 這個信任可以雙向設定。 受信任的樹系是使用者識別的來源。 信任的樹系包含使用者進行驗證的資源。 受信任的樹系可以對信任樹系的使用者進行驗證,而不允許進行相反的操作。

不受限制的 Kerberos 委派是使用者將其認證傳送到服務,讓服務可以代表使用者存取資源的機制。若要啟用不受限制的 Kerberos 委派,Active Directory 中服務的帳戶必須標示為受信任可以委派。 如果使用者和服務屬於不同樹系,則會造成問題。 服務樹系負責允許委派。 委派包括使用者樹系中的使用者認證。

允許一個樹系訂定影響另一個樹系帳戶的安全性決策,將會違反樹系之間的安全性界限。若攻擊者擁有信任的樹系,則可以對受信任樹系中的識別要求 TGT 委派,進而存取受信任樹系中的資源。 這不適用於 Kerberos 限制委派 (KCD)。

Windows Server 2012 引進對 Kerberos 完整委派的樹系界限強制執行 (英文)。 這個功能為受信任的網域新增原則,可根據信任來停用不受限制的委派。 這個功能的預設設定允許不受限制的委派,而且不安全。

下列 Windows Server 版本具有提供安全性強化的更新可供使用:

  • Windows Server 2019

  • Windows Server 2016

  • Windows Server 2012 R2

  • Windows Server 2012

這個功能及安全性強化中的變更已移植到下列版本:

  • Windows Server 2008 R2

  • Windows Server 2008

這些安全性變更會進行下列變更:

  • 安裝 5 月 14 日更新和以後的更新之後,依預設停用新樹系和新外部信任上不受限制的 Kerberos 委派。

  • 安裝 2019 年 7 月 9 日更新和以後的更新之後,停用樹系 (新的和現有的) 和外部信任上不受限制的 Kerberos 委派。

  • 系統管理員可以使用 5 月以後版本的 NETDOM 和 AD PowerShell 模組,藉此啟用不受限制的 Kerberos 委派。

這些更新可能會對樹系或外部信任間目前需要不受限制的 Kerberos 委派的應用程式造成相容性衝突。 對於依預設啟用隔離旗標 (也稱為 asSID 篩選) 的外部信任尤其如此。 具體來說,當您要求新票證時,對於透過所列信任類型使用不受限制委派的服務,驗證要求將會失敗。

如需發行日期,請參閱更新時間表

因應措施

若要在具有對 Kerberos 完整委派的樹系界限強制執行 (英文) 功能的 Windows Server 版本上提供資料和帳戶安全性,您可以在安裝 2019 年 3 月更新之後,將 netdom 旗標 EnableTGTDelegation 設定為 No,如下所示,藉此封鎖連入信任間的 TGT 委派:

netdom.exe trust fabrikam.com /domain:contoso.com /EnableTGTDelegation:No

分別安裝 2019 年 5 月和 7 月更新之後,新的和現有的樹系及外部信任上的 TGT 委派遭到封鎖。

若要重新啟用信任間的委派並回復原始的不安全設定,直到可以啟用限制或資源型委派,請將 EnableTGTDelegation 旗標設定為 Yes

啟用 TGT 委派的 NETDOM 命令列如下所示:

netdom trust <TrustedDomainName > /domain:<TrustingDomainName > /EnableTgtDelegation:Yes

概念上,您可以將用來啟用 TGT 委派的 NETDOM 語法想成:

netdom trust <domain that you are administering> /domain:<domain whose trust NETDOM is modifying> /EnableTgtDelegation:Yes

用來在 contoso.com 伺服器上啟用 fabrakam.com 使用者的 TGT 委派的 NETDOM 語法如下所示:

netdom.exe trust fabrikam.com /domain:contoso.com /EnableTGTDelegation:Yes

注意事項

  • 每個信任網域 (例如 contoso.com) 的 EnableTGTDelegation 旗標都應在受信任的網域 (在這個案例中,即為 fabrikam.com) 中設定。 設定旗標之後,受信任的網域將不再允許將 TGT 委派給信任網域。

  • EnableTGTDelegation 的安全狀態為 No

  • 若任何應用程式或服務依賴樹系間不受限制的委派,將會在以手動或程式設計方式將 EnableTGTDelegation 設定為 Yes 時發生失敗。 安裝 2019 年 5 月更新和 2019 年 7 月更新之後,新的和現有的信任上的 EnableTGTDelegation 會預設為 NO。 如需有關如何偵測這個失敗的詳細資訊,請參閱尋找依賴不受限制委派的服務。 請參閱更新時間表,以取得影響此因應措施套用方式的時間表變更。

  • 如需有關 NETDOM 的詳細資訊,請參閱 Netdom.exe 文件 (英文)

  • 如果您必須啟用信任上的 TGT 委派,建議您在用戶端電腦上啟用 Windows Defender Credential Guard,以避免這個風險。 這可以防止已啟用並執行 Windows Defender Credential Guard 的電腦中的所有不受限制委派。

  • 如果您擁有樹系或外部信任,並且其中一個設定為隔離,則無法啟用 TGT 委派,因為兩個旗標具有相反的語意。 隔離位元會強化參與網域之間的安全界限。 啟用 TGT 委派會將信任的網域存取權提供給受信任網域中的使用者認證,藉此清除網域之間的安全性界限。 您無法兩者都擁有。

    如果 [隔離] 旗標目前已啟用,請將 quarantine:no 旗標新增到 NETDOM 命令列語法。

  • 如果您已將 EnableTGTDelegation 變更為 Yes,請視需要刪除原始呼叫者和中繼呼叫者上的 Kerberos 票證。 要刪除的相關票證是相關信任間用戶端的轉介 TGT。 這可能牽涉不只一個裝置,視指定的環境中委派躍點的數目而定。

如需有關此程序的詳細資訊,請參閱下列 Windows IT Pro Center 文章:

使用 Windows Defender Credential Guard 保護衍生的網域認證 (部分機器翻譯)

更新時間表

2019 年 3 月 12 日

Kerberos 完整委派的樹系界限強制執行將以更新形式提供使用,以便在本文頂端<適用於>一節中所列、所有支援的 Windows Server 版本上啟用這個功能。 我們建議您在連入樹系信任上設定此功能。

此更新會將對 Kerberos 完整委派的樹系界限強制執行 (英文) 新增至下列系統:

  • Windows Server 2008 R2

  • Windows Server 2008

2019 年 5 月 14 日

已發行更新,將新的安全預設設定新增至新的樹系統和外部信任。 如果您需要信任間的委派,應在安裝 2019 年 7 月 9 日更新之前,先將 EnableTGTDelegation 旗標設定為 Yes。 如果您不需要信任間的委派,則不應設定 EnableTGTDelegation 旗標。 EnableTGTDelegation 旗標將會遭到忽略,直到安裝 2019 年 7 月 9 日更新為止,這讓系統管理員在需要時有時間可以重新啟用不受限制的 Kerberos 委派。

在此更新中,EnableTGTDelegation 旗標將會針對任何新建立的信任,依預設設定為 No。 這與先前的行為相反。 我們建議系統管理員改為重新設定受影響的服務,以便使用資源型限制委派。

如需有關如何偵測相容性問題的詳細資訊,請參閱尋找依賴不受限制委派的服務

2019 年 7 月 9 日

已發行更新,以便在樹系和外部信任的輸入端強制執行新的預設行為。 對於透過所列信任類型使用不受限制委派的服務,驗證要求將會經過驗證,但不包含委派。 當服務嘗試執行委派的操作時,將會發生失敗。

如需緩和措施,請參閱因應措施一節。

尋找依賴不受限制委派的服務

若要掃描具有允許 TGT 委派的連入信任的樹系,並尋找允許不受限制委派的任何安全性主體,請在指令碼檔案中執行下列 PowerShell 指令碼 (例如,Get-RiskyServiceAccountsByTrust.ps1 -Collect):

注意

您也可以傳遞 -ScanAll 旗標,以便在不允許 TGT 委派的信任間進行搜尋。


[CmdletBinding()]  
Param  
(  
    [switch]$Collect, 
    [switch]$ScanAll 
) 
 
if ($Debug) {  
    $DebugPreference = 'Continue'  
} 
else { 
    $DebugPreference = 'SilentlyContinue'  
} 

function Get-AdTrustsAtRisk 
{ 
    [CmdletBinding()]  
    Param  
    (  
        [string]$Direction = "Inbound", 
        [switch]$ScanAll 
    ) 
 
    if ($ScanAll) { 
        return get-adtrust -filter {Direction -eq $Direction} 
    } 
    else { 
        return get-adtrust -filter {Direction -eq $Direction -and TGTDelegation -eq $false} 
    } 
} 
 
function Get-ServiceAccountsAtRisk 
{ 
    [CmdletBinding()]  
    Param  
    (  
        [string]$DN = (Get-ADDomain).DistinguishedName, 
        [string]$Server = (Get-ADDomain).Name 
    ) 
 
    Write-Debug "Searching $DN via $Server" 
 
    $SERVER_TRUST_ACCOUNT = 0x2000  
    $TRUSTED_FOR_DELEGATION = 0x80000  
    $TRUSTED_TO_AUTH_FOR_DELEGATION= 0x1000000  
    $PARTIAL_SECRETS_ACCOUNT = 0x4000000    
 
    $bitmask = $TRUSTED_FOR_DELEGATION -bor $TRUSTED_TO_AUTH_FOR_DELEGATION -bor $PARTIAL_SECRETS_ACCOUNT  
  
$filter = @"  
(& 
  (servicePrincipalname=*) 
  (| 
    (msDS-AllowedToActOnBehalfOfOtherIdentity=*) 
    (msDS-AllowedToDelegateTo=*) 
    (UserAccountControl:1.2.840.113556.1.4.804:=$bitmask) 
  ) 
  (| 
    (objectcategory=computer) 
    (objectcategory=person) 
    (objectcategory=msDS-GroupManagedServiceAccount) 
    (objectcategory=msDS-ManagedServiceAccount) 
  ) 
) 
"@ -replace "[\s\n]", ''  
  
    $propertylist = @(  
        "servicePrincipalname",   
        "useraccountcontrol",   
        "samaccountname",   
        "msDS-AllowedToDelegateTo",   
        "msDS-AllowedToActOnBehalfOfOtherIdentity"  
    )  
 
    $riskyAccounts = @() 
 
    try { 
        $accounts = Get-ADObject -LDAPFilter $filter -SearchBase $DN -SearchScope Subtree -Properties $propertylist -Server $Server 
    } 
    catch { 
        Write-Warning "Failed to query $Server. Consider investigating seperately. $($_.Exception.Message)" 
    } 
              
    foreach ($account in $accounts) {  
        $isDC = ($account.useraccountcontrol -band $SERVER_TRUST_ACCOUNT) -ne 0  
        $fullDelegation = ($account.useraccountcontrol -band $TRUSTED_FOR_DELEGATION) -ne 0  
        $constrainedDelegation = ($account.'msDS-AllowedToDelegateTo').count -gt 0  
        $isRODC = ($account.useraccountcontrol -band $PARTIAL_SECRETS_ACCOUNT) -ne 0  
        $resourceDelegation = $account.'msDS-AllowedToActOnBehalfOfOtherIdentity' -ne $null  
      
        $acct = [PSCustomobject] @{  
            domain = $Server 
            sAMAccountName = $account.samaccountname  
            objectClass = $account.objectclass          
            isDC = $isDC  
            isRODC = $isRODC  
            fullDelegation = $fullDelegation  
            constrainedDelegation = $constrainedDelegation  
            resourceDelegation = $resourceDelegation  
        }  
 
        if ($fullDelegation) {  
            $riskyAccounts += $acct    
        } 
    }  
 
    return $riskyAccounts 
} 
 
function Get-RiskyServiceAccountsByTrust  
{ 
    [CmdletBinding()]  
    Param  
    ( 
        [switch]$ScanAll 
    ) 
     
    $riskyAccounts = @() 
 
    $trustTypes = $("Inbound", "Bidirectional") 
 
    foreach ($type in $trustTypes) { 
 
        $riskyTrusts = Get-AdTrustsAtRisk -Direction $type -ScanAll:$ScanAll 
 
        foreach ($trust in $riskyTrusts) { 
            $domain = $null 
     
            try { 
                $domain = Get-AdDomain $trust.Name -ErrorVariable eatError -ErrorAction Ignore 
            } catch { 
                write-debug $_.Exception.Message 
            } 
 
            if($eatError -ne $null) { 
                Write-Warning "Couldn't find domain: $($trust.Name)" 
            } 
 
            if ($domain -ne $null) { 
                $accts = Get-ServiceAccountsAtRisk -DN $domain.DistinguishedName -Server $domain.DNSRoot 
 
                foreach ($acct in $accts) { 
                    Write-Debug "Risky: $($acct.sAMAccountName) in $($acct.domain)" 
                }             
 
                $risky = [PSCustomobject] @{  
                    Domain = $trust.Name 
                    Accounts = $accts 
                } 
 
                $riskyAccounts += $risky 
            } 
        } 
    } 
 
    return $riskyAccounts 
} 
 
if ($Collect) { 
   Get-RiskyServiceAccountsByTrust -ScanAll:$ScanAll | Select-Object -expandProperty Accounts | format-table 
}

PowerShell 指令碼的輸出會列出網域中設定用於連入信任 (來自已設定不受限制委派的執行網域) 的 Active Directory 安全性主體。 輸出會類似下列範例。

domain

sAMAccountName

objectClass

partner.fabrikam.com

dangerous

user

partner.fabrikam.com

labsrv$

computer

透過 Windows 事件偵測不受限制的委派

發行 Kerberos 票證時,Active Directory 網域控制站會記錄下列安全性事件。 這些事件包含有關目標網域的資訊。 您可以使用這些事件來判斷不受限制的委派是否用於連入信任之間。

注意

請檢查包含與受信任網域名稱相符之 TargetDomainName 值的事件。

事件記錄檔

事件來源

事件識別碼

詳細資料

安全性

Microsoft-Windows-Security-Auditing

4768

Kerberos TGT 已發行。

安全性

Microsoft-Windows-Security-Auditing

4769

Kerberos 服務票證已發行。

安全性

Microsoft-Windows-Security-Auditing

4770

Kerberos 服務票證已更新。

疑難排解驗證失敗

停用不受限制的委派時,如果應用程式依賴不受限制的委派,則應用程式可能會遇到與這些變更相關的相容性問題。 這些應用程式應設定為使用限制委派或以資源為主的限制委派。 如需詳細資訊,請參閱 Kerberos 限制委派概觀 (部分機器翻譯)

依賴信任間來回行程驗證的應用程式並未受支援使用限制委派。 例如,如果樹系 A 中的使用者向樹系 B 中的應用程式驗證,並且樹系 B 中的應用程式嘗試將票證委派回樹系 A,則委派會失敗。

Need more help?

Want more options?

探索訂閱權益、瀏覽訓練課程、瞭解如何保護您的裝置等等。

社群可協助您詢問並回答問題、提供意見反應,以及聆聽來自具有豐富知識的專家意見。