SSL 双向认证的配置

本文介绍如何在Apache 2上配置SSL双向认证,并且用于保护服务器中特定的目录

0.双向认证的介绍

单向认证就是说,只有客户端使用ssl时对服务器端的证书进行认证,也就是说,客户端在请求建立之前,服务器端会向客户端发送一个证书,一般情况下,这种证书都是由自己或企业自行发布的,所以在客户端使用https时,会跳出“是否信任并继续”,点击信任则表示客户端信任服务器端证书,才可以继续交互。
双向认证,就是服务器端和客户端都对双方的证书进行认证,这时除了单向认证外,还需要在服务器端的受信任证书列表中加入客户端的证书,这样服务器端才能信任客户端的请求。

1.SSL证书的创建

服务器证书和客户端的证书可以分开生成,通常服务器证书需要CA机构签发。客户端认证的证书最好自行生成。这里使用xca工具进行证书的生成与签名完成SSL双向认证的配置。如果使用自行签发的服务器证书浏览器将会生成根证书不受信任的的警告。在Chrome下HTTPS上会有一个红色的斜线。免费的服务器证书可以参见Let‘s Encrypt

1.1. 服务器证书的创建

服务器证书的创建最好根据CA提供的相关文档,这里仅介绍如何生成CSR(证书请求)。
方法一(适用于openssl):
[codesyntax lang=”bash”]

openssl req -new -sha256 -newkey rsa:2048 -nodes -keyout server.key -out server.csr

[/codesyntax]
方法二:在线生成
方法三:使用xca

1.2. 客户端证书的创建

使用xca:
第一步创建客户端的根证书:
Certification>New Certification
签名算法(Signature Algorithm):SHA256
在签名(Signing)中选择:创建自签名证书(Create a self signed certificate with serial)
在证书内容选项卡(Subject):填写证书的信息,注意Country为两位字母
在下方Private Key中,点击Generate a new key,生成一个私钥
在扩展选项卡(Extension)中:类型(Type)选择Certification Authority
证书有效期(Validity):选择好起始时间
Key usage:在左侧选择 Certificate Sign和CRL Sign
Netscape:选择 SSL CA,S/MIME CA,Object Signing CA
全部完成后OK退出
第二步(可选),创建客户端前面中间证书,可以不要这步,直接用根证书对客户端证书签名:
大致步骤同第一步,Signing中选择Using this Certification for signing,选择框中选择刚刚生成的证书Internal Name。
第三步,创建客户端证书:
Certification>New Certification
签名算法(Signature Algorithm):SHA256
在签名(Signing)中选择:Using this Certification for signing,选择第一步的根证书或中间证书。
证书模板(Template for the new certification):[default] HTTPS_client 并点击Apply All。
在证书内容选项卡(Subject):填写证书的信息。
在下方Private Key中,点击Generate a new key,生成一个私钥。
在Key Usage右边的列表中选择需要的扩展属性。建议选上TLS Web Client Authentication
点击OK生成证书。

2.证书导出与安装

2.1. 证书的导出

第一步:导出为客户端签名的根证书:
在Certificate列表中选择为客户端证书签名的证书,单击Export。导出类型(Export Format)选择:PEM(*.crt)
如果有中间证书请重复以上步骤,导出中间证书。
将导出的根证书上传至服务器。
第二步:导出客户端证书
在Certificate列表中选择需要导出的证书,单击Export。导出类型(Export Format)选择:PKCS #12(*.p12),需要输入私钥的保护密码。

2.2. 证书的安装

2.2.1. 服务器端的安装

这里的安装根据Apache2+Ubuntu Server 14.04进行配置,其他系统文件位置可能不同
[codesyntax lang=”bash”]

vi /etc/apache2/sites-available/ssl.conf

[/codesyntax]
在Directory节中,开启AllowOverride:
[codesyntax lang=”apache”]

<Directory /path/to/directory>
        Options FollowSymLinks
        AllowOverride All
        Require all granted
</Directory>

[/codesyntax]
去除以下注释,并修改相关文件路径。
[codesyntax lang=”apache”]

SSLEngine on
SSLCertificateFile   /path/to/server_certification
SSLCertificateKeyFile /path/to/server_private_key
SSLCertificateChainFile /path/to/ca_chain
SSLCACertificateFile /path/to/client_ca
SSLVerifyClient none
SSLVerifyDepth  10

[/codesyntax]
其中/path/to/server_certification替换为CA颁发的证书文件名。
/path/to/server_private_key替换为服务器的私钥,在生成csr时同时产生,以.key结尾。
/path/to/ca_chain替换为证书链(ca-bundle),这个文件由ca提供
/path/to/client_ca替换为指向自己生成的客户端CA根。
开启SSL配置并重启apache
[codesyntax lang=”bash”]

a2ensite ssl
service apache2 restart

[/codesyntax]

2.2.2. 客户端证书安装

先安装CA根,直接双击crt,将证书安装至可信的根证书颁发机构。
如果有中间证书将证书安装至中间证书颁发机构。
双击导出的p12文件,将证书安装至个人

3. SSL保护目录

在需要SSL验证的目录下创建以下内容的.htaccess
[codesyntax lang=”apache”]

SSLVerifyClient require

[/codesyntax]
注意:如果需要使用SSL来限制wordpress控制面板的访问,除了在wp-admin目录下放置.htaccess,还需要在下面这些目录中放置.htaccess来确保登录界面显示正常。

  • wp-admin/images/
  • wp-admin/css/

这里的.htaccess 用于关闭SSL的验证
[codesyntax lang=”apache”]

SSLVerifyClient none

[/codesyntax]

4. SSL双向认证时 PHP变量

服务器配置中需要打开设置
[codesyntax lang=”apache”]

<FilesMatch "\.(cgi|shtml|phtml|php)$">
 SSLOptions +StdEnvVars
 </FilesMatch>

[/codesyntax]
在这之后$_SERVER变量中就会包含SSL证书的信息
使用

[codesyntax lang=”php” blockstate=”expanded”]

<?php
var_dump($_SERVER);
?>

[/codesyntax]