去年用tomcat、jboss配置过HTTPS双向认证,那时候主要用的是JDK自带的keytool工具。此次是用httpd + openssl,区别比较大
在网上搜索了不少文章,发现全面介绍的很少,或者就是版本比较旧了。因此把我配置的过程完整地记录下来,以供参考
首先要说明一下,HTTPS涉及到的内容很是繁杂,包括各类术语、命令、算法,我如今也没有彻底搞清楚。本文会尽可能把我知道的解释一下,可是深刻的内容,暂时不打算深究了
1、环境
httpd: 2.4.4
openssl:1.0.1
os:ubuntu 12.04 LTS
2、场景
我准备在httpd上配置一个HTTPS双向认证,既向客户端代表本身的身份,也只容许特定的客户端访问。本文说的主要是做为server的角色的配置,至于做为client的配置,最后也会稍微介绍一下,可是不会详细说明
通常来讲,互联网站不会去配置双向认证,由于客户端证书的分发和管理会比较麻烦,会把用户挡在门外,因此通常是不能这么作的。固然,像银行等对安全要求很高的网站,也会采用双向认证,好比U盾、安全控件什么的,其实就是固化的客户端证书
可是对于企业应用来讲,客户通常是固定的,好比两个已知的系统对接、内部系统集成等。因此在企业应用领域,双向认证仍是比较常见的
3、背景知识
证书(Certificate)是HTTPS的核心,可是其实证书并非一个单一的东西,而是几种技术的综合
为了网络传输的安全,有不少种技术,最主要的是如下3种:
一、加密/解密
避免消息明文传输,对消息进行加密。早期通常是用对称加密算法,如今通常都是不对称加密,最多见的算法就是RSA。在后面的介绍中,也会屡次看到RSA这个词
二、消息摘要
这个技术主要是为了不消息被篡改。消息摘要是把一段信息,经过某种算法,得出一串字符串。这个字符串就是消息的摘要。若是消息被篡改(发生了变化),那么摘要也必定会发生变化(通常是这样的。若是2个不一样的消息生成的摘要是同样的,那么这就叫发生了碰撞)
消息摘要的算法主要有MD5和SHA,在证书领域,通常都是用SHA(安全哈希算法)
三、数字签名
数字签名是为了验证双方的身份,避免身份伪造
以上三个技术结合起来,就是在HTTPS中普遍应用的证书(certificate),证书自己携带了加密/解密的信息,而且能够标识本身的身份,也自带消息摘要
4、在httpd中配置单向HTTPS
首先在%HTTPD_HOME%/conf/目录下,修改httpd.conf文件,加载必要的模块 html
这里的前提是,在编译httpd的时候,已经编译了ssl模块。这个步骤看另外一篇文档:
http://kyfxbl.iteye.com/blog/1902299
而后再导入默认的SSL配置文件,固然也能够选择不导入,在httpd.conf直接配置。可是导入默认的能够节省不少时间,而且默认的文件是用vhost配置的,不会跟main server冲突,能够算是一种最佳实践 linux
而后打开%HTTPD_HOME%/conf/extra/目录,看一下httpd-ssl.conf,主要有如下几个配置 算法
只要开启前3个,单向的HTTPS认证就配置好了。后面3个目前先注释掉,是后面双向认证才用到
而后重启一下httpd,会发现报错:
AH00526: Syntax error on line 106 of /usr/local/httpd/conf/extra/httpd-ssl.conf:
SSLCertificateFile: file '/usr/local/httpd/conf/server.cer' does not exist or is empty
这是由于httpd须要一个服务端的私钥(.key.pem),和一个服务端证书(.cer)。前面已经配置了这2个文件的路径,可是尚未建立。下一步就要建立这些文件
5、建立CA(Certificate Authority)
这个CA,也叫“根证书”
服务端作了一个证书,可是这是没有法律效力的,谁均可以本身作证书,就根本达不到安全的目的。因此就要有一个机构,负责来确认服务端的身份,而后统一的签发证书。这样才能有权威性
当浏览器经过HTTPS协议访问一个网站,网站首先会发过来一个本身的证书(certificate)。接下来浏览器就会到权威机构(CA),去 验证一下这个证书是否是它签发的。若是是的话,就信任这个网站的证书,继续访问;若是不是的话,要怎么处理就依赖于实现了。通常的浏览器会弹出一个警告, 让用户本身决定要不要继续访问。固然直接拒绝也是能够的
如今国际上有3大CA机构,若是是要本身作一个网站的话,如上所述,通常是须要请这些权威机构帮忙签发证书的。如今全部的主流浏览器,默认都安装 了这些CA的根证书,因此若是网站的证书是这些权威机构签发的,浏览器就不会发出警告了。好比支付宝,它的证书是由VeriSign签发的,因此访问支付 宝,浏览器不会发出警告
这里还有一个链条的关系,好比我有10个子网站,若是每一个都要去找CA签发证书,就很麻烦。我能够找CA给我签发一个次级根证书,而后再用这个次 级根证书给本身签发10个证书。那么只要客户的浏览器里有CA根证书就能够了,这10个证书均可以经过认证,不要求客户安装次级根证书,原文见下:
apache
若是是企业应用,那彻底能够本身给本身当CA,由于能够要求目标用户(系统)安装本身的CA根证书,效果是同样的,还能够省下请权威CA签发证书的费用(互联网应用分发本身的CA到无数的互联网用户上,难度很大)
下面就介绍如何建立本身的CA
一、准备工做
先在随便一个目录,建立如下几个子目录:
/private
/certificates
其中private放的是私钥和CSR(后面会介绍),certificates里放的就是证书了
二、建立CA私钥 ubuntu
最后的参数是RSA密钥的长度,默认是512。2048其实长了一点,老的浏览器稍后会不支持,不过如今的主流浏览器都是支持的,因此问题不大
经过这个命令,私钥就建立好了,文件名是ca.key.pem
用这个命令,能够看一下刚才建立的这个私钥的信息 浏览器
不过基本上,看也是白看,反正我是看不懂。只知道私钥里其实有2组数字,是用来造成公钥的,最后也会包含在证书里
tomcat
另外,最后的.pem扩展名,是表示该私钥用PEM编码。实际上私钥和证书都是用PEM编码的,PEM只是一种编码格式,不须要太在乎。 httpd能够直接处理这种编码格式,可是浏览器和JAVA都不行,因此在须要的时候,会把编码从PEM改为PKCS,后面会介绍。只要知道证书和私钥都 有编码,只是编码是PEM仍是PKCS的区别而已。就像"你好"能够用UTF-8编码,也能够用GBK编码同样,内容是不变的
三、建立CA签名请求 安全
这里要注意的是,若是不用-subj参数,那么就会在命令行交互输入签发目标的身份识别信息,这叫DN(Distinguished Name)。其中别的都没关系,最重要的是CN那一行,由于我这里是根证书,因此我设置为*.kyfxbl.net,这样我后面用这个CA签发的 www.kyfxbl.net、game.kyfxbl.net、news.kyfxbl.net……,全都是有效的
生成的签名请求文件,是ca.csr 服务器
同上,看不懂
四、本身签发CA根证书 网络
这里参数很复杂,我也不太清楚准确的意思是什么,能够用openssl x509 -help本身研究一下
生成的ca.cer,就是最终的根证书了!这个文件很是重要,由于后续的服务端证书、客户端证书,都是用这个CA签发的,也要把它分发给客户,让他们导入到本身的浏览器或者系统中
查看的命令是:
五、把根证书从PEM编码转为PKCS编码
这步其实不是必选的,可是前面说过,JAVA环境是不能直接用PEM编码的证书的,不少浏览器也不行,因此有时候也须要转一下编码
获得的ca.p12就是转码后的CA根证书,在不能直接用ca.cer的时候,就用ca.p12代替
6、签发服务端证书
如今CA根证书和私钥都有了,就能够开始签发服务端证书了(签发请求ca.csr是过程文件,有了cer就再也不须要它了,要删掉也能够)。下面的命令和签发CA证书时都差很少,可是参数上有区别
一、建立服务端私钥
二、建立服务端证书签发请求
和ca.csr的区别在于,这里的CN不是*.kyfxbl.net,而是www.kyfxbl.net,由于我如今是在为www.kyfxbl.net申请证书
三、利用CA根证书,签发服务端证书
这里和前面本身签发CA证书时,参数区别就比较大了,最后获得的server.cer,就是服务端证书
7、测试单向认证
把server.key.pem和server.cer拷贝到%HTTPD_HOME%/conf/目录下,而后从新启动httpd,会要求输入一个密码
而后访问http://localhost:443/,会报400错误:
接下来用https://localhost:443来访问,浏览器报警:
这里就是前面建立CSR时,输入的CN的做用,这个证书是为www.kyfxbl.net申请的,这里请求的地址倒是localhost,不匹配因此报错。为了能用www.kyfxbl.net这个主机名来访问,就须要改一下/etc/hosts文件:
127.0.0.1 localhost
192.168.1.102 www.kyfxbl.net
而后就能够用www.kyfxbl.net来访问了,再试一下:https://www.kyfxbl.net/
此次浏览器仍是告警,可是告警信息变了:
证书信息以下:
能够看到这个证书是由*.kyfxbl.net这个CA颁发的,浏览器不认识,因此不信任由这个CA签发的全部证书。接下来就须要把ca.cer 导入浏览器。这里直接导入server.cer也是能够的,可是后面若是又建立一个网站好比说www2.kyfxbl.net,那么又不行了。因此最好的 办法是直接导入CA根证书,那么后续只要是用这个根证书签发的证书,浏览器都会信任
导入前:
导入后:
再次访问,能够看到成功了,浏览器不告警,而且URL栏前面打了一个绿勾
8、配置双向认证
若是要配置服务器只容许合法的用户访问,就须要配置双向认证
配置为双向认证以后,除了服务端要发证书给客户端以外,客户端也要发客户端证书到服务端,服务端认证经过,才容许访问
在单项认证的基础上,再配置以上3个参数
SSLCACertificateFile,这个意思是当客户端发来客户端证书的时候,httpd用哪一个CA根证书校验它
配置好了,还不能重启,由于如今客户端证书还没作好
这里要说明一下,客户端证书是怎么来的
有2种方式:
第一种,客户端也本身CA,而后签发证书给本身。把客户端的CA根证书发过来,配置成SSLCACertificateFile。这在互联网应用里基本是不可能的,安全和管理都是问题。可是在企业应用里,仍是比较常见的,双方互相交换CA根证书
第二种,就用刚才服务端的CA根证书,签发一个客户端证书,发给用户,用户每次用这个证书来发请求,像银行,支付宝等等,用的是这种方式
固然理论上其实还有一种办法,就是客户本身去找权威CA签证书,可是这个是不可能的,由于很麻烦,找CA签也很是贵
本文用的是第2种方法。其实都是同样的。关键仍是在CA根证书上,因此前面也说过了,CA根证书很是重要
9、签发客户端证书
一、建立客户端私钥
二、建立客户端证书签发请求
这里的不一样在于,这里的CN不是*.kyfxbl.net,也不是www.kyfxbl.net,随便填一个kyfxbl就行了,或者干脆叫user都没问题,反正是一个客户端证书
三、利用CA根证书,签发客户端证书
这里和签发server.cer基本是同样的
四、把客户端证书转换成p12格式
这步是必须的,由于稍后就须要把客户端证书导入到浏览器里,可是通常浏览器都不能直接使用PEM编码的证书
10、测试双向认证
把ca.cer拷贝到%HTTPD_HOME%/conf/目录下,重启httpd
而后再次访问https://www.kyfxbl.net/,结果此次不是警告,而是直接报错:
接下来要把client.p12导入到浏览器里
导入前:
导入的时候会要求输入密码,这是为了不有人偷偷拷贝了别人的客户端证书,假装成合法用户:
导入后:
而后再次访问,浏览器会要求选择证书。这个步骤是经过双向认证访问网站时必须的,可是平时访问银行、支付宝的时候貌似没有,这是由于这些网站为了简化用户的操做,都会要求用户安装什么“安全控件”,控件自动选择了证书
点击肯定,访问成功!
11、JKS等
到这里,用httpd配置双向HTTPS认证就完成了
本文说的是做为server的角色,要如何配置。可是在JAVA环境下,若是要以client的角色,经过双向认证发起请求,则还有些不一样
这里其实是要充当一个相似浏览器的角色,须要校验server certificate,还须要在发起请求的时候,把client certificate发过去
在JAVA里,是经过keystore和truststore来实现的,不在本文的讨论范围内。能够看一下其余的几篇博客,在HTTPS分类里
12、参考资料
http://httpd.apache.org/docs/2.4/en/ssl/
http://linux.chinaunix.net/techdoc/net/2008/01/08/976172.shtml 《JAVA加密与解密的艺术》——做者梁栋