用php实现mtls

问题描述 投票:0回答:1

我想在虚拟 php 网页上实现从访客到我的 Openldap 服务器的 mTLS。 我有问题,即使我相应地指定了选项,我的 php 似乎也从未将客户端证书发送到我的服务器。我的客户访客上有

php 8.2
,我的
slapd
openldap server
版本位于
2.5.13
版本中。

我在我的服务器上启用了 TLS 并强制执行双向 TLS (mTLS):

olcTLSCACertificateFile: /etc/ldap/certs/issuing_ca.crt
olcTLSCertificateFile: /etc/ldap/certs/ldap.test.local.crt
olcTLSCertificateKeyFile: /etc/ldap/certs/ldap.test.local.key
olcTLSVerifyClient: demand

我可以使用来自客户来宾的客户端证书成功连接 csh 中的 ldapsearch,因此它们是正确且有效的:

setenv LDAPTLS_CACERT /var/run/certs/f03dd1db.crt
setenv LDAPTLS_CERT /var/run/certs/229c13f4.crt
setenv LDAPTLS_KEY /var/run/certs/229c13f4.key
ldapsearch -H ldaps://ldap.domain.local -b "dc=domain,dc=local" -D "uid=ldap_srv,ou=users,dc=domain,dc=local" -W -d 256 -x -LLL

但是我无法让它与我的 php 一起工作:

function simple_test(){
    $ldapUri = 'ldaps://ldap.domain.local:636';
    $caFile = '/var/run/certs/f03dd1db.crt';
    $certFile = '/var/run/certs/229c13f4.crt';
    $keyFile = '/var/run/certs/229c13f4.key';
    $ldapbindun = 'uid=ldap_srv,ou=users,dc=domain,dc=local';
    $ldapbindpw = 'password';

    $ldapOptions = [
        LDAP_OPT_X_TLS_CACERTFILE => $caFile,
        LDAP_OPT_X_TLS_CERTFILE => $certFile,
        LDAP_OPT_X_TLS_KEYFILE => $keyFile,
        LDAP_OPT_PROTOCOL_VERSION => 3,
        LDAP_OPT_REFERRALS => 0,
    ];
    //set global options
    foreach($ldapOptions as $k => $v) {
        ldap_set_option(null, $k, $v);
    }
    
    $error = false;
    // initial connection seems to work and return success:
    if (!($ldapResource = ldap_connect($ldapserver))) {
        $error = true;
    }
    // Also tried to set options here especially for $ldap without luck also :
    //ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, "/var/run/certs/229c13f4.crt");
    //ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE, "/var/run/certs/229c13f4.key");
    //try to bind and check for errors (that I have):
    //Same error if I switch to ldap_bind($ldapResource)
    if (!($res = ldap_bind($ldapResource, $ldapbindun, $ldapbindpw))) {
        $error = true;
    }

    if ($error == true) {
        ldap_get_option($ldapResource, LDAP_OPT_DIAGNOSTIC_MESSAGE, $errMsg);
        log_error(sprintf(gettext("%s (%d): %s\n"),ldap_error($ldapResource), ldap_errno($ldapResource),$errMsg));
        @ldap_close($ldapResource);
    }
}

客户端日志显示:

LDAP bind failed: Can't contact LDAP server (-1):

服务器日志向我展示:

 slap_listener_activate(8):
 >>> slap_listener(ldaps:///)
 conn=1022 fd=14 ACCEPT from IP=<MY_CLIENT_IP>:32896 (IP=0.0.0.0:636)
 connection_get(14): got connid=1022
 connection_read(14): checking for input on id=1022
 connection_get(14): got connid=1022
 connection_read(14): checking for input on id=1022
 TLS: can't accept: Certificate is required..
 connection_read(14): TLS accept failure error=-1 id=1022, closing
 connection_close: conn=1022 sd=14
 conn=1022 fd=14 closed (TLS negotiation failure)

但是,当我在绑定之前打印 $ldap 选项时,似乎一切都是正确的:

Option LDAP_OPT_DEREF: 'LDAP_DEREF_SEARCHING (Searching)'
Option LDAP_OPT_SIZELIMIT: 0
Option LDAP_OPT_TIMELIMIT: 25
Option LDAP_OPT_NETWORK_TIMEOUT: 25
Option LDAP_OPT_PROTOCOL_VERSION: '3 (LDAPv3)'
Option LDAP_OPT_ERROR_NUMBER: -1
Option LDAP_OPT_ERROR_STRING: Unable to retrieve value
Option LDAP_OPT_REFERRALS: '0 (Disable)'
Option LDAP_OPT_RESTART: '0 (Disable)'
Option LDAP_OPT_HOST_NAME: 'ldap.domain.local:636'
Option LDAP_OPT_MATCHED_DN: Unable to retrieve value
Option LDAP_OPT_SERVER_CONTROLS: Unable to retrieve value
Option LDAP_OPT_CLIENT_CONTROLS: Unable to retrieve value
Option LDAP_OPT_X_KEEPALIVE_IDLE: 0
Option LDAP_OPT_X_KEEPALIVE_PROBES: 0
Option LDAP_OPT_X_KEEPALIVE_INTERVAL: 0
Option LDAP_OPT_X_TLS_CACERTDIR: '/var/run/certs'
Option LDAP_OPT_X_TLS_CACERTFILE: '/var/run/certs/f03dd1db.crt'
Option LDAP_OPT_X_TLS_CERTFILE: '/var/run/certs/229c13f4.crt'
Option LDAP_OPT_X_TLS_CIPHER_SUITE: Unable to retrieve value
Option LDAP_OPT_X_TLS_CRLCHECK: 'LDAP_OPT_X_TLS_CRL_NONE (No CRL Checking)'
Option LDAP_OPT_X_TLS_CRLFILE: Unable to retrieve value
Option LDAP_OPT_X_TLS_DHFILE: Unable to retrieve value
Option LDAP_OPT_X_TLS_KEYFILE: '/var/run/certs/229c13f4.key'
Option LDAP_OPT_X_TLS_PACKAGE: 'OpenSSL'
Option LDAP_OPT_X_TLS_PROTOCOL_MIN: 'LDAP_OPT_X_TLS_PROTOCOL_SSL2 (SSLv2)'
Option LDAP_OPT_X_TLS_REQUIRE_CERT: 'LDAP_OPT_X_TLS_HARD (Hard)'
Option LDAP_OPT_X_TLS_RANDOM_FILE: Unable to retrieve value

但不知何故,我的 php 显然做错了什么。如果我相信 来自 php 手册的用户评论,或者 来自 github php 项目的评论,它应该可以工作。我看不出这里有什么问题。

编辑

随着我的测试的进行,事情变得非常奇怪。

通过调用与

test.php
完全相同的
root
文件并从 cli 调用为
env -i php -c /usr/local/etc/php.ini -d scan.dir=/usr/local/etc/php /usr/local/www/test.php
成功,证书已发送,绑定成功。

通过从我的网络服务器(

nginx/1.24.0
)到达这个完全相同的文件,它失败了。 我的日志很清楚:

  • CA 文件(它是一条链)已设置
    /var/run/certs/f03dd1db.0
  • 证书文件设置为
    /var/run/certs/229c13f4.crt
  • 密钥文件设置为
    /var/run/certs/229c13f4.key

这两种情况下的所有这三个文件都可以正确读取(并从我的

debug.log
写到我的
test.php

ldap_connect
似乎在两种情况下都可以工作,但是
ldap_bind
仅在cli
env -i php -c /usr/local/etc/php.ini -d scan.dir=/usr/local/etc/php /usr/local/www/test.php
中调用时才起作用,但从我的nginx网络服务器访问时则不起作用。

要与 cli 中的 nginx 环境一样接近(通过从

phpinfo()
调用
test.php
获取信息,并在从 nginx 到达时检查值):

  • 我用
    env -i <command>
  • 清除我的环境
  • 我设置了完全相同的加载配置文件
    -c /usr/local/etc/php.ini
  • 我还扫描此目录以获取其他 .ini 文件
    -d scan.dir=/usr/local/etc/php

仍然在 cli 中工作,而不是从我的网络服务器中工作。

编辑2

为了获取信息,我使用

Nginx + PHP-FPM
。 这是我非常简单的 nginx 配置:

#
# nginx configuration file

user  root wheel;
error_log /var/log/nginx/error.log;

events {
    worker_connections  1024;
}

http {
        include       /usr/local/etc/nginx/mime.types;
        default_type  application/octet-stream;
        access_log /var/log/nginx/access.log;

        server {
                listen 80;
                listen [::]:80;
                root "/usr/local/www/";

                location ~ \.php$ {
                        fastcgi_pass   unix:/var/run/php-fpm.socket;
                        fastcgi_index  index.php;
                        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                        fastcgi_param  HTTP_PROXY  "";
                        fastcgi_read_timeout 180;
                        include        /usr/local/etc/nginx/fastcgi_params_dummy;
                }

        }
}

我的 fastcgi_params_dummy 是这样的:

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

我尝试通过添加这些行来对值进行硬编码,但它并没有改变结果。

fastcgi_param  LDAPTLS_CERT       /var/run/certs/229c13f4.crt;
fastcgi_param  LDAPTLS_KEY        /var/run/certs/229c13f4.key;
fastcgi_param  LDAPTLS_CACERT     /var/run/certs/f03dd1db.0;
php ldap openldap mtls
1个回答
0
投票

对于运行 Nginx + PHP-FPM 的用户: 解决方案是重新启动 php-fpm 使其工作:

/bin/pkill -F /var/run/php-fpm.pid
随后是
/usr/local/sbin/php-fpm -c /usr/local/etc/php.ini -y /usr/local/lib/php-fpm.conf -RD 2>&1 >/dev/null

© www.soinside.com 2019 - 2024. All rights reserved.