Apache不会要求我的SSL客户端证书

首先请注意,我是configurationSSL的新手。 在过去,我一直很幸运有一个IT部门提前为我准备。 因此,请准备好我可能需要澄清一些答案的可能性。 =)

我正在尝试做什么

我正在为员工build立一个公司内部网站。 例如,将会有一个浏览器起始页面显示为每个员工定制的内容。 因此,我需要能够识别员工,而不需要任何用户名/密码或其他提示(一次性设置是好的,但我不希望他们每次都被提示)。 自然,SSL似乎是这样做的最好方式。

我将有一个MySQL数据库设置,将“用户”帐户与SSL_CLIENT_M_SERIAL和SSL_CLIENT_I_DN关联起来,我假设每个客户端证书(?)都是唯一的。 我从这篇文章中得到了这个想法: http : //cweiske.de/tagebuch/ssl-client-certificates.htm

用户第一次进入内部网站时,他们将没有证书(我不想为客户端手动生成它们),在这种情况下$ _SERVER [“SSL_CLIENT_VERIFY”] ==“NONE”。 如果发生这种情况,它将进入用户帐户设置页面,该页面将包含一个步骤,在该步骤中,PHP将生成一个SSL客户端证书并将其发送到浏览器供用户安装。 好而简单。 然后用户安装证书,build立关联,重新启动浏览器(为了好的措施),用户返回到内部网站。

此时,Apache应该请求浏览器发送的客户端证书。 然后,PHP脚本parsing必要的$ _SERVERvariables,与MySQL数据库进行比较,所有的时间都是好的。 再次,好,简单。

迄今为止工作到底是什么?

我有安装的服务器端证书。 是的,他们是自签名的(原因很明显)。 Apache已经安装了mod_ssl,所有这些似乎都正常工作。 我创build了一个只转储$ _SERVER数组的PHP脚本,所有的SSL_SERVER_ *键值都与我为它创build的证书相匹配。

问题

我无法获得客户端证书的工作! 在同样的PHP脚本中,无论我做什么,都会丢失SSL_CLIENT_VERIFY ==“NONE”和其他SSL_CLIENT_ *键。 如果我在ssl.conf中将SSLVerifyClient设置为可选项,会发生什么情况。 根据我读过的每个教程,他们都说Web服务器应该向浏览器请求客户端证书。 事情是,我无法做到这一点! 它只是直接到PHP脚本,并假设我根本没有客户端证书。 这发生在Firefox,Chrome和IE中。

所以我试着将SSLVerifyClient设置为required,然后重新启动webserver。 有了这个选项,我甚至不能build立SSL连接。 Firefox只是说连接已经重置(其他浏览器也显示他们自己的错误版本)。 奇怪的是,日志不显示这些连接尝试的任何活动! 即access_log,error_log,ssl_access_log,ssl_error_log和ssl_request_log都不显示ANYTHING ; 就好像这个尝试从来没有发生过。 这是令人沮丧的,因为这意味着我甚至没有任何错误信息。 只是一个Web服务器被动地积极告诉我去下地狱。

我尝试使用PHP的OpenSSL扩展手动生成/安装我自己的客户端证书。 证书安装得很好,但我找不到任何关于如何将该证书与服务器关联的信息(假设我甚至需要?)。 另外,它似乎并不重要,因为如果设置了可选项,Apache甚至不会请求客户端证书。 如果要求已经确定,那么只是不解释而已。 无论如何,我需要将其设置为可选,以便此架构能够正常工作。

环境

操作系统:CentOS 5.7 64位(VirtualBox)

Apache:2.2.3

PHP:5.3.10

我猜你可能需要更多的信息来帮助我,所以请问! 我会为你提供任何你需要的。

总结一下,我需要知道如何让Apache根据上述条件申请SSL客户端证书。 另外,如果为了使客户端证书与服务器证书“兼容”而需要执行任何特殊的签名/ etc(同样,不需要通过每个客户端证书的shell手动执行),我需要知道好。

截至目前,我已经100%地坚持下去了。 即使在Google上远程帮助也找不到任何内容。 任何帮助你可以提供这个将受到巨大的赞赏! 谢谢! =)

首先,您需要配置Apache Httpd来请求客户端证书。 为此,您至少需要在要用此方法进行身份验证的位置/目录上使用SSLVerifyClient optionalSSLVerifyClient optional

其次,客户端发送的证书也需要Apache Httpd的信任。 (原则上可以使用SSLVerifyClient optional_no_ca ,让任何客户端通过Apache Httpd SSL / TLS堆栈进行验证,然后才能在PHP中验证证书,但这是相当多的工作,对此您需要更加小心这不一定是简单的代码;更重要的是,在这种情况下,这是无用的,因为你处于一个控制你的CA的场景。)

据我所知, SSL_CLIENT_VERIFY (我没有使用太多的变量)似乎只对SSLVerifyClient optional_no_ca非常有用。 它可能与SSLVerifyClient optional工作,但我怀疑是这样的。 SSLVerifyClient require将使用不受信任的客户端证书(由SSLCACertificateFile / SSLCACertificatePath的一个CA)拒绝连接,或者如果没有证书。 据我所知, SSLVerifyClient optional将让客户端通过没有证书或信任的证书,但也将拒绝连接,如果证书不被信任。

在这里,通过拒绝连接,我的意思是突然关闭SSL / TLS连接的警报。 没有机会产生一个HTTP(S)错误页面。 所有你会在标准的浏览器错误,一些沿着ssl_error_unknown_certificate_... 。 (你应该考虑这个可用性。)

从那时起,你需要的是建立你自己的CA,可能是基于网络的浏览器中的密钥生成和在同一个网站内。 您不希望SSLVerifyClient require这样做,因为您需要让尚未拥有证书的用户(使用optional代替。 这就是说,这些指令不一定适用于整个主机,但可以是特定的某些位置/目录。

如果你是新手,集成你自己的基于网络的CA(或者更普遍的说,创建自己的CA)并不一定容易。 现成的工具(例如OpenCA )存在,或者您可以使用各种JavaScript / ActiveX构建您自己的工具,并且您需要服务器端代码来处理SPKAC或PKCS#10请求(并颁发实际的证书) 。 (为了使这样的CA有用,你需要申请新证书的用户在申请时提供一些证明,也许是一个密码。)

设置此设置时,应将SSLCACertificateFile (或...Path )配置为指向内部CA的CA证书(无论是否为基于Web的CA,在同一站点上)。 (当然,保持你的CA的私钥,也许配置在你的CA基于Web的应用程序中,但是Apache Httpd本身并不需要知道它。)浏览器将只建议由那些CA或中间体发布的证书(除非您还配置了SSLCADNRequestFile ,它将用于发送接受的CA列表)。

请注意,这两个步骤(设置您的CA并设置您的网站使用客户端证书)实际上是独立的。 两者都可以是同一个网站的一部分的事实可能是方便的,但并不是必须的。 您可以尝试设置Apache Httpd,而无需首先在网站上部署整个CA.(我建议,即使这只是为了看看你在做什么)。 有许多工具可以创建自己的小型CA,可以使用一些证书进行管理:例如OpenSSL的CA.pl或TinyCA 。 您也可以使用这些测试证书 ( localhosttestclient ,如果您想使用CRL,则可以撤消testclient_r ,可能不需要):所有密码都是testtest

正如您已经预料到的(使用您的MySQL数据库),您需要管理您颁发的证书并将其映射到用户。 SSL_CLIENT_M_SERIALSSL_CLIENT_I_DN不是正确的变量。 SSL_CLIENT_I_DN是颁发者DN(即CA的主题DN)。 您要查找的是SSL_CLIENT_S_DN :客户端证书主题DN。 SSL_CLIENT_M_SERIAL是证书序列号:不要使用它,因为它是每个证书唯一的:一个用户可以有多个具有相同主题DN的证书(例如,如果一个过期或被撤销)。


尽管如此,我不确定客户端证书是否是实现您的目标的最佳方式(让您公司的员工无需密码登录)。

  • 首先,用户应该用密码保护自己的证书。 你真正想要的是一种单点登录(SSO),我想。

  • 其次,根据用户的计算机文化程度,证书实际上可能很难管理。

    严格来说,“证书”一词根本不包括私钥,但有时隐含私钥的使用可能会让一些人感到困惑。 一方面,您有时会听到“将您的证书导入您的浏览器”和“使用您的证书登录”; 另一方面,你也可以听到“给我你的证书”。 前者意味着私钥的使用和可用性(在这些表达式中,“证书”可能只意味着.p12 )。 后者绝对不应该涉及私钥。

    浏览器用户界面对于管理证书或注销往往是相当差或混乱的。 同样,如果证书没有被识别,SSL / TLS连接将不会被建立,所以Web服务器没有机会显示任何类型的HTML错误页面。

也许你也可以考虑其他形式的SSO(例如CAS,基于SAML或Kerberos / SPNEGO)。

如果还没有完成,你可以看一下apache文档 。

一般的原则是你创建你的自签名证书并在尝试使用之前检查它。

然后,它看起来像客户端通过HTTP连接到您的Intranet网站。 从那里,有许多不同的方式切换到https使用您的SSL证书。 最简单的方法是使用Apache重写模块。 但在你的情况下,当你正在做php / mysql检查时,你可能会将你的客户端从http重定向到https,这不是简单的方法。

在任何一种情况下(通过mod_rewrite的apache自动重定向,或通过级联测试(php / javascript / html)重定向),您需要以正确的方式设置您的2个虚拟主机(一个用于http,一个用于https)一些假设。

例如(debian-apache 2.2),这里是一个由Apache完成的自动重定向(例如上面描述的第一种情况):

cat / etc / apache2 / sites-available / test

 # VHOST test <VirtualHost *:80> DocumentRoot /home/www/test serverName www.test.dev # ###################### # Redirect commons # ###################### RewriteEngine on # Case of vhosts RewriteOptions Inherit # ###################### # Redirect (empty index) # ###################### # Condition 1 to redirect : request matching with the server RewriteCond %{HTTP_HOST} ^www\.test\.dev [NC] # Condition 2 to redirect : non empty HOST RewriteCond %{HTTP_HOST} !^$ # Automatic Empty requests Redirect RewriteRule ^(.*)/$ /index.php # ###################### # Redirect to SSL # ###################### RewriteCond %{HTTP_HOST} ^www\.test\.dev [NC] RewriteCond %{HTTP_HOST} !^$ RewriteCond %{SERVER_PORT} ^80$ RewriteCond %{REQUEST_URI} / # Redirection RewriteRule ^/(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R] </VirtualHost> 

SSL的第二个虚拟主机:cat / etc / apache2 / sites-available / test-ssl

 # VHOST for ssl 

 DocumentRoot "/home/www/test" serverName www.test.dev # SSL SSLEngine on SSLCACertificateFile /etc/apache2/ssl/cur_cert/ca.pem SSLCertificateFile /etc/apache2/ssl/cur_cert/serveur.pem SSLCertificateKeyFile /etc/apache2/ssl/cur_cert/serveur.key <Directory "/home/www/test"> Options FollowSymLinks MultiViews AllowOverride None Order allow,deny Allow from 127.0.0.1 192.168.0.0/16 </Directory> <Directory "/home/www/test/cgi-bin"> Options FollowSymLinks MultiViews AllowOverride None Order allow,deny Allow from 127.0.0.1 192.168.0.0/16 Options +ExecCGI AddHandler cgi-script .cgi </Directory> </VirtualHost> 

你的情况可能会稍微延迟,例如你不会在第一个虚拟主机中有重定向部分,但是只有一个简单的虚拟主机,第二个是https(ssl)。 一旦你完成了你的mysql检查,重定向将由php / javascript完成。

下面是一个PHP类的示例摘要,用于将http切换到https,使用php,然后是javascript,然后是html:

 public function Redirect($url){ if (TRUE !== Validator::isValidURL($url)) die ("FATAL ERR: url not valid"); // PHP ABSOLUTE URL REDIRECT (HTTP1.1) if (!headers_sent()) { header("Status: 200"); header("Cache-Control: no-cache, must-revalidate"); // required for HTTP/1.1 header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // past Date header("Pragma: no-cache"); header('Location: '.$url); // note: 302 code return by default with "Location" flush(); exit(); // if headers are already sent... do javascript redirect... if javascript is disabled, do html redirect. } else { // Js redirect echo '<script type="text/javascript">'; //echo "<!--"; echo 'document.location="'. $url .'";'; //echo "//-->"; echo '</script>'; // HTML redirect if js disabled echo '<noscript>'; echo '<meta http-equiv="refresh" content="0;url="'.$url.'" />'; echo '</noscript>'; exit(); } return FALSE; } /* end of method (redirect) */ 

希望它能帮助你更好地理解如何进行和适应你的具体情况。

我有一个类似的问题:

  • CentOS 6.3
  • Apache 2.2.15

经过一些尝试,我认识到我的问题。

如果我将SSLVerifyClient optional设置SSLVerifyClient optionalSSLVerifyClient optional_no_ca并且还指定了SSLCACertificateFileSSLCACertificatePath ,则只有在从配置中指定的CA参考文件/路径中找到的CA释放的情况下,Apache才会获取客户端证书。