Introduction to LDAP Security

LDAP (Lightweight Directory Access Protocol) is the protocol that applications use to query and modify Active Directory. By default, Windows Server 2019 domain controllers accept LDAP connections on port 389 without requiring signing or channel binding, making them vulnerable to man-in-the-middle attacks where an attacker can intercept and relay LDAP authentication. Configuring LDAP security—specifically LDAP signing and LDAP channel binding—is one of the most impactful hardening measures for Active Directory. This tutorial covers enabling LDAP signing, enabling LDAP Channel Binding, configuring LDAPS (LDAP over TLS), and identifying non-compliant clients.

Understanding LDAP Vulnerabilities

Without LDAP signing, a man-in-the-middle attacker on the same network segment as a domain controller can relay NTLM authentication from a victim computer to the DC using the victim’s credentials. This is the basis of relay attacks like those facilitated by tools used in penetration testing. LDAP signing requires that LDAP messages be cryptographically signed by the sender, preventing tampering. Channel binding extends this protection by cryptographically linking the LDAP session to the underlying TLS channel.

Checking Current LDAP Signing Configuration

Before making changes, identify the current LDAP signing setting on your domain controllers and client computers. The setting is stored in the registry under HKLMSYSTEMCurrentControlSetServicesNTDSParameters.

Get-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesNTDSParameters" `
    -Name "LDAPServerIntegrity" -ErrorAction SilentlyContinue

Values: 0 = None (no signing required), 1 = Negotiate (prefer but allow unsigned), 2 = Required (reject unsigned LDAP). The default value on Windows Server 2019 is 1 (Negotiate).

Identifying Non-Compliant LDAP Clients

Before enforcing LDAP signing, identify all clients that currently connect with unsigned LDAP. Microsoft KB4520412 introduced diagnostic logging that captures unsigned LDAP binds. Enable this logging on domain controllers first, monitor for 30 days, then review the events before enforcing signing.

Enable LDAP interface events logging on the DC:

Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesNTDSDiagnostics" `
    -Name "16 LDAP Interface Events" -Value 2

Query the Directory Service event log for unsigned bind events (Event ID 2889 for unsigned binds, Event ID 3039 for clients without channel binding):

Get-WinEvent -FilterHashtable @{
    LogName = 'Directory Service'
    Id = 2889
} | ForEach-Object {
    $xml = [xml]$_.ToXml()
    [PSCustomObject]@{
        Time = $_.TimeCreated
        ClientIP = $xml.Event.EventData.Data[0].'#text'
        IdentityName = $xml.Event.EventData.Data[1].'#text'
    }
} | Sort-Object ClientIP -Unique

Configuring LDAP Signing via Group Policy

Configure LDAP signing on domain controllers via the Default Domain Controllers Policy or a dedicated GPO linked to the Domain Controllers OU. Navigate to Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options. Find “Domain controller: LDAP server signing requirements” and set it to Require signing.

gpmc.msc

Also configure the client side. Navigate to Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options and find “Network security: LDAP client signing requirements”. Set it to Require signing for domain computers. Link this GPO to all computer OUs.

Configuring LDAP Signing via Registry

Apply the LDAP server signing requirement directly via registry for immediate effect on a specific DC. Setting value 2 requires signing.

# On the Domain Controller - require signing
Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesNTDSParameters" `
    -Name "LDAPServerIntegrity" -Value 2 -Type DWord
# On client computers - require signing  
Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesldap" `
    -Name "LDAPClientIntegrity" -Value 2 -Type DWord

Configuring LDAP Channel Binding

LDAP Channel Binding ties the LDAP authentication to the underlying TLS connection, preventing credential relay even when LDAPS is used. Configure it on domain controllers via Group Policy under Domain controller: LDAP server channel binding token requirements.

# Registry method - value 1 = supported (default), 2 = always required
Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesNTDSParameters" `
    -Name "LdapEnforceChannelBinding" -Value 2 -Type DWord

Values: 0 = Disabled, 1 = Supported (allow clients without CBT), 2 = Always (reject clients without CBT). Set to 2 for maximum security after verifying all clients support channel binding.

Setting Up LDAPS (LDAP over TLS)

LDAPS operates on port 636 and encrypts the entire LDAP session using TLS. Domain controllers automatically support LDAPS when they have a valid certificate in the Machine certificate store with “Client Authentication” and “Server Authentication” EKU values, and the certificate subject or SAN matches the DC’s FQDN. Install a certificate via auto-enrollment from your internal CA (see Post 59) or install it manually.

# Verify LDAPS is working using ldp.exe
ldp.exe

In ldp.exe, go to Connection > Connect, enter the DC name, port 636, and check SSL. A successful connection confirms LDAPS is operational. Test from PowerShell:

$conn = [System.Net.Sockets.TcpClient]::new("DC01.yourdomain.com", 636)
if ($conn.Connected) { Write-Host "LDAPS port 636 is open" } else { Write-Host "LDAPS not available" }
$conn.Close()

Configuring LDAP Denial of Service Protection

Restrict maximum LDAP query results and connection limits to prevent resource exhaustion from runaway queries or DoS attempts. These settings are configured in the registry on domain controllers.

# Maximum number of objects returned per LDAP query (default 1000)
Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesNTDSParameters" `
    -Name "MaxPageSize" -Value 1000 -Type DWord

# Maximum time in seconds for an LDAP search before it is terminated (default 120)
Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesNTDSParameters" `
    -Name "MaxQueryDuration" -Value 120 -Type DWord

# Disable anonymous LDAP operations
Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesNTDSParameters" `
    -Name "DSHeuristics" -Value "0000002" -Type String

Verifying LDAP Configuration with ldp.exe

Use ldp.exe to test your LDAP security configuration. After enabling LDAP signing requirements, attempt an unsigned simple bind and verify it is rejected. This confirms the signing requirement is enforced.

ldp.exe

Connect to port 389 without SSL, then attempt a simple bind. With signing required, the bind should fail with an “Unwilling to perform” or “Strong authentication required” error.

Conclusion

Securing LDAP on Windows Server 2019 is a critical hardening step that Microsoft has been progressively enforcing through security updates. LDAP signing prevents relay attacks, LDAP channel binding prevents credential relay on TLS connections, and LDAPS provides full session encryption. The two-phase approach—first audit with event ID 2889 logging, then enforce—ensures you do not break legacy applications that use unsigned binds. Address any unsigned LDAP clients before enabling the Require signing policy on domain controllers.