HTTPS到底是个啥玩意儿? 【2016-03-27 23:12更新】

HTTPS到底是个啥玩意儿?

.NET

44 2016/3/27 23:12

我们现在经常听说谁谁谁密码被盗了,谁谁谁信息又被劫持了。其中有一个原因:绝大部分网站用的是http这个明文协议。你以为很安全的在password框里填了隐藏的密码,他却一字一句明明白白的写到了网络上。于是乎好多网站开始从http迁移到https(至少登录部分)。我也准备做同样的事情,因此抽时间和小伙伴tt一起研究了一下https。

刚开始看https的时候,各种头大。国内网上讲相关的资料虽然一大堆,但是大部分是相互的抄,内容多而乱,且没有把事情讲清楚。后来查阅了一些外文资料(包括rfc、wikipedia等),读了JSSE的源代码以后,基本把这个事情的来龙去脉看懂了大部分,但是涉及到很多很细节的东西还是觉得不是完全懂,如有疏漏和错误,敬请大家指正和原谅 :-)

这篇文章的目标:用尽量简单和有趣的语言,把这个复杂的东东讲述清楚。所以,接下来我打算分成三部分来聊聊我理解的Https:

1、入门篇:主要用通俗的语言讲讲Https是什么东东,以及他大体的工作方式;

2、技术篇:结合抓包工具和源代码,分析Https的通讯流程和细节;

3、理论篇:不是特别深入的聊聊一些跟Https相关的算法。

====入门篇的分割线====

What’s HTTPS?

简单的说,https就是给http带了一个安全套,即使别人拿到了信息,也不知道这个里面装的啥。客户端(包括browser、手机app等)和服务器每次发http包的时候,都对这个包加个密,让第三者看到的只是加密后的乱码(我只想对你说:你猜你猜你猜猜猜),到对端以后再解密。

这个安全套,原来是叫SSL(Secure Sockets Layer),最先是Netscape弄出来的,后来哥们儿完蛋了,就慢慢变了名字,叫TLS(Transport Layer Security Protocol)。具体的区别可以去wikipedia搜索TLS,他们之间的升级细节讲述的非常详细(这一点百度百科真的差的有点远~)。

这个安全套跑在TCP的上层,在TCP连接完成后且HTTP启动前,协商一些跟加密相关的工作,完成协商之后,就可以对要发送的http包加密/解密了。

那他到底协商了些啥呢?其实就是保证安全的几个问题:

1、服务器要证明自己是靠谱的、安全的,不然给一个假网站发加密的密文就跟裸奔没啥区别

2、服务器和客户端通讯需要的加密算法和加密密钥

就跟当年天地会和韦小宝通信一样,先要亮出身份,证明自己,然后再拿出暗语的书信。

ComeOn! How TLS works?

第一步,服务器证明自己是靠谱的。

一个哥们儿XX说他是天地会的。如果你是韦小宝,你会怎么确认他的身份呢?

其中有一种方案可能是这样的:他会说S1是他师傅,如果你知道S1并和他确认了,就ok了。如果不认识,就继续问S1的师傅S2……一直问道陈近南,只要陈近南确认了,那就可以证明他了。看起来好像设计模式里面的责任链 XX -> S1 -> S2 -> … -> ROOT

服务器证明自己也是同样的逻辑,服务器S0有一个证书,说我是谁谁谁,这个证书由上级签发机构S1核准,如果你本地有这个S1的证书,那验证一下就可以了。如果没有,就问S1的签发机构S2。直到根的签发机构。如果本地认证找到了其中任何一级的证书,就认为S0是靠谱的。否则就是不靠谱。S0 -> S1 -> S2 -> … -> Root CA

实际上非常像工商局发的营业执照,你上面有我盖的红坨坨才是靠谱的。

上图就是淘宝的认证级联关系。

这些靠谱的证书内置在操作系统、jdk等地方(百度或者谷歌上搜索“https数字证书设置”相关内容就可以看到)。

此图就是我本机证书列表的一部分。

这个就是基本逻辑,说白了,就是找一个我们都公认靠谱的人来证实你的靠谱。

第二步,协商加密算法+密钥。

加密和摘要算法有很多,常见的比如RSA、AES、DES、MD5、SHA等等。

大家把他们这样来分:

1、加密/解密算法:能加密同时能反解的,就是加解密算法。按照加解密的密钥是否一样,又分为对称和非对称算法。比如对称加密算法:AES、DES;非对称加密算法:RSA。

2、摘要算法:就是只用来做摘要、签名、验证防止被别人篡改,基本不能反解(有可能可以通过碰撞暴力破解)。比如:MD5、SHA。

那服务器和客户端接下来就协商一下,我们要用什么加密解密算法和密钥防止别人看见,用什么摘要算法,防止别人篡改。

一般来讲,对称加密算法效率会比非对称高,所以通常选择对称加密的AES较多。双方通过某种方式协商出一个密钥,后面就通过这个密钥和加密算法进行加解密。

客户端发送一个:“地振高冈,一派溪山千古秀”

服务端回复一个:“门朝大海,三河合水万年流”

整个过程大体就是这样,后面双方就开始发HTTP的加密包,对方解包得到对应的HTTP数据。

世界一下就清晰了,对吗?

No No No 其实还是很复杂滴…… 如果要想了解详细的技术内容,就让我带着你继续往下看(你敢不敢跟我来)

===技术篇的分割线===

工欲善其事,必先利其器

为了做详细的分析,我做了几个准备工作:

1、装了一个wireshark,用来抓取网络包

2、写了一个java程序,打开debug运行(java -Djavax.net.debug=all TestHttps),用来看交互细节

import java.net.URL;

import java.net.URLConnection;

public class TestHttps

{

public static void main(String[] args) throws Exception

{

final URL url = new URL("https://www.taobao.com");

final URLConnection conn = url.openConnection();

conn.connect();

}

}

3、找到openjdk源代码:http://grepcode.com/

通过前两个工作可以看到网络交互的过程和详细的数据包,第三个可以用来分析整个流程的代码。

(注:以下涉及到代码的分析,都是基于JDK8进行的,如果因为版本原因,相关函数和代码行数对接不上,请大家查找对应版本的代码)

好了,准备工作做好了,我们开始吧!

抓个包,先看看门道

先给taobao同学发个请求吧:curl https://www.taobao.com,看到整个交互过程大体是这样的(我把tcp三次握手,ACK包等无关的数据包都过滤掉了,只剩TLS相关的数据包):

上图有几个交互数据都合并到一个TCP包进行发送了,比如漂蓝的那一行(No = 49)的TCP包实际上包含了三个TLS包(Certificate、Server Key Exchange、Server Hello Done),下面分析的时候,我就把这个包展开。

Client Server

Client Hello ->

<- Server Hello

<- Certificate

<- Server Key Exchange

<- Server Hello Done

Client Key Exchange ->

Change Cipher Spec ->

Encrypted Handshake Message ->

<- Change Cipher Spec

<- Encrypted Handshake Message

Application Data ->

<- Application Data

Encrypted Alert ->

上面抓的包全部展开就是这样的效果。怎么样,是不是差不多也看了个大概?我来翻译翻译吧。

Client Server

Client Hello你好!

Server Hello嗯,你好!

Certificate我的证书给你,验证我吧

Server Key Exchange这是我给你的加密密钥相关的东东

Server Hello Done好,我说完了

Client Key Exchange这是我给你的加密密钥相关的东东

Change Cipher Spec准备转换成密文了哦

Encrypted Handshake Message%……&*4 (密文思密达)

Change Cipher Spec我也转换密文了

Encrypted Handshake Message#%&……* (密文思密达)

Application Data%&¥&%*……(HTTP密文数据)

Application Data**……&%(HTTP密文数据)

Encrypted Alert警告(实际就是说完了,拜拜~)

看起来是不是很简单呢?

这实际上就是文章一开始,我说的要解决的两个大问题:

1、认证server端的靠谱性

2、交换加密算法和密钥

具体每个包里面都发了哪些数据?server端靠谱性是如何来证明的?加密算法和密钥是怎么交换的?接下来让我一一给你道来。

具体的交互流程和代码的实现

我们就按命令逐个来分析一下。

C:Client Hello

可以看到发送了很多数据,但是最关键的几个数据:

1、TLS的版本

2、随机数:这个是用来生成最后加密密钥的影响因子之一,包含两部分:时间戳(4-Bytes)和随机数(28-Bytes)

3、session-id:用来表明一次会话,第一次建立没有。如果以前建立过,可以直接带过去。

4、加密算法套装列表:客户端支持的加密-签名算法的列表,让服务器去选择。

5、压缩算法:似乎一般都不用

6、扩展字段:比如密码交换算法的参数、请求主机的名字等等

这一段的java实现,是在sun.security.ssl.HandshakeMessage.ClientHello里面:

S:Server Hello

当服务器收到客户端的问候以后,立即做出了响应:

大体内容和客户端差不多,只是把加密算法的套装列表换成了服务器选择支持的具体算法。

通过这一步,客户端和服务器就完成了加密和签名算法的交换。这里的TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256拆分开看就是:TLS协议,用ECDH密钥交换算法交换对称加密密钥相关的参数,用RSA算法做签名,最后使用AES_128_CBC做内容的对称加密,SHA256做摘要。

具体实现在:sun.security.ssl.HandshakeMessage.ServerHello

S:Certificate

这一步很关键,是服务器给客户端展示证书的时候。

上一篇 下一篇
music cover

歌曲名称

作者

00:00/00:00

歌名 歌手 时长