You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP 8.2连接LDAPS(Active Directory)失败,无法修改用户密码

问题描述

环境:VSCode、PHP 8.2、Wampserver
需求:修改Windows Active Directory的LDAP用户密码,服务器已启用LDAPS,可通过微软ldp工具用636端口正常连接,已导出证书但不知道怎么配置。

尝试过的代码片段:

$ldapConnect = ldap_connect("ldaps://10.1.1.1:389");
$ldapConnect = ldap_connect("10.1.1.1:636");
putenv('LDAPTLS_REQCERT=never');

最后尝试的完整代码:

$newPassword = "newPassword";
$ldapConnect = ldap_connect("ldaps://10.1.1.1:636");
ldap_set_option($ldapConnect, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapConnect, LDAP_OPT_REFERRALS, 0);
ldap_start_tls($ldapConnect);
$ldapbind = ldap_bind($ldapConnect, "DOMAIN\\admin", "AdminPassword");
$newPassword = '"' . $mdp . '"';
$newPassEncoded = iconv('UTF-8', 'UTF-16LE', $newPassword);
$userdata["unicodePwd"] = $newPassEncoded;
ldap_mod_replace($ldapConnect, "CN=name firstname,OU=YES,OU=Users,DC=DOMAIN,DC=COM", $userdata);

出现的错误:

Warning: ldap_start_tls(): Unable to start TLS: Can't contact LDAP server in C:\wamp64\www\dev\passwordchanger\Controllers\login.php on line 15

( ! ) Warning: ldap_bind(): Unable to bind to server: Can't contact LDAP server in C:\wamp64\www\dev\passwordchanger\Controllers\login.php on line 16

疑问:这是证书问题吗?该怎么解决?


解决方案

1. 先解决代码核心冲突:LDAPS连接别调用start_tls

ldaps://协议本身就是基于SSL的加密连接(默认636端口),而ldap_start_tls是给普通LDAP(389端口)升级加密用的,两者混用直接导致连接失败,删掉ldap_start_tls($ldapConnect);这一行即可。

2. 证书问题的两种处理方式

测试阶段:临时绕过证书验证(不建议生产用)

如果只是测试功能,不想折腾证书配置,在代码开头添加以下代码:

putenv('LDAPTLS_REQCERT=never');
// 或者用LDAP选项设置,效果一致
ldap_set_option($ldapConnect, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);

⚠️ 注意:生产环境禁用此方法,存在安全风险。

生产环境:配置信任AD证书

把你导出的AD证书(格式为.cer或.pem)放到WampServer的PHP SSL证书目录,比如C:\wamp64\bin\php\php8.2.x\extras\ssl\certs,然后打开php.ini文件找到[ldap]段落,添加或修改:

ldap.tls_cacert_file = "C:/wamp64/bin/php/php8.2.x/extras/ssl/certs/你的AD证书文件名.cer"

修改完成后重启WampServer的Apache服务生效。

3. 密码编码的注意事项

AD的unicodePwd字段有严格要求:密码必须用双引号包裹,且编码为UTF-16LE。确保代码中:

  • 变量$mdp已正确定义为新密码,避免未定义或空值
  • 编码代码正确:
$newPassword = '"' . $实际密码变量 . '"';
$newPassEncoded = iconv('UTF-8', 'UTF-16LE', $newPassword);

4. 绑定与连接的优化细节

  • 绑定用户可以使用UPN格式(如admin@DOMAIN.COM)替代DOMAIN\\admin,兼容性更好
  • 连接后先检查是否成功,再执行绑定操作,方便快速排查问题:
if (!$ldapConnect) {
    die("LDAP服务器连接失败");
}

修正后的完整代码示例

// 测试用:临时绕过证书验证
putenv('LDAPTLS_REQCERT=never');

$newPassword = "YourNewPass123!";
$ldapHost = "ldaps://10.1.1.1:636";
$bindUser = "DOMAIN\\admin"; // 或使用UPN格式:admin@DOMAIN.COM
$bindPass = "AdminPassword";
$userDn = "CN=name firstname,OU=YES,OU=Users,DC=DOMAIN,DC=COM";

// 建立LDAP连接
$ldapConnect = ldap_connect($ldapHost);
if (!$ldapConnect) {
    die("无法连接LDAP服务器");
}

// 设置LDAP必要参数
ldap_set_option($ldapConnect, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapConnect, LDAP_OPT_REFERRALS, 0);
// 生产环境请启用以下配置(需配合证书设置)
// ldap_set_option($ldapConnect, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_HARD);

// 绑定管理员账号
$ldapBind = ldap_bind($ldapConnect, $bindUser, $bindPass);
if (!$ldapBind) {
    die("绑定失败:" . ldap_error($ldapConnect));
}

// 处理密码编码
$encodedPassword = iconv('UTF-8', 'UTF-16LE', '"' . $newPassword . '"');
$userData = ["unicodePwd" => $encodedPassword];

// 修改用户密码
$result = ldap_mod_replace($ldapConnect, $userDn, $userData);
if ($result) {
    echo "密码修改成功";
} else {
    echo "密码修改失败:" . ldap_error($ldapConnect);
}

// 关闭LDAP连接
ldap_unbind($ldapConnect);

内容的提问来源于stack exchange,提问作者CalebDeCoteau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:17:09