Django LDAP认证明文传输问题:如何在TCP/389下实现安全认证?
解决方案:用NTLM认证替代简单绑定,避免LDAP明文传密码
你的场景确实很常见——AD没开LDAPS,又没有权限修改配置,那NTLM认证是最适合的方案,它能在389端口上安全传输认证信息,不需要LDAPS或START_TLS,而且可以通过自定义django_auth_ldap后端轻松实现。
核心思路
AD原生支持NTLM认证,它采用挑战-响应机制,不会明文传输密码。我们只需要重写django_auth_ldap的绑定逻辑,把默认的简单绑定换成NTLM绑定即可。
具体代码修改步骤
- 创建自定义LDAP后端
在你的Django项目里(比如某个app的backends.py文件),添加以下代码:
import ldap from django_auth_ldap.backend import LDAPBackend class NTLMLDAPBackend(LDAPBackend): def bind(self, connection): # 用NTLM协议绑定AD服务器 ntlm_username = self.settings.BIND_DN password = self.settings.BIND_PASSWORD # 调用python-ldap的NTLM绑定方法 connection.simple_bind_s(ntlm_username, password)
- 调整LDAP配置
修改你的settings.py里的LDAP相关配置,重点调整BIND_DN格式和认证后端:
import ldap from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, LDAPGroupQuery AUTH_LDAP_GLOBAL_OPTIONS = { ldap.OPT_X_TLS_REQUIRE_CERT: False, ldap.OPT_REFERRALS: False, ldap.OPT_PROTOCOL_VERSION: ldap.VERSION3, # 必须启用LDAPv3才能支持NTLM } # 注意:这里的BIND_DN要改成NTLM格式,比如 DOMAIN\sam_account_name 或者 user@domain.local # 不再使用LDAP的DN格式(CN=xxx,OU=xxx...) AUTH_LDAP_BIND_DN = "YOUR_DOMAIN\\your_bind_user" AUTH_LDAP_BIND_PASSWORD = credentials.adlogin['pass'] AUTH_LDAP_SERVER_URI = "ldap://x.x.x.x" # 以下配置保持不变 AUTH_LDAP_USER_SEARCH = LDAPSearch("OU=xxx,DC=xxx,DC=xxx,DC=coxxm", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)") AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=groups,dc=example,dc=com", ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)") AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() AUTH_LDAP_REQUIRE_GROUP = ( LDAPGroupQuery("CN=xx-xx,OU=xx,OU=xxx,,DC=xx,DC=xxx,DC=xx") | LDAPGroupQuery("CN=xx-xx,OU=xx,OU=xxx,,DC=xx,DC=xxx,DC=xx") ) AUTH_LDAP_USER_ATTR_MAP = { "first_name": "givenName", "last_name": "sn", "email": "mail" } SESSION_COOKIE_AGE = 15*60 # 替换为自定义的NTLM后端 AUTHENTICATION_BACKENDS = [ 'your_app_name.backends.NTLMLDAPBackend', # 替换成你实际的app路径 'django.contrib.auth.backends.ModelBackend', ]
关键注意事项
- BIND_DN格式:必须用
DOMAIN\sam_account_name或者user@domain.local的格式,不能再用原来的LDAP DN(比如CN=xxx...),因为NTLM认证是基于SAM账户名的。 - python-ldap依赖:确保你的python-ldap安装包支持NTLM。如果是用pip安装的,一般默认支持;如果是系统包,可能需要安装带NTLM支持的libldap开发库(比如Ubuntu的
libldap2-dev)。 - Kerberos的备选方案:Kerberos也能实现安全认证,但配置更复杂——需要和AD的KDC服务器同步时间、创建keytab文件,对于你的场景来说NTLM是更轻量的选择。
这样修改后,你的Django应用就能在389端口上安全地和AD做认证,不会明文传输密码了。
内容的提问来源于stack exchange,提问作者john_thats_me
相关产品推荐
相关产品推荐

