升级https总结
实时流水升级https总结文章:
背景:
实时流水系统作为计费系统的相关联辅助系统,主要负责对实时交易流水的存储查询和推送业务或相关系统进行逻辑处理等。相关推送模块之前只支持http,作为外部通知模块,关键路径推送用户交易信息,需要更加安全可靠的机制保证信息传输的安全可靠,需要支持https。
升级方案:
curl+openssl+签名。一般curl库只支持http,需要openssl库配合curl库重新编译,支持https(当然也可以直接在安装curl库时选择支持https);
https也并非完全可靠,TLS/SSL层加密在传输层上,一般的如何保证收发端的正确,需要加签名机制。本次升级使用签名机制参考:https://wiki.midas.qq.com/post/index/3/54/127/0
(md5,RSA1等部分签名方式已被证明存在漏洞,选取更高级的签名算法版本,确保安全性)
https实现机制,自签名证书生成,相关编码调试,证书验证及部署经验:
1)关于https机制分析
http使用明文传输,且没有相应域名ip信息验证机制,可能造成信息泄露,或者被劫持植入广告等。https在http传输协议基础上,加上TLS/SSL层的加密,来实现信息加密,身份验证,信息校验等相关工作。TSL/SSL处于tcp和http协议之间
https协议的握手传输过程示意图:
这是一个简化版的https连接过程示意图,十分直观,但对于称**的生成过程,证书的验证过程不甚详细。详细可参见如下连接步骤:
1. 客户端发起加密通信的请求,这被叫做client hello请求。在这步中,客户端主要提供的信息有:协议版本(例TLS 1.0)、一个客户端生成的随机数(稍后用于生成"对话**")、支持的加密方法(例RSA)。
2. 服务器发出响应(server hello),回应主要包含的内容:TSL/SSL协议版本(例如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信)、一个服务器生成的随机数(稍后用于生成"对话**")、确认使用的加密方法(比如RSA)、服务器证书
注:除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。但一般场景没有这种要求,服务端也会视情况验证,如果客户端有传送证书便进行验证。
3.客户端收到服务器响应后,首先要验证服务器证书(域名地址的正确性)。证书没有问题,客户端就可以从证书中取出公开**,然后发送下面的信息: 一个随机数,用服务器公钥加密,防止被窃听。编码改变通知,表示随后的信息都将用双方商定的加密方法和**发送。客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。注:以上过程总共出现了三个随机数,客户端用商定的加密方法对这三个随机数进行处理,生成此次会话要使用的对称**(这个时候也可以称它为会话**)
4.服务器最后的回应,服务器这个时候和客户端一样生成对称**。然后发送以下消息:编码改变通知,表示随后的信息都将用双方商定的加密方法和**发送。服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。
到这里客户端和服务器就可以进行https通信了
需要再梳理清楚也是使用证书验证的原因:服务器直接把公钥传给客户端,不传递数字证书。如果这样的话,有可能会有第三方劫持会话,发送一个假的公钥,实现中间人攻击。所以需要证明这个**就是真正的服务器所发送的,这个时候需要第三方的权威认证机构来证明。证明的方法是:首先,服务器的运营人员向数字证书认证机构提出公开**的申请。数字证书认证机构在判明提出申请者的身份之后,会对已申请的公开**做数字签名,然后分配这个已签名的公开**,并将该公开**放入公钥证书后绑定在一起。而且第三方权威认证机构公布自己的**,浏览器一般会把公开**植入内部。所以服务器会发送一个证书过来。验证证书的时候,使用第三方权威认证机构的公开**进行解密,验证通过那就意味着认证服务器的公开**是真实有效的数字证书,而且服务器的公开**是值得信赖的。
*证书验证机制保证对端是正确的域名地址,可信任的。TLS/SSL层加密保证信息传输的过程中不被人截取和偷窥,避免被劫持,注入广告等。
*使用公钥加***,使用私钥解密后协商,之后使用对称**加密。(对称加密的加解密基本使用位或与等运算效率更高,所以先用非对称加密协商对称加密的**,之后全部使用对称加密)
*https的tls、ssl加密也包含了消息的签名,防止信息被篡改。
2)关于证书生成,部署配置相关
概念:
首先要有一个CA根证书,然后用CA根证书来签发用户证书(可以是服务器证书,也可以是客户端证书,而验证阶段即使用根证书来对自己颁发的服务端或客户端证书进行验证,看一看是否是自己的孩子!!!当然这个根证书需要我们交给对端。而正常情况下,使用知名机构的签名证书,浏览器会自己下载这些知名机构的CA证书来对知名机构颁发的服务器证书或者说是客户端证书进行验证)。
用户进行证书申请:一般先生成一个私钥,然后用私钥生成证书请求(证书请求里应含有公钥信息),再利用证书服务器的CA根证书来签发证书。
特别说明:
(1)自签名证书(一般用于*证书、根证书): 证书的名称和认证机构的名称相同.
(2)根证书:根证书是CA认证中心给自己颁发的证书,是信任链的起始点。任何安装CA根证书的服务器都意味着对这个CA认证中心是信任的。
数字证书则是由证书认证机构(CA)对证书申请者真实身份验证之后,用CA的根证书对申请人的一些基本信息以及申请人的公钥进行签名(相当于加盖发证书机构的公章)后形成的一个数字文件。数字证书包含证书中所标识的实体的公钥(就是说你的证书里有你的公钥),由于证书将公钥与特定的个人匹配,并且该证书的真实性由颁发机构保证(就是说可以让大家相信你的证书是真的),因此,数字证书为如何找到用户的公钥并知道它是否有效这一问题提供了解决方案。
CA根证书的生成步骤:生成CA私钥(.key)–>生成CA证书请求(.csr)–>自签名得到根证书(.crt)(CA给自已颁发的证书)。
Generate CA private key
openssl genrsa -out ca.key 2048
Generate CSR
openssl req -new -key ca.key -out ca.csr
Generate Self Signed certificate(CA 根证书)
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
在实际的软件开发工作中,往往服务器就采用这种自签名的方式,因为毕竟找第三方签名机构是要给钱的,也是需要花时间的。
用户证书的生成步骤:生成私钥(.key)–>生成证书请求(.csr)–>用CA根证书签名得到证书(.crt)
服务器端用户证书:
private key
$openssl genrsa -des3 -out server.key 1024
generate csr
$openssl req -new -key server.key -out server.csr
generate certificate
$openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
客户端用户证书:
$openssl genrsa -des3 -out client.key 1024
$openssl req -new -key client.key -out client.csr
$openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key
生成pem格式证书
有时需要用到pem格式的证书,可以用以下方式合并证书文件(crt)和私钥文件(key)来生成
$cat client.crt client.key> client.pem
$cat server.crt server.key > server.pem
结果:
服务端证书:ca.crt, server.key, server.crt, server.pem
客户端证书:ca.crt, client.key, client.crt, client.pem
在生成证书的时候,会让我们设置相关信息,需要注意的是,我们可以生成ip证书,也可以生成域名证书。ip证书在验证时候会验证对端ip的正确性,域名证书则会对对端域名进行验证。
需要注意的是现在大多是机构是不支持颁发ip证书的。当然我们可以自生成。
附:相关后缀文件的说明名,openssl中有如下后缀名的文件
.key格式:私有的**
.csr格式:证书签名请求(证书请求文件),含有公钥信息,certificate signing request的缩写
.crt格式:证书文件,certificate的缩写
.crl格式:证书吊销列表,Certificate Revocation List的缩写
.pem格式:用于导出,导入证书时候的证书的格式,有证书开头,结尾的格式
证书的部署:
对于自签名的CA证书,来生成的客户端或服务器证书,在验证时候,需要我们把CA根证书交给对端来进行验证。
部署在系统信任的CA根证书列表,需要root权限:相关证书转换参见:http://netkiller.github.io/cryptography/openssl/format.html
#转换格式 .cer 到 .pem
openssl x509 -inform der -in twca.cer -out twca.pem //现在生成的证书一般都是pem格式,一般不需要此步骤进行格式转化。
#追加到信任列表
cat twca.pem >> /etc/pki/tls/certs/ca-bundle.crt
注:生成的证书放在windows下可以直观的看到证书的颁发者,有效期,路径等信息。
3)关于代码编写curl相关配置设置
C++ curl发送https的相关设置选项说明(其他语言也是大同小异,函数选项参数一般相同):
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); //是否验证对等证书
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2); //0不校验域名正确性,1只检查证书域名是否存在,2在1的基础上对域名进行校验(当前域名是否和CN匹配)
// 0: Don’t check the common name (CN) attribute
// 1: Check that the common name attribute at least exists
// 2: Check that the common name exists and that it matches the host name of the server
curl_easy_setopt(curl, CURLOPT_CAINFO, CAFile.c_str()); //CA证书的文件名,当然如果不验证对等证书即没意义;当然也可以直接将CA证书部署在系统上,直接在系统信任列表中查询;
curl_easy_setopt(curl, CURLOPT_CAPATH, CAPath.c_str()); //CA证书的路径,当然不验证对等证书即没意义;当然也可以直接将CA证书部署在系统上,直接在系统信任列表中查询;
双向认证时候需要传递客户端证书给服务端:
curl_easy_setopt(m_curl_handler, CURLOPT_SSLCERT, client_cert_file.c_str()) // 客户端证书,用于双向认证
curl_easy_setopt(m_curl_handler, CURLOPT_SSLCERTTYPE, client_cert_type.c_str()) // 客户端证书类型,用于双向认证
curl_easy_setopt(m_curl_handler, CURLOPT_SSLKEY, private_key.c_str()) // 客户端证书私钥,用于双向认证
curl_easy_setopt(m_curl_handler, CURLOPT_SSLKEYTYPE, private_key_type.c_str()) // 客户端证书私钥类型,用于双向认证
curl_easy_setopt(m_curl_handler, CURLOPT_KEYPASSWD, private_key_passwd.c_str()) // 客户端证书私钥密码(生成私钥的算法不同,可能没有私钥密码)
4)以及curl命令验证时候的相关参数-v --carcert -k等的使用经验
在调试程序之前,我们可以先试用curl命令来验证下链路是否可通,是否支持https的传输,以及可以判断证书的部署是否存在问题。
-k 不对证书进行验证,与编码实现中的不验证对等证书作用相同
–carcert 加证书,使用所指定的CA证书进行验证
-v 显示详细的握手验证传输过程,报错信息等
总结:
当然https也并非完美无缺,http也不是没有使用场景。https由于存在复杂的握手建立连接的过程,证书验证等,且传输过程需要不停的对信息加密解密,效率可想而知。 而且https的证书需要向证书机构付费申请的哦(当然你也可以自己生成CA证书,然后用自生成的CA证书给自己颁发服务器证书,但这显然对用户来说是不方便的,用户需要下载你的CA证书部署后,才可正确访问你的服务器。而知名机构的CA证书浏览器会自己下载。)在一些对信息没有加密需求的场景,需要高效传输的场景,http依然是可选的。
上一篇: HTTPS总结
下一篇: nginx https应用