Reputation: 21
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:
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}
Upvotes: 2
Views: 18339
Reputation: 123320
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, i.e. the difference you see is probably due to different client certificates used.
Upvotes: 1
Reputation: 3763
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
Upvotes: 3