文章目录
几个HTTP协议
HTTP协议是web应用中最基础的协议之一。当前关于HTTP最多的关键词就是:
- HTTP
- HTTPS
- HTTP2
HTTP不用说了,后面两个是什么东西?
HTTPS
HTTPS是搞什么事的
先来说说HTTPS。Web应用都是基于HTTP协议来做数据交换的,但是,在网络这个险恶的环境里,总是有那么一些人想要折腾一点事,正应了那句话:“总有刁民想害朕”。
在HTTP协议的数据,基本上可以说是裸奔的,用抓包工具很容易的发现HTTP包里面的数据。为了安全起见,自然就有人出来解决这个问题,对于数据安全或者说网络安全问题,主要是要解决下面几个事情:
- 窃听风险(eavesdropping):第三方可以获知通信内容。
- 篡改风险(tampering):第三方可以修改通信内容。
- 冒充风险(pretending):第三方可以冒充他人身份参与通信。
那么,HTTPS是怎么解决这三个问题的呢?答案就是SSL/TLS协议。
SSL/TLS协议
从网络协议层来看:
这个协议的内容,阮一峰大佬的文章讲的非常清楚,搬运过来:
SSL/TLS协议
里面涉及到的几个概念:
-
加密算法:主要用于解决窃听风险:避免被他人窃听,收到数据后无秘钥无法获知通信内容。又分为了对称加密和非对称加密。
对称加密的话就是加密和解密的秘钥相同
非对称加密就是加密和解密的秘钥不同,就引出另外两个概念:公钥 & 私钥
主要的加密方法,这样的科普知识直接搬运:
主要加密算法 -
算法用途1:数字签名/数字证书。在通信加密问题中,生成秘钥后,如何保证秘钥是安全的交换也是一个关键的问题,如何保证我接收到的东西就是对方提供的,而不是恶意的第三方截获之后再给的呢?也就是未被篡改,未被冒充。这就是数字签名能起到的作用了,或者叫做数字证书。
为了解决冒充风险,确认第三方身份,可以将身份信息签名。
而数字签名,是对某些信息形成一个整体的信息摘要,从而保证不可篡改。如果篡改,对方秘钥无法正常验证,从而识别出信息被篡改。 -
算法用途2:内容加密。这个很好理解,就是把原文加密成看不懂的东西,没有秘钥的人拿了也不知道是什么内容。
-
会话秘钥。为了解决非对称秘钥的计算复杂度,减少每次通讯的性能损耗,至于为什么非对称秘钥费时,我也不清楚,有兴趣的去翻翻密码学的书吧。
SSL/TLS协议的4次握手协议,主要就是安全的生成一个会话秘钥并保存在通讯的两端。
而SSL/TLS通讯结束后,后续的HTTPS协议就是使用这个会话秘钥来进行数据加密和传输。
HTTPS和HTTP几个不同点
详细的HTTPS的内容可以参考RFC2818。
列一下HTTPS和HTTP一些主要的不同点:
- HTTPS需要CA(Certificate Authority,数字证书认证机构) 申请证书,免费的很少
- HTTP默认80端口,HTTPS默认443端口
- HTTP使用http标识符,HTTPS使用https标识符
- HTTP是明文传输;
- HTTPS是加密传输
- HTTP响应比HTTPS快,因为HTTPS还需要TSL握手,所以HTTPS更耗费服务器资源
express创建https服务器
上面的描述里提到了,HTTPS层用的是SSL/TLS层协议。而这一层的协议需要有一对秘钥:公钥 + 私钥来建立安全的链接,并且生成会话秘钥来保证后续HTTPS协议的数据传输。
在SSL的握手过程中,服务器会返回除了用于加解密用的公钥以外,还有一些其他的信息:网站地址,认证等信息,这些信息放一起就形成了证书。
浏览器获得网站证书之后浏览器要做验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示。
那么,浏览器根据什么来确定哪些是受信的,哪些是不受信的呢?你说行就行?那是不可能的。互相不相信的情况下怎么办呢?那么就有一个叫CA(Certificate Authority,授权中心)的三方结构进来。每个提供服务的人来我这注册,把你的服务名(网站域名)和主体关键信息和公钥告诉我。我给你提供证明(证书),再用CA的数字签名给你签个名,妥了,你有了介绍信,也就是有身份的人了。大家就都认可你了,当然你定期还是得来CA报个到(证书有效期)。
一个CA忙活不过来的时候,CA(root CA)也可以给其他的分支CA授权,分支的CA再进行证书授权,也是可以的。
当前如果需要在web上发布自己的https服务,都是需要去想第三方CA注册证书的,都是收费的。
我们这只是想在局域网内弄一个,就不付费了。
生成证书
express创建https服务
我们用linux自带的openssl工具来生成这样一个证书:
// 生成服务器端私钥
openssl genrsa -out server.key 1024
//生成服务端公钥
openssl rsa -in server.key -pubout -out server.pem
//生成CA私钥
$ openssl genrsa -out ca.key 1024
//生成csr文件
$ openssl req -new -key ca.key -out ca.csr
//生成自签名证书
$ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
//生成server.csr文件,把自己的私钥放到csr申请文件中
$ openssl req -new -key server.key -out server.csr
//生成带有ca签名的证书,用CA的私钥为某台服务器的server.csr签名,把CA自己的CRT证书带进去。CA也得为自己证明
$ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
最终生成一堆的文件:
ca.key:认证中心的私钥
ca.csr:认证中心的证书信息文件,用于申请证书
ca.crt:认证中心用私钥签名过的信息文件
我们自己搞了一个CA,所以自己生成一些这样的文件。
server.key:服务器的私钥
server.csr:服务器的证书信息文件,用于申请证书
server.crt:认证中心用认证中心的私钥签名过的信息文件,服务器用这个证书对外提供服务
server.pem:服务器私钥对应的公钥
在生成csr文件,也就是注册信息文件的时候,openssl会要求你填写一些信息,就是把这些也会写入到证书里:
反正是假的,一路回车就好。
express代码
新建一个app.js
var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
//同步读取密钥和签名证书
var options = {
key:fs.readFileSync('./keys/server.key'),
cert:fs.readFileSync('./keys/server.crt')
}
var app = express();
var httpsServer = https.createServer(options,app);
var httpServer = http.createServer(app);
app.get('/',function(req,res,next){
res.send('Hello Express+https');
});
//https监听3000端口
httpsServer.listen(3000);
//http监听3001端口
httpServer.listen(3001);
选择Accept the Risk and Continue就可以看到界面了。
如果是用express脚手架搭的程序的话,
直接改bin/www的文件就可以了,主要和http服务器的监听端口分开。
HTTP和HTTPS的关系
我自己的理解,HTTPS = HTTP + SSL/TLS。因为HTTP和HTTPS的协议格式是一样的,只是协议体里面的内容加密和没加密的区别。
HTTP2
现在大部分的网站和浏览器都还是运行在HTTP1.X的基础上:
chrome浏览器的开发者工具中:
Network => XHR,选择其中一个
而现在支持HTTP2的网站很少,我这也只是先了解一下HTTP2到底有些啥东西。
先了解一下HTTP发展历史:
先来看看HTTP2的设计目标(从官网GITHUB摘录):
HTTP/2 is a replacement for how HTTP is expressed “on the wire.” It is not a ground-up rewrite of the protocol; HTTP methods, status codes and semantics are the same, and it should be possible to use the same APIs as HTTP/1.x (possibly with some small additions) to represent the protocol.
The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.
也就是说HTTP2主要是为了解决HTTP的一些性能问题,而且提到了非常重要的一点就是多路复用(allow the use of a single connection from browsers to a Web site)。
下面的图都是从官网中摘录。
HTTP2 Frame
HTTP2中设计了一种新的数据类型:Frame
和HTTP 1.x不一样。HTTP2中的request和response都是由多个Frame组成。Frame有不同的类型:
HTTP2链接
http协议是一个无状态的协议,所以它不维护链接,而底层的协议是TCP。TCP是一个有状态的协议。
- 在HTTP/1.0中,TCP链接会断开,除非设置Connection: keep-alive。也就是说每次http请求都要新建一个TCP的有链接协议,会消耗服务端的资源,也会增加请求时间。
- HTTP/1.1不会断开,不会再次进行初始化连接和SSL,除非设置Connection: Close。在HTTP1.1中就反过来,默认不会断开,除非你显式指定断开。
- 从HTT2的描述来看:In HTTP/2, each endpoint is required to send a connection preface as a final confirmation of the protocol in use and to establish the initial settings for the HTTP/2 connection. The client and server each send a different connection preface。HTTP也是想转变成一个带链接的协议。维护自己协议层的链接。
- HTTP2创建了Stream的概念,从描述上看,HTTP2会是一个带链接,有序的协议(感觉HTTP1和HTTP2的区别会是UDP与TCP的区别)。这些链接都基于同一个TCP链接来建立
多路复用
基于上面的内容,浏览器可以把一个消息拆成不同的DATA Frame,用同一个HEADER Frame,在不同的Stream中发送,而Stream的时序性保证了这些Frame会有序抵达,那么就相当于解除了一个大的HTTP请求(一般可能是POST)只能在同一条链接中发送的限制,使得所有的请求和响应多路复用。通过允许客户端和服务端把HTTP消息分解成独立的帧,交错传输,然后在另一端组装。
服务器推送
因为HTTP2有了Stream的概念,就可以摆脱请求-响应的这个限制(只有谁请求了,服务器才知道响应给谁,没有保持上下文信息,不能主动发起数据传输)。服务器就可以主动推送一些资源到客户端,客户端就可以提前异步加载,减少网络请求时间。
头信息压缩
就是引入了一些编码方式,将头部的一些信息进行压缩和解压缩(cookies/localStorage),多了的话还是挺大的。
总的来说,我觉得HTTP2相较于HTTP1.x,改动还是挺大的,从一个无状态的协议转成了一个有状态保持和链接的协议。