Almost every AD security assessment, penetration test, or architecture conversation ends up containing the recommendation to “switch from unsecured LDAP to LDAPS” for your Active Directory (AD). Working for a software vendor whose products “do stuff with AD,” I hear the question multiple times a week: “Does your product XY support LDAPS? If not, is it on the roadmap?”. In most cases, the correct answer is “No, and it’s not a security concern.” Let’s look at the reasons for that answer.
What’s the problem with LDAPS?
The Internet offers literally thousands of articles, blogs, and videos on how to create and import TLS certificates into your domain controllers (DCs) to make them serve LDAP over TLS on Port 636/TCP. For more information about the method that DCs use to select their LDAPS certificate when multiple candidates exist, you can read this post from Marc-André Moreau at AwakeCoding, but to recap, Moreau explains that:
“Enabling and enforcing LDAPS is a common security hardening task in Windows Active Directory environments today…. In theory, it all looks great, until you realize that not only [can’t you] explicitly select the LDAPS certificate to use, but there are no logs to enable, and no way to diagnose the problem.”
What these “implement LDAPS” articles usually do not tell you is what to do with LDAPS after it’s enabled. One thing is for certain, however: Your DCs will continue serving TLS-less LDAP on Port 389, and you cannot disable it or block it on the firewall without severely disrupting your AD members.
Let me repeat: An AD member will always use Port 389/3268 for any LDAP/GC queries it has to perform by virtue of its being an AD member. There is no way to change that behavior or to entice a member machine to use the TLS-backed LDAPS on Port 636/3269, period. There is also no standardized, universally reliable way to have the infrastructure advertise LDAPS to applications.
Why LDAPS workarounds don’t work
Because the only known mechanism for LDAP service discovery is DNS, people have tried multiple techniques:
- Add an SRV record for LDAPS, like _ldaps._tcp.domain.com along with _ldap and _gc.
- Change the port number in the LDAP service records from 389 to 636 (and prevent them from being updated by DCs).
- Replace _ldap SRV records with _ldaps (i.e., actually delete the _ldap and _gc records).
Here’s the problem with those approaches: They don’t work.
Adding an SRV record for LDAPS changes nothing
Because _ldaps is not a standard service, no application will look for it in DNS. If you create an application that would benefit from LDAP over TLS, you are welcome to implement LDAPS service discovery in your code; it will then work like every custom service discovery. But it is not and never has been an industry standard, so no other application will make use of it.
Changing the port number won’t work
Changing the port number will not disrupt AD members’ communications because Port 389 is hardcoded in Windows. This action might disrupt other LDAP-consuming applications, because switching the port from 389 to 636 will not cause them to try to establish a TLS handshake before attempting an LDAP bind.
Deleting _ldap and _gc records = Just don’t
The third approach is a great way to break service discovery for LDAP, including that of domain members. Don’t do this at home (or at work … or anywhere, really).
Simple binds vs SASL binds
So, is LDAP in Active Directory just “insecure by design”? Quite the contrary.
The reason you’ve been advised to switch to LDAPS is to protect the cleartext credentials that LDAP uses if you perform a simple bind. The thing is, AD members—and most of the applications accessing AD via LDAP—do not use simple binds. Instead, they use SASL binds in which authentication is performed by GSS-SPNEGO and the LDAP encryption layer is negotiated with session keys exchanged during the authentication process.
So, not only are there no cleartext credentials to protect, but the communication that takes place is, in fact, already encrypted, without needing to rely on certificates for the TLS layer. This mechanism is not limited to domain members. Any application can do this, regardless of operating system and domain membership.
What should you do to harden AD LDAP, if not block Port 389?
If you are certain that no application in your environment actually needs simple binds with cleartext credentials, enforce LDAP signing on your DCs by setting the Group Policy as described here. In addition to … well, having the communications signed, which will prevent a variety of Kerberos and NTLM relay attacks, the DCs will also reject a simple bind over an unencrypted LDAP connection.
If you want to be absolutely sure you aren’t disrupting anything, observe your DCs’ event logs, as described in this evergreen Learn article about LDAP signing, Channel Binding and LDAPS.
If you do have applications that require a simple bind, force those applications to use Port 636/3269 by configuring this behavior (and the trust in the LDAPS certificates) within the applications themselves.
[Editor’s note: This blog was adapted from the author’s original post.]
