Https概述与流程
HTTP
HTTP
超文本传输协议协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。使用TCP端口为80。
HTTPS
为了解决HTTP协议的这一缺陷,网景公式设计了SSL(Secure Sockets
Layer-安全套接层)协议用于对Http协议传输的数据进行加密,保证会话过程中的安全性。使用TCP端口为
443。SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
HTTPS也称作HTTP over TLS。TLS(Transport Layer
Security-传输层安全)协议的前身是SSL,TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL
3.2,TLS 1.2为SSL 3.3,TLS 1.3为SSL 3.4。
SSL1.0 | SSL2.0 | SSL3.0 | TLS1.0(SSL3.1) | TLS1.1(SSL3.2) | TLS1.2(SSL3.3) | TLS1.3(SSL3.4) |
---|
红色的表示不安全的,绿色的是安全的。
层级 | 层名 | 常用协议 |
---|---|---|
7 | 应用层 | HTTP/HTTPS、FTP、Socket、Telnet、SSH、SMTP、POP3、DHCP、DNS、NFS、SNMP |
6 | 表示层 | XDR、LPP |
5 | 会话层 | SSL/TLS、LDAP/DAP、RPC |
4 | 传输层 | TCP、UDP |
3 | 网络层 | IP、OSPF、ICMP、 |
2 | 数据链路层 | 以太网、令牌环、PPP、PPTP、L2TP、ARP、ATMP |
1 | 物理层 | 物理线路、光纤、无线电 |
客户端执行https请求时,需要由TCP协议建立和释放连接。这就涉及TCP协议的三次握手和四次挥手。
注意:我们可能会经常看到“HTTP的三次握手”这个说法,其实这种说法不准确,HTTP是没有什么三次握手的,这个其实指的就是TCP的三次握手。
HTTPS认证流程
TCP连接建立好后,对于HTTP而言,服务器就可以发数据给客户端。但是对于HTTPS,它还要运行SSL/TLS协议,SSL/TLS协议分两层,第一层是记录协议,主要用于传输数据的加密压缩;第二层是握手协议,它建立在第一层协议之上,主要用于数据传输前的双方身份认证、协商加密算法、交换密钥。
HTTPS验证过程就是SSL握手协议的交互过程。“HTTPS验证”这个说法其实不准确的,应该是“SSL验证”,这两种说法网上都能看到。
https单相认证
https双向认证之客户端认证
单向认证
- 客户端向指定域名的服务器发起https请求
请求内容包括:
1)客户端支持的SSL/TLS协议版本列表
2)支持的对称加密算法列表
3)客户端生成的随机数A
-
服务器收到请求后,回应客户端,回应的内容主要有:
1)SSL/TLS版本。服务器会在客户端支持的协议和服务器自己支持的协议中,选择双方都支持的SSL/TLS的最高版本,作为双方使用的SSL/TLS版本。如果客户端的SSL/TLS版本服务器都不支持,则不允许访问
2)与1类似,选择双方都支持的最安全的加密算法。
3)从服务器密钥库中取出的证书
4)服务器端生成的随机数B
- 客户端回应
客户端收到后,检查证书是否合法,主要检查下面4点:
1、检查证书是否过期
2、检查证书是否已经被吊销。
有CRL和OCSP两种检查方法。CRL即证书吊销列表,证书的属性里面会有一个CRL分发点属性,如下图所示(Microsoft
IT的证书),这个属性会包含了一个url地址,证书的签发机构会将被吊销的证书列表展现在这个url地址中;OCSP是在线证书状态检查协议,客户端直接向证书签发机构发起查询请求以确认该证书是否有效。
3、证书是否可信。
客户端会有一个信任库,里面保存了该客户端信任的CA(证书签发机构)的证书,如果收到的证书签发机构不在信任库中,则客户端会提示用户证书不可信。
若客户端是浏览器,各个浏览器都会内置一些可信任的证书签发机构列表,在浏览器的设置中可以看到。
如果不在信任表中,则浏览器会出现类似下面的警告页面,提示你不安全。(当然,你可以选择继续访问)
若客户端是程序,例如Java中,需要程序配置信任库文件,以判断证书是否可信,如果没设置,则默认使用jdk自带的证书库(jre\lib\security\cacerts,默认密码changeit)。如果证书或签发机构的证书不在信任库中,则认为不安全,程序会报错。(你可以在程序中设置信任所有证书,不过这样并不安全)。
4、检查收到的证书中的域名与请求的域名是否一致。
若客户端是程序,这一项可配置不检查。若为浏览器,则会出现警告,用户也可以跳过。
证书验证通过后,客户端使用特定的方法又生成一个随机数c,这个随机数有专门的名称“pre-master
key”。接着,客户端会用证书的公钥对“pre-master key”加密,然后发给服务器。
-
服务器的最后回应
服务器使用密钥库中的私钥解密后,得到这个随机数c。此时,服务端和客户端都拿到了随机数a、b、c,双方通过这3个随机数使用相同的DH密钥交换算法计算得到了相同的对称加密的密钥。这个密钥就作为后续数据传输时对称加密使用的密钥。
服务器回应客户端,握手结束,可以采用对称加密传输数据了。
这里注意几点:
1、整个验证过程,其实是为了安全地得到一个双方约定的对称加密密钥,当然,过程中也涉及一些身份认证过程。既然刚开始时,客户端已经拿到了证书,里面包含了非对称加密的公钥,为什么不直接使用非对称加密方案呢,这是因为非对称加密计算量大、比较耗时,而对称加密耗时少。
2、对称加密的密钥只在这次连接中断前有效,从而保证数据传输安全。
3、为什么要用到3个随机数,1个不行吗?这是因为客户端和服务端都不能保证自己的随机数是真正随机生成的,这样会导致数据传输使用的密钥就不是随机的,时间长了,就很容易被破解。如果使用客户端随机数、服务端随机数、pre-master
key随机数这3个组合,就能十分接近随机。
4、什么是信任库和密钥库。信任库前面已经说了,它是用来存放客户端信任的CA的证书。在程序交互中,需要确保你访问的服务器的证书在你的信任库里面。密钥库是用来存放服务器的私钥和证书。
5、中间人攻击问题。前面过程说明中,有一点,客户端是验证有问题的时候,是可以选择继续的。对浏览器而言,用户可以选择继续访问;对程序而言,有些系统为了处理简单,会选择信任所有证书,这样就给中间人攻击提供了漏洞。
中间人攻击时,它想办法拦截到客户端与服务器之间的通信。在客户端向服务器发信息时,中间人首先伪装成客户端,向真正的服务器发消息,获得真正的证书,接着伪装成服务器将自己的伪证书发给客户端。服务器向客户端发消息时,中间人伪装成客户端,接收消息,然后再伪装成服务器向客户端发消息。最后验证过程完成后,客户端的真实对称密钥被中间人拿到,而真正的服务器拿到的是中间人提供的伪密钥。后续数据传输过程中的数据就会被中间人窃取。
双向认证
单向验证过程中,客户端会验证自己访问的服务器,服务器对来访的客户端身份不做任何限制。如果服务器需要限制客户端的身份,则可以选择开启服务端验证,这就是双向验证。从这个过程中我们发现,使用单向验证还是双向验证,是服务器决定的。
一般而言,我们的服务器都是对所有客户端开放的,所以服务器默认都是使用单向验证。如果你使用的是Tomcat服务器,在配置文件server.xml中,配置Connector节点的clientAuth属性即可。若为true,则使用双向验证,若为false,则使用单向验证。如果你的服务,只允许特定的客户端访问,那就需要使用双向验证了。
双向验证基本过程与单向验证相同,不同在于:
1)第二步服务器第一次回应客户端的消息中,会要求客户端提供“客户端的证书”
2)第三步客户端验证完服务器证书后的回应内容中,会增加两个信息:
1、客户端的证书
2、客户端证书验证消息(CertificateVerify
message):客户端将之前所有收到的和发送的消息组合起来,并用hash算法得到一个hash值,然后用客户端密钥库的私钥对这个hash进行签名,这个签名就是CertificateVerify
message
3)服务器收到客户端证书后:
a)确认这个证书是否在自己的信任库中(当然也会校验是否过期等信息),如果验证不通过则会拒绝连接;
b)用客户端证书中的公钥去验证收到的证书验证消息中的签名。这一步的作用是为了确认证书确实是客户端的。
所以,在双向验证中,客户端需要用到密钥库,保存自己的私钥和证书,并且证书需要提前发给服务器,由服务器放到它的信任库中。
总结
1、单向验证中,如果是你客户端,你需要拿到服务器的证书,并放到你的信任库中;如果是服务端,你要生成私钥和证书,并将这两个放到你的密钥库中,并且将证书发给所有客户端。
2、双向验证中,如果你是客户端,你要生成客户端的私钥和证书,将它们放到密钥库中,并将证书发给服务端,同时,在信任库中导入服务端的证书。如果你是服务端,除了在密钥库中保存服务器的私钥和证书,还要在信任库中导入客户端的证书。
3、再次强调,使用单向验证还是双向验证,是服务器决定的。
4、https的验证过程,不管是单向还是双向,只有四步,图上画的步骤只是为了便于理解。很多关于https验证过程的文章中,写了来来回回七八上十步。要真是这样,访问一个https地址,时间全花在了交互上了。
https双向认证与openssl
证书相关概念
CA(Certificate
Authority):被称为证书授权中心是数字证书发放和管理的机构。签发主流机构:Symantec、Thawte、GeoTrust、GlobalSign等。
根证书:CA证书授权中心给自己颁发的证书,
是信任链的起始点。安装根证书意味着对这个CA认证中心的信任。权威CA机构的根证书内置于浏览器中。
签发证书的过程:
撰写证书元数据:包括 签发人(Issuer)、地址、签发时间、有效期
等,还包括证书持有者(Owner)基本信息,比如 DN(DNS
Name,即证书生效的域名)、 Owner 公钥 等信息使用通用的 Hash 算法(如SHA-256)对证书元数据计算生成 数字摘要
使用 Issuer
的私钥对该数字摘要进行加密,生成一个加密的数字摘要,也就是Issuer的
数字签名将数字签名附加到数字证书上,变成一个 签过名的数字证书
将签过名的数字证书与 Issuer
的公钥,一同发给证书使用者(注意,将公钥主动发给使用者是一个形象的说法,只是为了表达使用者最终获取到了
Issuer 的公钥)
验证证书的过程:
证书使用者获通过某种途径(如浏览器访问)获取到该数字证书,解压后分别获得
证书元数据 和 数字签名使用同样的Hash算法计算证书元数据的 数字摘要
使用 Issuer 的公钥 对数字签名进行解密,得到 解密后的数字摘要
对比 2 和 3 两个步骤得到的数字摘要值,如果相同,则说明这个数字证书确实是被
Issuer 验证过合法证书,证书中的信息(最主要的是 Owner 的公钥)是可信的
证书链:https://www.jianshu.com/p/fcd0572c4765
客户端验证服务器证书
Openssl :目前最流行的 SSL
密码库工具,其提供了一个通用、健壮、功能完备的工具套件,用以支持SSL/TLS
协议的实现。
X.509:是被广泛使用的数字证书标准,是用于标志通讯各方身份信息的一系列数据。
X.509证书包含三个文件:key(私钥),csr(生成数字证书请求文件),cer/crt(是用于存放证书的签名文件,以二进制形式存放,不含私钥)。
生成数字证书
我们需要 自签根证书、服务端证书、服务端私钥、客户端证书。
注意:Openssl使用1.0.2版本,否则生成请求文件会报错。
- 创建根证私钥
OpenSSL>genrsa -out D:\F\two-way-verification\root-key.key 1024
说明:生成rsa私钥,1024位长度,输出到root-key.key。
- 创建根证书请求文件
OpenSSL> req -new -out D:\F\two-way-verification\root-req.csr -key
D:\F\two-way-verification\root-key.key
说明:会让填写信息,其中国家,省市,公司等需要和后面的证书保持一致.后面challenge
password的地方直接回车就好。
- 生成自签根证书
OpenSSL> x509 -req -in D:\F\two-way-verification\root-req.csr -out
D:\F\two-way-verification\root-cert.cer -signkey
D:\F\two-way-verification\root-key.key -CAcreateserial -days 3650
- 生成服务端私钥
OpenSSL> genrsa -out D:\F\two-way-verification\server-key.key 1024
- 生成服务端请求文件
OpenSSL>req -new -out D:\F\two-way-verification\server-req.csr -key
D:\F\two-way-verification\server-key.key
说明:国家省市公司和2)保持一致, Common Name 要特别注意,
要用你服务器的域名,我们测试用wangting.com
- 生成服务端证书(root-cert.cer,root-key.key,server-key.key,server-req.csr
这4个文件来生成服务端证书)
OpenSSL> x509 -req -in D:\F\two-way-verification\server-req.csr -out
D:\F\two-way-verification\server-cert.cer -signkey
D:\F\two-way-verification\server-key.key -CA
D:\F\two-way-verification\root-cert.cer -CAkey
D:\F\two-way-verification\root-key.key -CAcreateserial -days 3650
- 生成客户端key
OpenSSL> genrsa -out D:\F\two-way-verification\client-key.key 1024
- 生成客户端请求文件
OpenSSL> req -new -out D:\F\two-way-verification\client-req.csr -key
D:\F\two-way-verification\client-key.key
生成客户端证书(root证书,rootkey,client-key.key,client-req.csr这4个生成文件生成客户端证书)
OpenSSL> x509 -req -in D:\F\two-way-verification\client-req.csr -out
D:\F\two-way-verification\client-cert.cer -signkey
D:\F\two-way-verification\client-key.key -CA
D:\F\two-way-verification\root-cert.cer -CAkey
D:\F\two-way-verification\root-key.key -CAcreateserial -days 3650
- 生成客户端p12格式根证书(密码设置123456)
OpenSSL> pkcs12 -export -clcerts -in
D:\F\two-way-verification\client-cert.cer -inkey
D:\F\two-way-verification\client-key.key -out
D:\F\two-way-verification\client.p12
为什么必须转p12,因为步骤9生成的证书导入不了浏览器客户端。
备注:参数名称和意义
genrsa 产生RSA密钥命令
req 产生证书签发申请命令
x509 签发X.509格式证书命令
pkcs12 PKCS#12编码格式证书命令。
-in 表示输入文件
-out 表示输出文件
-req 表示证书输入请求。
-export 表示导出证书
-inkey 表示输入私钥文件
-days 表示有效天数
-CAcreateserial 表示创建CA证书序列号
-CAkey 表示CA证书私钥
-CA 表示CA证书
-signkey 表示自签名私钥
-new 表示新请求
-clcerts 表示仅导出客户证书。
配置nginx服务
注意事项:1. nginx安装包路径中不能有中文,否则启动不了
- 配置https的证书路径时注意要使用/,不能使用\。
重定向http请求
server {
listen 80;
server_name 127.0.0.1;
rewrite ^(.*)host$1; # 强制转https
}
创建监听443端口服务
server {
listen 443 ssl;
server_name wangting.com;
ssl_certificate D:/two-way-verification/server-cert.cer; #server公钥证书
ssl_certificate_key D:/two-way-verification/server-key.key; #server私钥
ssl_client_certificate D:/two-way-verification/root-cert.cer;
客户端证书的CA证书了(即根证书),代表此CA签发的证书都是可信的。 使用 CA
证书来验证请求带的客户端证书是否是该 CA 签发的
ssl_verify_client off; #启用客户端证书审核
ssl_session_cache shared:SSL:1m; #设置储存SSL会话的缓存类型和大小
ssl_session_timeout 5m; #设置客户端能够反复使用储存在缓存中的会话参数时间
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #指定要使用的SSL协议
location / {
root D:/two-way-verification;
index index.html;
}
}
配置Host域名解析
C:\Windows\System32\drivers\etc\hosts
安装客户端证书
将client.p12进行安装
备注:不同的客户端证书通过Common Name 和 Email Address区分
注意: 为什么不安装client-cert.cer证书
因为client-cert.cer证书中只有公钥信息,双向认证浏览器安装的客户端证书中需要使用到私钥信息。
https单向认证与keytool
单向认证
注释掉
ssl_verify_client on; #启用客户端证书审核
Keytool简介
keytool 是个Java提供的密钥和证书管理工具。
keytool 将密钥和证书储存在一个称为keystore的密钥仓库中
Keytool生成私钥和证书
- 创建keystore秘钥库
keytool -genkey -v -alias wangting -keyalg RSA -validity 3650 -keystore
D:/one-way-verification/wangting.keystore
- 创建证书
keytool -export -alias wangting -keystore
D:/one-way-verification/wangting.keystore -storepass 123456 -rfc -file
D:/one-way-verification/wangting.cer
备注:参数名称和意义
-keyalg 使用加密的算法,这里是RSA
-keypass 私有密钥的密码,这里设置为 123456
-keystore 密钥库
-validity 该密钥的有效期为 365天 (默认为90天)
-keysize 指定密钥长度
-alias 证书别名
-storepass 指定密钥库的密码
-export 将别名指定的证书导出到文件
-rfc 表示以base64输出文件,否则以二进制输出
- 获取秘钥
keytool不提供命令导出私钥,所以需要使用程序导出key
配置nginx
更换nginx.conf中的私钥和证书,域名如有变化需要更改
配置Host
C:\Windows\System32\drivers\etc\hosts
tomcat配置https
使用openssl生成的私钥和证书
-
根据双向认证时生成的服务端证书和私钥生成PKCS#12的证书文件:
pkcs12 -export -clcerts -in D:\two-way-verification\server-cert.cer -inkey
D:\two-way-verification\server-key.key -out
D:\two-way-verification\server.p12 -
将server.p12文件转为keystore:
keytool -importkeystore -v -srckeystore D:/two-way-verification/server.p12
-srcstoretype pkcs12 -srcstorepass 123456(p12刚输入的密码) -destkeystore
D:/two-way-verification/server.keystore -deststoretype jks -deststorepass
123456(keystore密钥库的密码)注意:(标黄的两个密码需要一致,不一致tomcat启动时会报错。)
-
配置tomcat的server.xml
启动tomcat, 访问https://wangting.com:8443/
在浏览器中配置证书
使用keytool生成keystore
使用单向认证时生成的密钥库wangting.keystore,以及证书wangting.cer
-
配置tomcat的server.xml
启动tomcat, 访问https://yada:8443/
在浏览器中配置证书
生成带SAN的证书
问题:在之前的案例中我们发现及时浏览器安装了证书,在谷歌浏览器中依然会警告
原因:Chrome 58 及以上版本只会使用 subjectAlternativeName 扩展程序(而不是
commonName)来匹配域名和网站证书。因此会报错:NET::ERR_CERT_COMMON_NAME_INVALID
。
修改openssl配置文件
首先需要修改openssl.cnf(该文件在bin文件中),有的bin文件中没有openssl.cnf,
但是有openssl.cnf,将后缀名改一下就可以了。
确保req下存在以下2行(默认第一行是有的,第2行被注释了)
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
确保req_distinguished_name下没有 0.xxx 的标签,有的话把0.xxx的0. 去掉
新增最后一行内容 subjectAltName = @alt_names(前2行默认存在)
[ v3_req ]
Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
新增 alt_names,注意括号前后的空格,DNS.x 的数量可以自己加
[ alt_names ]
DNS.1 = wangting.com
DNS.2 = yuxinditie.com
根据配置文件生成证书
1)生成私钥
genrsa -out server.key 2048
- 生成csr文件
req -new -key server.key -out server.csr -config openssl.cnf
- 生成ca.key并自签署
req -new -x509 -days 3650 -keyout ca.key -out ca.crt -config openssl.cnf
4)用生成的CA的证书为刚才生成的server.csr文件签名
ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key -extensions
v3_req -config openssl.cnf
配置nginx服务
同上
配置Host域名解析
同上
使用程序访问https网站
可以看到执行完这段代码,程序会报如下错误:
原因:验证服务器证书时出错,程序启动后,java虚拟机会查看jvm信任的证书列表,发现没有信任服务器的证书。
解决方案: 将服务器证书导入到jdk。
keytool -import -v -trustcacerts -alias wang-ca -file D:/certWithSAN/ca.crt
-storepass changeit -keystore
D:/D/Installed/Java/jdk1.8.0_131/jre/lib/security/cacerts
重新运行程序,成功。
--查看jvm信任的证书列表
keytool -list -keystore
“D:/D/Installed/Java/jdk1.8.0_131/jre/lib/security/cacerts” -storepass changeit
--删除证书
keytool -delete -alias wang2 -keystore
“D:/D/Installed/Java/jdk1.8.0_131/jre/lib/security/cacerts” -storepass changeit