【干货分享】HTTPS SSL 加密问题浅析

SSL(Secure Socket Layer):是Netscape公司设计的主要用于WEB的安全传输协议,它在https协议栈中负责实现上加密层。本文介绍了HTTPS以及SSL协议,以及Nginx如何实现加密。

HTTPS SSL证书

SSL(Secure Socket Layer)是Netscape公司设计的主要用于WEB的安全传输协议。从名字就可以看出它在https协议栈中负责实现上面提到的加密层。因此,一个https协议栈大致是这样的,如图 1:

SSL结构图

SSL结构图

数字证书:一种文件的名称,好比一个机构或人的签名,能够证明这个机构或人的真实性。其中包含的信息,用于实现上述功能。

加密和认证:加密是指通信双方为了防止敏感信息在信道上被第三方窃听而泄漏,将明文通过加密变成密文,如果第三方无法解密的话,就算他获得密文也无能为力;认证是指通信双方为了确认对方是值得信任的消息发送或接受方,而不是使用假身份的非法者,采取的确认身份的方式。只有同时进行了加密和认证才能保证通信的安全,因此在SSL通信协议中这两者都被应。早期一般是用对称加密算法,现在一般都是不对称加密,最常见的算法就是RSA。

消息摘要:这个技术主要是为了避免消息被篡改。消息摘要是把一段信息,通过某种算法,得出一串字符串。这个字符串就是消息的摘要。如果消息被篡改(发生了变化),那么摘要也一定会发生变化(如果2个不同的消息生成的摘要是一样的,那么这就叫发生了碰撞)。消息摘要的算法主要有MD5和SHA,在证书领域,一般都是用SHA(安全哈希算法)。

数字证书、加密和认证、消息摘要三个技术结合起来,就是在HTTPS中广泛应用的证书(certificate),证书本身携带了加密/解密的信息,并且可以标识自己的身份,也自带消息摘要。

HTTPS工作过程

  1. 浏览器发送一个连接请求给安全服务器
  2. 服务器将自己的证书,以及同证书相关的信息发送给客户浏览器
  3. 客户浏览器检查服务器送过来的证书是否是由自己信赖的 CA 中心所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续
  4. 接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份
  5. 服务器要求客户发送客户自己的证书。收到后,服务器验证客户的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得用户的公钥
  6. 客户浏览器告诉服务器自己所能够支持的通讯对称密码方案
  7. 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器
  8. 浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器
  9. 服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥
  10. 服务器、浏览器接下来的通讯都是用对称密码方案,对称密钥是加过密的

上面所述的是双向认证 SSL 协议的具体通讯过程,这种情况要求服务器和用户双方都有证书。单向认证 SSL 协议不需要客户拥有 CA 证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的 (这并不影响 SSL 过程的安全性)密码方案。

这样,双方具体的通讯内容,就是加过密的数据,如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密 的数据进行解密,这时候的安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使用128 位加密通讯的原因。

单向加密

单向认证主要是用来认证自己所访问的站点发送过来的信息安全可靠,一般这种网站的证书都是权威的第三方机构颁发的。

nginx配置单向加密

nginx中默认使用443端口来做SSL加密,配置如图 2:

nginx配置单向加密

nginx配置单向加密

配置和使用单向加密需要:

  1. 证书:使用权威机构的根证书签发
  2. 私钥:自己的私钥,用于解密用户发来的内容

关于如何签发证书和生成key文件,可以参考附录。

浏览器证书导入

如果你使用的是权威机构所签发的证书的话,你不需要把证书手动的导入到浏览器的证书中,如果你想使用自己签发的证书的话,你需要:

  1. 生成root证书:该证书相当于权威机构的签发证书,证书中一般包含了机构信息
  2. 使用root证书签发自己的网站证书:该证书是用来发送给用户的
  3. 客户端导入root证书到受信任的根证书颁发机构

浏览器访问过程如下:

  1. 发送请求到服务器
  2. 服务器发送网站的证书
  3. 浏览器校验证书发现该网站的证书是受信任证书颁发机构颁发的,认证通过
  4. 协商密钥通信

双向加密

工作中遇到的一个麻烦问题涉及到fileserver双向加密,导致的一个后果就是不能使用浏览器调试,如果要在浏览器上面调试api的话,需要导入证书。

双向认证只是在单向认证的基础上,加上了客户端的认证,单向认证的实质是检验服务端的可靠性,大家都认为支付宝是安全的,但是任何钓鱼网站都可以伪造支付宝网站,怎么样才能认为我们访问的是官网?客户端此时需要对网站服务商进行认证,确定其不是伪造的。

而双向认证则是在这个基础上对客户端进行验证,比如有些很重要的服务需要内部使用或者是小范围的合作商使用,通过API提供这些服务,那么只有受信任的客户才能获取到数据。

nginx配置双向认证

双向认证nginx配置如图 3:

 nginx双向认证配置

nginx双向认证配置

除了配置服务端的证书外,我们看到了fileserver配置了client的证书,改证书是用来签发客户端证书的根证书,原则上该证书应该是服务提供商自己生成的,而不是由其他公共机构签发,服务商生成这个证书后,用来签发证书给付费的客户,客户拿到证书后才能够使用相应的服务,配置完成了需要打开ssl_verify_client开关来验证客户身份。

双向认证工作过程

双向认证是服务器与客户端通过互相验证彼此的证书来确保对方的可信,其认证过程如图 4:

SSL双向认证过程

SSL双向认证过程

双向认证的前提是拿到了对方的根证书,也就是签发证书,然后里利用该签发证书来验证对方发来的证书是否可信。

fileserver SSL

fileserver使用的是双向的SSL加密,根证书是由自己生成的,客户端的根证书也是自己生成的,这种情况下,客户端和服务的根证书可以是同一个,这样比较方便。

从图 3中我们看到,服务端发往客户端的证书是server.cert,服务端的私钥存储在server.pkey中,客户端的根证书是CA.cert,客户端的证书必须是由这个CA.cert证书签发。

nginx配置

如图 3所示。

服务端证书

服务端的证书是server.cert,在fileserver_v2的svn中有一个key目录,里面保存了服务端了客户端的证书信息,我们可以包服务端的根证书server/CA.cert导入到自己的浏览器的受信任的根证书中,来验证服务端的证书。

客户端证书

客户端的证书保存在key/device/目录下面,我们需要把客户端的根证书配置在nginx中,用来验证客户的可信性,我们也需要在浏览器上面导入到用户的个人证书/device/device.cert,当我们发送请求到服务端时,我们携带上这个证书,让服务端验证我们的身份。

这里由于fileserver key目录下面的用户个人证书中有密码,所以导入到个人证书的时候并不让通过,而密码我们是不知道的,但是也是可以使用的,我们可以利用客户端的根证书自己签发一个新的证书,这样密码可有可无,我们仍旧能通过服务端的验证。

附录:

使用openssl生成根证书

  1. 创建私钥:openssl genrsa –out ca-key.pem 1024
  2. 创建证书请求:openssl req -new –out ca-req.csr -key ca-key.pem
  3. 签发证书:openssl x509 -req -in ca-req.csr -out ca-cert.pem -signkey ca-key.pem -days 3650

openssl签发客户端证书

  1. 创建客户端私钥:openssl genrsa –out client-key.pem 1024
  1. 创建客户证书请求:openssl req -new –out client-req.csr -key client-key.pem
  2. 使用ca签发证书:openssl x509 -req -in client-req.csr -out client-cert.pem -signkey client-key.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -days 3650
  3. 将证书导出为p12格式:openssl pkcs12 -export -clcerts -in client-cert.pem -inkey client-key.pem -out client.p12

openssl签发服务端证书

与客户端类似。

如果您需要了解更多内容,可以
加入QQ群:570982169、486207500
直接询问:010-68438880-8669

发表评论