简体   繁体   中英

How do I obtain SSL_CLIENT_* variables from the SSL client certificate using PHP 5.6 running on Apache 2.4?

Introduction

I'm using PHP 5.6 and Apache 2.4 in the back-end of my web site where I use SSL to authenticate clients as an optional form of entering the site. I want to get some SSL_CLIENT_* variables which are contained in the certificate but aren't being shown by Apache 2.4, therefore, I cannot access them using $_SERVER .

Description

I want to get the following environment variables from the client certificate:

  • SSL_CLIENT_S_DN_CN
  • SSL_CLIENT_SAN_OTHER_msUPN_0
  • SSL_CLIENT_SAN_Email_0

When I dump $_SERVER in PHP 5.6 I can see what is returned by the variable SSL_CLIENT_VERIFY . If it returns GENEROUS , all three variables are shown; if it is SUCCESS only the first on the list above, SSL_CLIENT_S_DN_CN , is shown; and, if SSL_CLIENT_VERIFY is NONE , there is no certificate supplied by the client.

I used XAMPP v3.2.2 on Windows 10 (Apache 2.4 and PHP 7.0) locally and I can access all the variables, but, somehow, I cannot do the same using a remote Debian 9 server running Apache 2.4 and PHP 5.6.

I tried unsuccessfully to set up the SSLRequire (which is deprecated according to the docs - mod_ssl) option and Require as well.

I resorted to StackOverflow and ServerFault search for similar questions, involving SSL client certificates, but all the questions I came across involve SSL basic configuration (HTTP to HTTPS, Proxy, etc.) and creating headers with existing environment variables, like SSLRequire that works this way, for what I understood by reading the docs.

In the default-ssl.conf I tried to set the headers using the variables, but when I do the following:

print_r(getallheaders());

PHP 5.6 returns NULL :

Array ( [...] [SSL_CLIENT_SAN_OTHER_msUPN_0] => (null) [SSL_CLIENT_SAN_Email_0] => (null) )

The question again is how to get the variables SSL_CLIENT_SAN_OTHER_msUPN_0 and SSL_CLIENT_SAN_Email_0 from the client certificate.

Attachments

1. My Apache 2.4 SSL configuration file:

default-ssl.conf

<VirtualHost *:443>
    ServerName myserver.name #Omitted
    RequestHeader set SSL_CLIENT_SAN_OTHER_msUPN_0 "%{SSL_CLIENT_SAN_OTHER_msUPN_0}s"
    RequestHeader set SSL_CLIENT_SAN_Email_0 "%{SSL_CLIENT_SAN_Email_0}s"
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
    # Configuracoes de cache    
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Note "Cache desabilitado no servidor/host"

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    # Configuracao do SSL
    SSLEngine on
    # [...] Certificados AC e certificados da aplicacao: OMITTED
    SSLOptions +StdEnvVars +OptRenegotiate -StrictRequire +FakeBasicAuth -ExportCertData  
    # Solicita certificado SSL/TLS do cliente            
    SSLVerifyClient optional_no_ca 
    SSLVerifyDepth 3

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
        SSLOptions +OptRenegotiate -ExportCertData -StrictRequire +FakeBasicAuth +StdEnvVars
    </FilesMatch>
    <Directory /usr/lib/cgi-bin>
        SSLOptions +StdEnvVars
    </Directory>
    BrowserMatch "MSIE [2-6]" \
                 nokeepalive ssl-unclean-shutdown \
                 downgrade-1.0 force-response-1.0
    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</VirtualHost>

2. PHP 5.6 file

index.php

<?php //index.php

// Get client certificate data
$cn = $_SERVER['SSL_CLIENT_S_DN_CN'];
$email = $_SERVER['SSL_CLIENT_SAN_Email_0'];
$id = $_SERVER['SSL_CLIENT_SAN_OTHER_msUPN_0'];

$client_certificate_data = [
    'cn' => $cn,
    'email' => $email,
    'id' => $id
];

echo json_encode(
    $client_certificate_data,
    JSON_NUMERIC_CHECK
);

// Output: {"cn":"EXAMPLE CN CONTENT HERE","email":null,"id":null}

The Apache directive SSLOptions +StdEnvVars passes the SSL information as environment variables to Php. See these links for more information:

Using SSL Client Certificates with PHP and SSLOptions Directive

If SSL_CLIENT_VERIFY is set to NONE it means no certificate was sent by the client. In this case of course no information about a client certificate can be provided.

In all other cases you should get SSL_CLIENT_S_DN_CN . SSL_CLIENT_SAN_* you get only if the client certificate contains SAN entries, ie the difference you see is probably due to different client certificates used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM