CentOS7下PHP7.0经SSL连接LDAP 636端口绑定失败问题咨询
环境基础
运行环境为CentOS 7 + PHP 7.0,已安装php-ldap扩展,安装与验证命令如下:
# yum install -y php php-ldap ... # php -m ... ldap ...
通过389端口非加密连接LDAP服务可正常运行,测试代码如下:
<?php $ldapconn = ldap_connect("dc.example.com", 389) or die("Could not connect to LDAP server."); if ($ldapconn) { $ldaprdn = 'username'; $ldappass = 'password'; $ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass); if ($ldapbind) { echo "LDAP bind successful..."; } else { echo "LDAP bind failed..."; } } $Result = ldap_search($ldapconn, "DC=example,DC=com", "(sAMAccountName=johndoe)"); $data = ldap_get_entries($ldapconn, $Result); print_r($data); ?>
上述代码可正常完成LDAP连接、绑定操作,能成功搜索到用户johndoe并返回其完整AD属性信息。
故障现象
切换为636端口SSL连接方式时,使用如下测试代码:
<?php putenv('LDAPTLS_REQCERT=require'); putenv('LDAPTLS_CACERT=/var/www/html/servercert.der'); // 临时存放路径 $ldapconn = ldap_connect("dc.example.com", 636) or die("Could not connect to LDAP server."); ldap_set_option($ldapconn, LDAP_OPT_DEBUG_LEVEL, 7); ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0); if ($ldapconn) { $ldaprdn = 'username'; $ldappass = 'password'; $ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass); if ($ldapbind) { echo "LDAP bind successful..."; } else { echo "LDAP bind failed..."; } } $Result = ldap_search($ldapconn, "DC=example,DC=com", "(sAMAccountName=johndoe)"); $data = ldap_get_entries($ldapconn, $Result); print_r($data); ?>
执行后返回如下错误:
Warning: ldap_bind(): Unable to bind to server: Can't contact LDAP server in /var/www/html/index.php on line 14 LDAP bind failed... Warning: ldap_search(): Search: Can't contact LDAP server in......
已完成前置验证:
- Windows AD服务器端已开放636端口,当前PHP Web服务器可正常连通该端口
- 服务器证书本身为有效状态
遗漏配置与修复方法
共有4处关键配置不符合LDAPS连接要求,按优先级修复即可:
- 缺少LDAPS协议前缀
PHP ldap扩展连接加密LDAP服务时,必须在地址前显式添加ldaps://前缀,仅指定域名+636端口不会触发SSL握手流程,客户端会直接向636端口发送明文LDAP请求,被服务端直接断开连接。
修复方式:将连接行修改为
$ldapconn = ldap_connect("ldaps://dc.example.com", 636);
- 证书格式不兼容
PHP ldap扩展底层依赖OpenLDAP库,该库默认仅识别PEM格式的证书,当前使用的DER格式证书无法被正常读取,会直接导致SSL证书校验失败。
修复方式:执行以下命令将DER证书转为PEM格式:
openssl x509 -inform DER -in /var/www/html/servercert.der -out /var/www/html/servercert.pem
随后将代码中LDAPTLS_CACERT对应的路径修改为转换后的pem文件路径。
- 证书文件权限不足
Web服务运行用户(通常为apache、nginx、www-data身份)需要对CA证书文件有读取权限,当前将证书放在Web根目录,如果默认权限配置过严,会导致OpenLDAP无法读取证书文件,握手失败。
修复方式:执行命令给证书添加全局读权限,更稳妥的方式是将证书移动到OpenLDAP默认证书目录/etc/openldap/certs/下,不要存放在Web根目录:
chmod 644 /var/www/html/servercert.pem
- 可选调试配置
如果完成上述修改后仍连接失败,可临时将LDAPTLS_REQCERT的值改为never关闭证书强校验,先确认SSL链路是否能正常连通,连通后再调回require排查证书域名匹配、证书链信任等问题。
修正后可正常运行的代码参考:
<?php putenv('LDAPTLS_REQCERT=require'); putenv('LDAPTLS_CACERT=/etc/openldap/certs/servercert.pem'); // 注意添加ldaps://前缀 $ldapconn = ldap_connect("ldaps://dc.example.com", 636) or die("Could not connect to LDAP server."); ldap_set_option($ldapconn, LDAP_OPT_DEBUG_LEVEL, 7); ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0); if ($ldapconn) { $ldaprdn = 'username'; $ldappass = 'password'; $ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass); if ($ldapbind) { echo "LDAP bind successful..."; } else { echo "LDAP bind failed..."; } } $Result = ldap_search($ldapconn, "DC=example,DC=com", "(sAMAccountName=johndoe)"); $data = ldap_get_entries($ldapconn, $Result); print_r($data); ?>
内容的提问来源于stack exchange,提问作者夏期劇場
相关产品推荐
相关产品推荐

