常见的https站点都是客户端用服务端提供的证书验证服务端的签名,确认自己访问的站点不是伪造的。同样的,服务端也可以添加客户端提供的公钥证书,用来验证客户端的身份。流程同上,客户端用私钥签名后,服务端用客户端的公钥证书验签。
下面我用tomcat-8.5.64来演示一下如何配置基于tomcat的自签名证书的https双向认证。
生成服务器端和客户端的密钥对
首先生成两个密钥对,一个给服务端使用(也就是tomcat),一个给客户端使用(也就是浏览器端)。我们用JDK提供的keytool工具来生成密钥对。
>keytool -genkeypair -alias server -keyalg RSA -validity 365 -storetype PKCS12 -keystore tomcat-key.p12 -storepass 123456 -dname "CN=tomcat-site.com,OU=tomcat,O=mytomcat,L=chengdu,S=sichuan,C=CN"
用同样的方式再生成客户端的密钥对。
>keytool -genkeypair -alias client -keyalg RSA -validity 365 -storetype PKCS12 -keystore client-key.p12 -storepass 123456 -dname "CN=client-site.com,OU=my,O=myclient,L=chengdu,S=sichuan,C=CN"
从客户端的密钥库中导出公钥证书,把这个证书提供给服务端,服务端需要将它添加到自己的信任证书库中。
>keytool -exportcert -alias client -file client.cert -keystore client-key.p12 -storepass 123456
执行上一条命令得到客户端证书文件client.cert。为了方便tomcat的配置,直接将这个证书导入一个空的密钥库。
>keytool -importcert -alias client -file client.cert -keystore server-trust.p12 -storetype PKCS12 -storepass 123456
配置tomcat
将服务端密钥库和信任密钥库考到tomcat的conf目录中,这个不是必须的,复制过去只是为了方便配置和管理,也可以在tomcat中配置这两个密钥库的绝对路径。
tomcat默认是没有开启https的,我们在conf目录里面找到server.xml并用文本编辑器打开它。找到被注释掉的SSL/TLS HTTP/1.1 Connector,如下图所示:
取消这个connector的注释。将服务端密钥库配置在Certificate节点中。
<Certificate certificateKeystoreFile="conf/tomcat-key.p12"
certificateKeystorePassword="123456"
type="RSA" />
certificateKeystoreFile配置的就是密钥库的位置,由于我们把它拷贝到了conf目录中,所以我们只需配置它的相对路径就可以了。certificateKeystorePassword指定密钥库的密码。type指定密钥库的类型。我们生成的时候指定的类型是RSA,所以这里也配置为RSA就可以了。这样配置好以后,单向的https就成功了,我们可以启动tomcat试一试。在浏览器中输入https://localhost:8443
。
看到的结果如上图所示,因为我们使用的是自签名的密钥库,所以不受浏览器的信任,我们点击“高级”:
然后点击“继续前往localhost(不安全)”:
打开了tomcat的管理页面。左上角有个“不安全”的提示,提示这个的原因同上,我们的服务端密钥库是自签名的,响应给浏览器的证书也是自签名的,不受浏览器信任。
接着我们继续配置双向的https。单向是服务端向客户端提供自己的证书,客户端用此证书验证服务端的身份,双向的话就是还需要客户端向服务端提供证书,服务端用这个证书来验证客户端的身份。服务端这边的话就只需要把我们刚才生成的第三个密钥库(导入了客户端证书的那个)配置到tomcat中。这个需要配置到SSLHostConfig节点上。完整的connector的配置如下:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig truststoreFile="conf/server-trust.p12" truststorePassword="123456" certificateVerification="required">
<Certificate certificateKeystoreFile="conf/tomcat-key.p12"
certificateKeystorePassword="123456"
type="RSA" />
</SSLHostConfig>
</Connector>
truststoreFile就是配置的客户端证书所在的密钥库,truststorePassword配置的是该密钥库的密码,而certificateVerification配置为"required"表示必须进行客户端身份验证。配置完毕后我们重新启动tomcat,然后尝试访问它。得到如下图所示的页面:
这是因为客户端密钥库还没有配置导致的。客户端用密钥库中的私钥签名后,服务端才能用我们刚才配置的受信任密钥库中的客户端证书进行验证。我使用的是chrome浏览器,打开浏览器的“设置”页面,点击左侧的“隐私设置和安全性”菜单,
然后点击上图红框中的“安全”,进入如下图所示页面:
往下滚动页面,找到“管理证书”:
点击右侧红框中的箭头,弹出如下图所示的windows系统证书管理界面:
然后点击“导入”按钮,进入证书导入向导:
点击“下一步”,进入如下图所示界面:
点击“浏览”,选择我们刚才生成的客户端密钥库文件:
然后点击“下一步”:
输入密钥库的密码,并且勾选“启用强私钥保护”复选框,点击“下一步”:
默认证书存储的位置是个人,我们不用改变它,直接点击“下一步”:
最后点击“完成”:
会弹出如上图所示的一个提示框,我们不管它,直接点击“确定”,然后会弹出导入成功的提示框,表示客户端的密钥库已经配置完毕,这时我们再次尝试访问页面:
浏览器会弹出一个如上图所示的提示框,我们选中刚才配置的密钥库,然后点击确定,此时还会弹出一个提示框:
点击“允许”,完成后会看到tomcat的管理页面已经正常打开了。
至此,针对tomcat的https双向认证配置就完成了。