最近学了些HTTP相关的内容,做了些笔记,深入了解TLS后感觉密码学挺有意思。

关于TCP/IP的内容链接

HTTP

HTTP/0.9

  • 这是后来回来定义的版本,这个初始版本采用纯文本格式
  • 只有GET动作,在响应请求后立即关闭连接,功能非常有限

HTTP/1.0

  • 1996年发布,与1.1差不了多少了
    1. 增加了HEADPOST等方法
    2. 增加响应状态码,标记可能的错误原因
    3. 引入协议版本号概念
    4. 引入了Header头部的概念
    5. 传输的数据不再仅限于文本
  • 但是1.0并不是一个标准,只相当于一个备忘录(参考文档)

HTTP/1.1

  • 1999年,发布RFC文档编号2616,是个正式的标准
    1. 增加了PUTDELETE等方法
    2. 增加了缓存管理和控制
    3. 明确了连接管理,允许持久连接
    4. 允许响应数据分块(chunked),利于传输大文件
    5. 强制要求Host头,让互联网主机托管成为可能
HTTP请求报文格式

  • 请求方法 | URL | 协议版本
  • Header头部(一行一个字段,key-value,中间冒号分隔)
  • 空行
  • 请求包体(GET没有,POST用)(GET也可以填body,服务端不一定处理)
HTTP响应报文格式

  • 协议版本 | 状态码 | 状态码描述
  • Header头部(一行一个字段,key-value,中间冒号分隔)
  • 空行
  • 响应包体
常见的Header
  1. Accept-Charset: 数据编码格式
  2. Content-Type: 数据的类型
  3. Cache-control:max-age,客户端的话就是希望多新的缓存,服务端的话就是告诉客户端某个时间段内的数据都是最新的
  4. If-Modified-Since:如果服务器的资源在某个时间之后更新了,那么客户端就应该下载最最新的资源;如果没有更新,服务端会返回304 Not Modified的响应,那客户端就不用下载了
  5. Retry-After:告诉客户端应该在多长时间以后再次尝试一下
  6. Connection:一般是keep-alive,用来保活TCP连接,close的话就是传输完后就关闭TCP连接
  7. Referer:客户端告诉服务端我是从哪个链接来的,服务端收到后可以做处理,重定向,或者用于支付后的回调(微信支付)
  8. User-Agent:老生常谈,操作系统和浏览器名称版本,很多骚操作
一些特点
  1. 一般POST时,先发送header,服务器响应 100 Continue 后,浏览器再发送Data,服务器响应 200 OK,可能分两个TCP包
  2. header是key-value,中间冒号分隔
  3. HTTP即超文本传输协议 HyperTextTransferProtocol, 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范
  4. HTTP没有实体,不是互联网,不是语言,不是HTML,不是孤立的协议。
  5. HTTP是基于TCP的,TCP的重传HTTP不知道
  6. 由于有Keep-Alive机制,每次HTTP连接无需TCP重新握手

HTTP/2.0

  • HTTP2.0通过头压缩、分帧、多路复用等技术提升性能

  1. SPDY是谷歌推出的,HTTP2.0基于此制定
  2. HTTP2.0对header压缩,用索引表替代key-value,将一个TCP连接中切分多个流。
    • 每个流有自己ID,流是双向的虚拟通道,流有优先级。2.0还将所有信息分割为帧。
    • 有header帧和data帧,用二进制编码,多个data帧属于同一个流。
    • 这样可以将多个请求分到不同的流中,将请求内容拆成帧,进行二进制传输。
    • 帧可以打散乱序发送,然后根据每个帧首部的流标识符重新组装,并根据优先级决定先处理哪个流。
    • HTTP2.0其实是将n个请求变成n个流,将数据分成帧,乱序发送到一个TCP连接中。
    • 这样2.0解决了1.1的队首阻塞问题。1.1通过pipeline用多条TCP实现并发,2.0只用1个TCP实现并发,提高性能。
    • 但HTTP2.0还是基于TCP的,TCP处理包时有严格顺序,前面流2的帧没收到,后面流1的帧也会阻塞

QUIC

  • QUIC是谷歌基于UDP改进的应用层,未来HTTP3.0可能基于此实现,解决HTTP2.0的问题,QUIC也是面向连接的。
  • QUIC自定义类似TCP的连接、重试、多路复用、流量控制技术,进一步提升性能

  1. 机制1:自定义连接

    • 一条TCP连接是四元组(源IP和端口,目标IP和端口)标识的,一旦一个元素变化就需要断开重连
    • 移动互联经常不稳定、切换,都会导致重连,又三次握手,时延高
    • 而基于UDP的QUIC自己用64位随机数作为标识替代四元组,而且UDP是无连接的
    • 当前述的四个元素变化时,不用重新建立连接
  2. 机制2:自定义重传机制

    • TCP有通过采样往返时间RTT的自适应重传算法,但是这种采样不准确。
    • QUIC也有递增序列号,任何一个包重发序列号都+1,不像TCP重发包还是原来的序号。
    • 这样超时采样就准了,但是如何知道重发的包内容与前一个一样呢
    • QUIC在数据流里定义了offset,可以通过offset查看数据发送到了哪里
    • 只要某个offset没到就重发,按照offset拼接成一个流,相当于多设一个参数处理流的顺序。
  3. 机制3:无阻塞的多路复用

    • 跟2.0一样,同一条QUIC上可以创建多个流来发送HTTP请求
    • 但因为基于UDP,一个连接上的多个流之间没有依赖
    • 假如流2丢了一个UDP包,后面跟着流3的一个UDP包,虽然流2的包需要重传,但流3的包无需等待,而TCP就会阻塞
  4. 机制4:自定义流量控制

    • TCP的流量控制是通过滑动窗口协议,QUIC也是通过window_update来告诉对方自己可接受的字节数
    • 但QUIC的窗口是适应自己的多路复用机制的,不但在一个连接上控制窗口,每个流也有控制窗口
    • TCP里接收端的窗口起始点是下一个要接收并且ACK的包,即便后来的包都到了放在缓存里,窗口也不能右移
    • 只要前面的包没到,后面的到了也不能ACK,就会导致后面的到了也可能超时重传,浪费带宽。
    • QUIC的ACK是基于offset的,每个offset的包到了进了缓存就可以应答,应答后就不用重发,再继续等中间的包即可
    • QUIC窗口的其实位置为当前收到的最大offset,从这个offset到当前流所能容纳的最大缓存才是真正的窗口
    • 另外还有整个连接的窗口,需要对所有流的窗口做一个统计

关于HTTP的队首阻塞

  1. HTTP/1.0对于同一个tcp连接,所有的请求放入队列中,只有前一个请求的响应收到了,然后才能发送下一个请求。可见,HTTP/1.0的队首组塞发生在客户端。

  2. HTTP/1.1对于同一个tcp连接,HTTP/1.1允许一次发送多个请求,也就是说,不必等前一个响应收到,就可以发送下一个请求,这样就解决了HTTP/1.0的客户端的队首阻塞。但服务端响应的发送要根据请求的顺序排队发送,如果前一个请求的处理时间长就会影响后面的响应发送。可见,HTTP/1.1的队首阻塞发生在服务器端。

  3. HTTP/2.0无论在客户端还是在服务器端都不需要排队,在同一个TCP连接上,有多个stream,由各个stream发送和接收请求,各个steam相互独立,互不阻塞。只要TCO没有人在用那么就可以发送已经生成的requst或者reponse的数据,在两端都不用等,从而彻底解决了HTTP协议层面的队首阻塞问题。

HTTPS

建立连接过程

  1. 开始连接时,客户端用服务端的公钥加密发送,服务端用客户端的公钥加密回应
  2. CA证书里有公钥,CA是递归的最后有几个大的rootCA,先用非对称加密获取密钥,然后用对称加密传输数据,TLS/SSL
  3. HTTPS握手过程:(c是客户端,s是服务端)
    • c发送 Client Hello 给s,明文传输TLS版本、加密套件候选列表、压缩算法候选列表等以及一个随机数A
    • s返回 Server Hello 给c,声明选择使用的协议版本、加密套件、压缩算法等以及一个随机数B
    • s发送 Server Certificate 给c,然后再发送 Server Hello Done,说明发送信息就这么多了,结束
    • c校验前一步s给的证书,从自己信任的CA仓库中拿CA证书的公钥取解密s的证书,过程中可能需要往上追溯CA、CA的CA等
    • c发送 Client Key Exchange,内含生成的一个随机数C:Pre-master,用s证书的公钥加密,发送给s,s可以通过自己的私钥解密出来(Pre-master是RSA加密的说法,DH加密需要 DH exponent
    • 现在,c和s都有了三个随机数,分别是自己的、对方的、Pre-master,通过这三个随机数,c和s能生成相同的对称密钥
    • c发送 Change Cipher Spec 通知s采用协商的通信密钥和加密算法进行对称加密通信
    • c发送 Encrypted Handshake Message 将先前商定好的参数采用协商密钥加密,发送给s用于数据与握手验证
    • s发送 Change Cipher Spec 回应c采用协商的通信密钥和加密算法进行对称加密通信
    • s发送 Encrypted Handshake Message 将先前商定好的参数采用协商密钥加密,发送给c用于数据与握手验证
    • 双方转而使用对称加密通信,握手完成,除了以上过程,其余过程与HTTP一样
  4. 上面是HTTPS单向验证,只是c验证了s的证书,是大部分的场景,也可以在更加严格安全要求的情况下,启用双向验证,互验证书
  5. 重放与篡改攻击:自定义的:通过Timestamp和Nonce随机数联合起来做不可逆签名来保证。
  6. 为什么不直接用非对称加密通信?
    • 非对称加密的加密的内容不能超过公钥长度,所以只能用来作密钥交换或者内容签名
    • 性能问题,对称加密是毫秒级,非对称是秒级,HTTPS握手过程的90%时间都在解密RSA
  7. 除了Premaster外还需要两个随机数的原因是TLS不信任每个客户端都能产生安全的随机数,所以引入多两个随机数

SSL/TLS

  1. TLS即SSL升级版,18年推出TLS1.3,目前(19年)用TLS1.2和1.3的都不少,SSL早就废弃了
  2. 对称加密算法有:AESDES3DES,非对称加密算法有:RSAECDHE
  3. TLS中上面将两个随机数和Premaster计算成对称加密主密钥的算法是PRF算法(SHA256)
  4. TLS是在传输层(TCPUDP层)之上,应用层(HTTP)之下的层,HTTPS其实就是在TCP和HTTP之间加了TLS层

  1. 握手的加密套件:例子:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256ECDHE密钥交换、RSA身份验证、AES算法、128加密强度、GCM加密模式、SHA256是MAC或者PRF
  2. 目前主流HTTPS的流量是使用ECDHE进行密钥交换、用RSA进行身份验证

TLS协议原理

  • 自顶向下、分层抽象,TLS大致在四层

    1. 最底层是基础算法原语的实现如AESRSAMD5SHA256ECDH
    2. 第二层是选定参数后,符合密码学里标准分类的算法,包括块加密算法,签名算法,非对称加密算法,MAC算法等,例如: aes-128-cbc-pkcs7rsaes-oaeprsassa-pkcs1-v1_5, hmac-sha256ecdsa-p256curve25519
    3. 第三层是把多种标准算法组合而成的半成品组件,例如:对称传输组件例如 aes-128-cbc + hmac-sha256,aes-128-gcm,认证密钥协商算法: rsassa-OAEP + ecdh-secp256r1,数字信封:rsaes-oaep + aes-cbc-128 + hmac-sha256 ,文件密码加密存储组件:pbkdf2+aes-128-cbc-hmac-sha256,密钥扩展算法 PRF-sha256
    4. 第四层是用各种组件拼装而成的各种成品密码学协议/软件,例如:TLS协议,SSH协议,SRP协议,gnupg文件格式,iMessage协议,bitcoin协议等等
  • 很多程序员自己造的轮子,往往说白了就是想重复实现第3层的某个组件而已。

TLS加密套件 (CipherSuite)
  • 从上述分层的角度看,TLS大致是由三个组件拼成的:

    1. 对称加密传输组件,例如aes-128-gcm;
    2. 认证密钥协商组件,例如rsa-ecdhe;
    3. 密钥扩展组件,例如TLS-PRF-sha256
  • 这些组件可以再拆分为5类算法,在TLS中,这5类算法组合在一起,称为一个CipherSuite

    1. authentication (认证算法)
    2. encryption (加密算法 )
    3. message authentication code (消息认证码算法 简称MAC)
    4. key exchange (密钥交换算法)
    5. key derivation function (密钥衍生算法)
  • TLS协议设计之初就考虑到了这每一类算法的演变,所以没有定死算法,而是设计了一个算法协商过程,来允许加入新的算法( 简直是软件可扩展性设计的典范!),协商出的一个算法组合即一个CipherSuite

  • 常见加密套件

加密算法分类

  • 上述第二层中的密码学算法常见有下面几类

    1. 块加密算法:AES(AES_128_GCM等)、Serpent
    2. 流加密算法:RC4ChaCha20
    3. 加密用哈希函数:MD5SHA1SHA256POLY1305
    4. 消息验证码函数:AEADHMAC-SHA256
    5. 密钥交换算法:RSADHECDHECDHE
    6. 公钥加密算法:RSA
    7. 数字签名算法:RSADSAECDSA
  • 设计一个加密通信协议的过程,就是自顶向下,逐步细化,挑选各类组件,拼装成完整协议的过程

AES加密算法

  1. 每个加密数据块大小固定为128位(16个字节),最后一块不满16字节的话需要用填充算法补齐
  2. 最终生成的加密密钥长度有128位、192位、256位三种
  3. 多种工作模式:ECBCBCCFB等,这块内容很多,后续补充

DES、3DES加密算法

  1. DES:

    • 每个加密数据块大小固定为64位(8个字节)
    • 生成的密钥长度为64位(其中8位用于校验(每个字节的第8位)),所以AES比DES安全
  2. 3DES:

    • 还是64位的加密数据块大小
    • 简单粗暴的 Triple DES,使用3个DES密钥(所以共192位,其中24位校验),对数据块(还是64位的小块)应用三次DES算法进行三次加密
    • 使用的3个密钥不是合并成1个密钥,而还是分成3个用,3DES加密时依次使用密钥1、密钥2、密钥3对明文数据块进行加密,解密过程反之亦然。
    • 每次加解密原理与DES一样

RSA加密算法

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的“非对称加密算法”。

  1. 公钥与私钥的产生

    • 假设Alice想要通过一个不可靠的媒体接收Bob的一条私人讯息。
    • 她可以用以下的方式来产生一个公钥和一个私钥:
    • 随意选择两个大的质数p和q,p不等于q,计算N=pq。
    • 根据欧拉函数,求得r =φ(N)=φ(p)φ(q)= (p-1)(q-1)
    • 选择一个小于 r 的整数 e,求得 e 关于模 r 的模反元素,命名为d。(模反元素存在,当且仅当e与r互质)
    • 将 p 和 q 的记录销毁。
    • (N,e)是公钥,(N,d)是私钥。Alice将她的公钥(N,e)传给Bob,而将她的私钥(N,d)藏起来。
  2. 加密消息

    • 假设Bob想给Alice送一个消息m,他知道Alice产生的N和e。
    • 他使用起先与Alice约好的格式将m转换为一个小于N,且与N互质的整数n
    • 比如他可以将每一个字转换为这个字的Unicode码,然后将这些数字连在一起组成一个数字。
    • 假如他的信息非常长的话,他可以将这个信息分为几段,然后将每一段转换为n。
    • 用下面这个公式他可以将n加密为c:
    • n^e ≡ c (mod N)
    • 计算c并不复杂。Bob算出c后就可以将它传递给Alice。
  3. 解密消息

    • Alice得到Bob的消息c后就可以利用她的密钥d来解码。她可以用以下这个公式来将c转换为n:
    • c^d ≡ n (mod N)
    • 得到n后,她可以将原来的信息m重新复原。
    • 解码的原理是 c^d ≡ n^(e·d)(mod N)
    • 已知e·d ≡ 1 (mod r),即e·d =1 +hφ(N)。由欧拉定理可得:
    • n ^(e·d) =n^ (1 +hφ(N))=n·((n^φ(N))^h)≡(n(1)^h)(modN) ≡ n (mod N)
  4. 签名消息

    • RSA也可以用来为一个消息署名。
    • 假如Alice想给Bob传递一个署名的消息的话,那么她可以为她的消息计算一个散列值(Message digest)
    • 然后用她的私钥加密这个散列值并将这个“署名”加在消息的后面。
    • 这个消息只有用她的公钥才能被解密。
    • Bob获得这个消息后可以用Alice的公钥解密这个散列值
    • 然后将这个数据与他自己为这个消息计算的散列值相比较。
    • 假如两者相符的话,那么他就可以知道发信人持有甲的密钥,以及这个消息在传播路径上没有被篡改过。
  5. 实战例子

    • 通过一次简单实践更好的了解RSA
    • 假设p = 2,q = 5(p,q都是素数即可),则N = pq = 10;
    • 得到:r = (p-1)(q-1) = (2-1)(5-1) = 4;
    • 根据模反元素公式,可以得出,e·d ≡ 1 (mod 4),即e·d = 4n+1 (n为正整数);
    • 假设n=5,则e·d = 21,且e、d为正整数,并且e与r互质,则e = 7,d = 3;
    • 获得公钥和密钥:公钥为(N, e) = (10, 7),密钥为(N, d) = (10, 3);
    • 假设要传输的数字为2,通过公钥加密后为:(2^7)(mod 10) = 8;
    • 通过密钥解密:(8^3)(mod 10) = 512(mod 10) = 2,即获得结果;

ECDHE加密算法

  • 主要用于HTTPS中的密钥交换
  • ECDHE源自ECDHECDH即使用椭圆曲线加密技术(ECC)的 DH密钥交换(Diffie-Hellman)算法.
  • DH密钥交换算法,可以让交换双方在不共享任何秘密的情况下协商出一个密钥。ECC则是建立在基于椭圆曲线的离散对数问题上的密码体制,在相同的密钥长度下,其安全性比RSA更高。
  • ECDHE则是ECDHEphemeral version,它会为每次握手过程分配一个不同的DH key,从而提供前向安全性。实际上,在HTTP/2中允许使用的Cipher Suite必须采用具有前向安全性的密钥交换算法。

总结

  1. HTTPS实际就是在TCP层与http层之间加入了TLS/SSL来解决安全问题的。
  2. 在进行应用数据传输之前,TLS需要通过握手过程来协商安全通信所需的相关参数。
  3. 整个通信过程中主要用到散列、对称加密、非对称加密和证书等相关技术,来解决客户端与服务器数据传输中各种安全风险问题,从而达到保证整个通信过程的安全。

 评论

 无法加载Disqus评论系统,请确保您的网络能够正常访问。

©2019 派大星星星星

本站使用 Material X 作为主题 , 总访问量为 次 。