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

时间:2012-04-20 19:35:18

标签: php linux apache ssl openssl

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

我正在尝试做什么

我正在为员工建立公司内部网网站。例如,将有一个浏览器起始页面,显示为每个员工定制的内容。因此,我需要能够识别所述员工而无需任何用户名/密码或其他提示(虽然一次性设置是可以的;我只是不希望每次都提示他们)。当然,SSL似乎是实现这一目标的最佳方式。

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

用户第一次访问内部网站时,他们没有证书(我不想为客户手动生成证书!),在这种情况下$ _SERVER [“SSL_CLIENT_VERIFY”] ==“无”。如果发生这种情况,它将转到用户帐户设置页面,其中包括PHP生成SSL客户端证书并将其发送到浏览器以供用户安装的步骤。很好,很简单。然后,用户安装证书,建立关联,并在重新启动浏览器后(为了更好地衡量),用户返回内部网站。

此时,Apache应该请求客户端证书,然后浏览器会发送该证书。 PHP脚本然后解析必要的$ _SERVER变量,与MySQL数据库进行比较,并且所有人都有好的时间。再次,美好而简单。

到目前为止工作

我安装了服务器端证书。是的,他们是自签名的(出于显而易见的原因)。 Apache安装了mod_ssl,所有这些似乎都运行正常。我创建了一个只转储$ _SERVER数组的PHP脚本,所有的SSL_SERVER_ *键值都与我为它创建的证书相匹配。

问题

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

所以我尝试将SSLVerifyClient设置为必需并重新启动网络服务器。有了这个选项,我甚至无法建立SSL连接。 Firefox只是说连接已经重置(其他浏览器也会显示自己的错误版本)。奇怪的是,日志在这些连接尝试中没有显示任何活动!即access_log,error_log,ssl_access_log,ssl_error_log和ssl_request_log都不显示 ANYTHING ;就好像这次尝试从未发生过一样。这令人沮丧,因为这意味着我甚至没有可以使用的错误消息。只是一个网络服务器被动 - 积极地告诉我下地狱。

我尝试使用PHP的OpenSSL扩展手动生成/安装我自己的客户端证书。证书安装得很好,虽然我找不到任何关于如何将该证书与服务器关联的信息(假设我甚至需要?)。此外,它似乎无关紧要,因为如果设置了可选项,Apache仍然不会请求客户端证书。如果设置了需求,它只是在没有解释的情况下爆炸。无论如何我都需要将它设置为可选,以使该模式起作用。

环境

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

Apache:2.2.3

PHP:5.3.10

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

总而言之,我需要知道如何在给定上述条件的情况下让Apache请求SSL客户端证书。此外,如果有任何特殊的签名/等必须要使客户端证书与服务器证书“兼容”(再次,没有通过shell为每个客户端证书手动执行!),我将需要知道好。

到目前为止,我100%坚持这一点。在Google上找不到任何远程帮助。您可以提供的任何帮助将是非常感谢!!谢谢! =)

3 个答案:

答案 0 :(得分:4)

首先,您需要配置Apache Httpd以请求客户端证书。为此,您至少需要在要使用此方法进行身份验证的位置/目录上使用SSLVerifyClient 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,可能是基于Web的浏览器密钥生成,并且位于同一网站内。您不会想要SSLVerifyClient require,因为您需要让尚未拥有证书的用户(使用optional代替)。话虽如此,这些指令不一定适用于整个主机,但可以特定于某些位置/目录。

如果您对所有这些CA不熟悉,那么集成您自己的基于Web的CA(或更一般地说,创建您自己的CA)并不一定容易。存在现成的工具(例如OpenCA),或者您可以使用JavaScript/ActiveX的各种位构建自己的工具,并且您需要服务器端代码来处理SPKAC或PKCS#10请求(和发出实际证书)。 (为了使这样的CA有用,您希望申请新证书的用户在申请时提供一些ID证明,也许是密码。)

设置完成后,您应该将SSLCACertificateFile(或...Path)配置为指向内部CA的CA证书(无论是否是基于Web的CA,是否相同的网站)。 (当然,保持您的CA的私钥是私有的,可能在您的CA基于Web的应用程序中配置,但Apache Httpd本身并不需要知道它。)浏览器只会建议由这些CA或中间体颁发的证书。 (除非您还配置了SSLCADNRequestFile,否则将用于发送已接受的CA列表。

请注意,这两个步骤(设置CA并设置网站以使用客户端证书)实际上是独立的。两者都可以是同一站点的一部分这一事实可能很方便,但并非必要。您可以先尝试Apache Httpd设置,而无需首先在网站上部署整个CA(我建议您这样做,即使只是为了了解您正在进入的内容)。有许多工具可以创建您自己的小CA,可以使用少量证书进行管理:例如OpenSSL's CA.plTinyCA。您还可以使用这些test certificateslocalhosttestclienttestclient_r如果您想使用CRL,则可能会被撤销,可能一开始不需要):所有密码都是{{ 1}}。

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


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

  • 首先,用户应该使用密码保护自己的证书。你想要的是某种形式的单点登录(SSO),我猜。

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

    严格来说," certificate"这个词根本不包含私钥,但有时暗示使用私钥可能会让一些人感到困惑。一方面,您有时会听到"将您的证书导入浏览器"和"使用您的证书登录&#34 ;;另一方面,您也可以听到"向我发送您的证书"。前者意味着私钥的使用和可用性("证书"在这些表达式中可能只是SSL_CLIENT_M_SERIAL)。后者绝对不应该涉及私钥。

    浏览器用户界面往往很差或者难以管理证书或注销。同样,如果证书未被识别,则不会建立SSL / TLS连接,因此Web服务器没有机会显示任何类型的HTML错误页面。

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

答案 1 :(得分:0)

如果没有完成,您可以查看apache doc

一般原则是您创建自签名证书并在尝试使用之前进行检查。

然后看起来客户端通过http连接到您的Intranet站点。从那里,有许多不同的方法可以使用您的ssl证书切换到https。最简单的方法是使用apache重写模块。但在您的情况下,当您进行php / mysql检查时,您可以将客户端从http重定向到https,这不是简单的方法。

在任何两种情况下(apache通过mod_rewrite自动重定向,或通过级联测试重定向(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) */

希望它能帮助您更好地了解如何继续并根据您的具体情况调整此方法。

答案 2 :(得分:0)

我遇到了类似的问题:

  • CentOS 6.3
  • Apache 2.2.15

经过一些尝试,我认出了我的问题。

如果我设置了SSLVerifyClient optionalSSLVerifyClient optional_no_ca并且我还指定了SSLCACertificateFileSSLCACertificatePath,那么只有在CA参考文件中找到的CA发布后,Apache才会获取客户端证书/ path在配置中指定。