Http 遇上 Websocket 协议

http://mp.weixin.qq.com/s/IbBBVTtFR9Hd3crna0sYPw

HTTP是一个基于TCP/IP通信协议来传递数据

HTTP 1.1 做了哪些升级:

  • 缓存处理

    引入了更多可供选择的缓存头来控制缓存策略

  • 带宽优化及网络连接的使用

    HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。

  • 错误通知的管理

    在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

  • Host头处理

    HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。

  • 长连接

    HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

如何建立连接(三次握手)

  • 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

  • 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

  • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

完成三次握手,客户端与服务器开始传送数据。

如何关闭连接(四次挥手):

  • 客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。

  • 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。

  • 服务器B关闭与客户端A的连接,发送一个FIN给客户端A。

  • 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。

TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。

在讲HTTP/2之前我们先来说说SPDY

SPDY协议是一种更加快速的内容传输协议

HTTP/2 的主要目标是改进传输性能,更有效地利用网络资源,实现低延迟和高吞吐量。

HTTP/2 是如何提高效率呢?

  • 二进制分帧:HTTP 2.0 的所有帧都采用二进制编码

  • 多路复用 (Multiplexing)

  • 请求优先级

  • header压缩

    HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP/2使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

服务器推送到底是什么?

服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。

  • HTTP/1.0 一次请求-响应,建立一个连接,用完关闭;每一个请求都要建立一个连接;

  • HTTP/1.1 Pipeling解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞;

  • HTTP/2多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行;

    多路复用允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。有了新的分帧机制后,HTTP/2 不再依赖多个TCP 连接去实现多流并行了。每个数据流都拆分成很多互不依赖的帧,而这些帧可以交错(乱序发送),还可以分优先级。最后再在另一端把它们重新组合起来。HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个连接)即可。

通常所说的web缓存实际上更多的指的是http的缓存,当然还有浏览器本身自己的缓存机制。

总结起来,就是三个方面:缓存的存储策略,缓存的过期策略,缓存的刷新策略。

  • 缓存存储 (用来确定http的响应内容是否可以被客户端存储)

    关键的属性Cache-Control,max-age:缓存的时间,相对时间,从请求时间到过期时间的间隔,单位是秒

  • 缓存过期 (我特么怎么知道什么时候该请求,什么时候该从本地缓存拿数据?)

    Expires 属性控制,但是cache-control里面的东西永远都是优先级高的,换句话说,如果max-age设置了,Expires 设置了也白搭。

  • 缓存刷新

    你真的过期了吗?请求的内容真的有变化吗? 对于是否真的过期,客户端会给服务端一个标识last-modified-since,通过时间的对比去判断是否真的过期。 对于数据是否改变,客户端会带过来一个字段if-none-match,每一次服务端都会有一个对应Etag字段,对比两个字段的值去判断实体数据是否发生了变化从而决定要不要返回给客户端数据。

https的技术

  • 加密技术

    主要用到以DES为代表的对称加密算法和以RSA为代表的非对称加密算法,对称加密算法一般很难破解,但是不太好保管,安全性也不是很高,为啥呢?因为客户端和服务端拿到的密钥是一样的,不可能每次都把key给改了,而不改的话,一直用同一个key的话也会存在安全隐患。因此https的加密的方式采取的是混合方式。交换密钥的时候采取非对称的,建立通信交换报文的时候采取对称加密的方法。

  • 身份验证技术

    就是用公钥生成可信赖的证书。因为非对称加密存在一个问题就是没法验证拿到的公钥就是服务端公开的公钥。为了解决以上问题,CA应用而生(Certifity Authority),数字证书认证机构。

CA的使用流程:

  • 相关人去CA机构进行公钥申请。
  • CA机构会验证申请者的信息真实性,合法性。
  • 通过审核后,CA机构会做数字签名,给其证书。证书里面包含申请者的信息,数字签名后的公钥,有效时间和签名。
  • 客户端https建立连接的时候像服务端要证书。
  • 读取证书信息,拿公钥进行解密校验。
  • 客户端会内置CA的信息,如果不存在或者信息不对,证明CA非法。

备注:遵循私钥永远都是服务端一方掌握。


关于Https那些事

下面知识点的参考链接:

http://mp.weixin.qq.com/s/E75toyRukUHEtt34-snEgQ

Https是一种通过计算机网络进行安全通信的传输协议。Https经由Http进行通信,但利用TLS来加密数据包,Https的主要目的是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。

HTTPS相对HTTP提供了更安全的数据传输保障。主要体现在三个方面:

  • 内容加密

    客户端到服务器的内容都是以加密形式传输,中间者无法直接查看明文内容。

  • 身份认证

    通过校验保证客户端访问的是自己的服务器。

  • 数据完整性

    防止内容被第三方冒充或者篡改。

Https实现原理

1,什么是对称加密?

即加密和解密使用同一个密钥,由于对称加密需要在网络上传输密钥和密文,一旦被黑客截取很容易就能被破解,因此对称加密并不是一个较好的选择。 

2,什么是非对称加密?

即加密和解密使用不同的密钥,分别称为公钥和私钥。我们可以用公钥对数据进行加密,但必须要用私钥才能解密。在网络上只需要传送公钥,私钥保存在服务端用于解密公钥加密后的密文。但是非对称加密消耗的CPU资源非常大,效率很低,严重影响HTTPS的性能和速度。因此非对称加密也不是HTTPS的理想选择。    

3,那么HTTPS采用了怎样的加密方式呢?

其实为了提高安全性和效率,HTTPS结合了对称和非对称两种加密方式。即客户端使用对称加密生成密钥(key)对传输数据进行加密,然后使用非对称加密的公钥再对key进行加密。因此网络上传输的数据是被key加密的密文和用公钥加密后的密文key,因此即使被黑客截取,由于没有私钥,无法获取到明文key,便无法获取到明文数据。所以HTTPS的加密方式是安全的。    

我们以TLS1.2为例来认识HTTPS的握手过程

  • 客户端发送 client_hello,包含一个随机数 random1。

  • 服务端回复 server_hello,包含一个随机数 random2,携带了证书公钥 P。

  • 客户端接收到 random2 之后就能够生成 premaster_secrect (对称加密的密钥)以及 master_secrect(用premaster_secret加密后的数据)。

  • 客户端使用证书公钥 P 将 premaster_secrect 加密后发送给服务器 (用公钥P对premaster_secret加密)。

  • 服务端使用私钥解密得到 premaster_secrect。又由于服务端之前就收到了随机数 1,所以服务端根据相同的生成算法,在相同的输入参数下,求出了相同的 master secrect。

HTTPS的工作原理,通过对称加密和非对称加密实现数据的安全传输。我们也知道非对称加密过程需要用到公钥进行加密。那么公钥从何而来?其实公钥就被包含在数字证书中。数字证书通常来说是由受信任的数字证书颁发机构CA,在验证服务器身份后颁发,证书中包含了一个密钥对(公钥和私钥)和所有者识别信息。数字证书被放到服务端,具有服务器身份验证和数据传输加密功能。

Android系统中已经内置了所有CA机构的根证书,也就是只要是CA机构颁发的证书,Android是直接信任的。对于此种情况,虽然可以正常访问到服务器,但是仍然存在安全隐患。假如黑客自家搭建了一个服务器并申请到了CA证书,由于我们客户端没有内置服务器证书,默认信任所有CA证书(客户端可以访问所有持有由CA机构颁发的证书的服务器),那么黑客仍然可以发起中间人攻击劫持我们的请求到黑客的服务器,实际上就成了我们的客户端和黑客的服务器建立起了连接。

如果我们服务器的证书是非认证机构颁发的 (例如12306)或者自签名证书,那么我们是无法直接访问到服务器的,直接访问通常会抛出如下异常:

javax.net.ssl.SSLHandshakeException: 
java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

网上很多解决SSLHandshakeException异常的方案是自定义TrustManager忽略证书校验。这样的处理方式虽然解决了SSLHandshakeException异常,但是却存在更大的安全隐患。因为此种做法直接使我们的客户端信任了所有证书(包括CA机构颁发的证书和非CA机构颁发的证书以及自签名证书)

最简单的解决方案就是在客户端内置服务器的证书,我们在校验服务端证书的时候只比对和App内置的证书是否完全相同,如果不同则断开连接。那么此时再遭遇中间人攻击劫持我们的请求时由于黑客服务器没有相应的证书,此时HTTPS请求校验不通过,则无法与黑客的服务器建立起连接。

首先从访问的服务器网站下载签名证书,并放置到我们项目资源目录raw下。然后根据证书构造SSLSocketFactory。

上面讲到的都是单向认证,对于HTTPS双向认证,用到的情况不多。但是对于像金融行业等对安全性要求较高的企业,通常都会使用双向认证。所谓双向认证就是客户端校验服务器证书,同时服务器也需要校验客户端的证书。因此,双向认证就另需一张证书放到客户端待服务端去验证。

单项认证保证了我们自己的客户端只能访问我们自己的服务器,但并不能保证我们自己的服务器只能被我们自己的客户端访问(第三方客户端忽略证书校验即可)。那么双向认证则保证了我们的客户端只能访问我们自己的服务器,同时我们的服务器也只能被我们自己的客户端访问。因此双向认证可以说相比单项认证安全性足足提高一个等级。

private 表示当前响应是针对单个用户的,并非通用数据,因此不建议任何中间缓存对其进行缓存。

我们应该将响应数据尽可能多的缓存,尽可能的缓存足够长的时间,并且为每个资源提供单独的数据验证令牌,以便在时间过期之后快速校验。

1,严格不使用缓存:

Cache-Control:no-store

2,允许客户终端缓存,但是每次使用都需要确认

Cache-control:no-cache

ETag: "cxmyDev1234"

(ETag是数据验证令牌,通常就是返回数据的Hash值或者其他数据指纹,它是当前数据的一个唯一标识)

3,允许客户终端短时间缓存

Cache-Control:private max-age=600

ETag: "cxmyDev1234"

对于更新频率比较低的数据内容,我们可以适当的将max-age调大


编码压缩

1,请求头中的 Accept-Encoding

指定当前客户端支持的压缩编码

2,响应头中的 content-encoding

服务端对内容压缩使用的编码格式,同时还会修改 Content-Length 来明确表示当前实体被编码压缩后的长度

Content-Encoding 就是用这些标准化的代号来说明编码使用的算法。

比较常用的算法有:

  • gzip:表明实体采用 GNU zip 编码。

  • compress:表明实体采用 Unix 的文件压缩程序。

  • deflate:表明使用是用 zlib 的格式压缩的。

  • br:表明实体使用 Brotli 算法的压缩格式。

  • identity:表明没有对实体进行编码,为默认值。

浏览器的默认实现中,这些压缩编码通常只会作用在文本内容上,就是 Content-Type 为 text/Xxx 的请求上,而对于一些媒体文件,则不会使用这种方式对其进行压缩。


GET与POST请求方式的区别:

  • GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),POST把提交的数据则放置在是HTTP包的包体中。

  • GET的URL会有长度上的限制,则POST的数据则可以非常大。

  • POST比GET安全,因为数据在URL上不可见,非明文传输。

  • GET传输的数据量非常小,一般限制在 2 KB 左右,但是执行效率却比POST好;而POST方式传递的数据量相对较大,它是等待服务器来读取数据。

results matching ""

    No results matching ""