对http、https和代理的一些理解

2,501 阅读22分钟

目录解读:

  • 不同版本http?http的连接复用是什么?
  • http为什么不安全?https比http好在哪里,区别是什么?
  • 对称加密和非对称加密??
  • https怎么对http进行加密的? 如何转http为https?
  • 代理服务器?正向代理和反向代理,nginx、vpn?

先来两道面试题:

解析url:

合法的URL_牛客题霸_牛客网 (nowcoder.com)

协议为http(s)

// 首先URL结构一般包括协议、主机名、主机端口、路径、请求信息、哈希
// 而本题协议已给出为HTTP(S),使用正则匹配URL,核心步骤有:

// 首先必须是以http(s)开头并且可以不包含协议头部信息
// 主机名可以使用"-"符号,所以两种情况都要判断,包含"-"或不包含"-"
// 顶级域名很多,直接判断"."之后是否为字母即可
// 最后判断端口、路径和哈希,这些参数可有可无

// 开始符 ^
// 协议部分http(s)://        表示为((https|http|ftp|rtsp|mms)?:\/\/)
// 域名部分                  表示为(([A-Za-z0-9]+-[A-Za-z0-9]+|[A-Za-z0-9]+)\.)+
// 顶级域名com cn等为2-6位   表示为([a-zA-Z]{2,6})
// 端口部分                  表示为(:\d+)?, ?表示0次或1次
// 请求路径如/login          表示为 (\/.*)?
// 问号传参及哈希值如?age=1   表示为 (\?.*)?和(#.*)?
// 结束符 $

// http  ://  a.com  :  80   /news/detail   ?  id=1  #t1
// scheme     demain    port     path         query    hash
function checkURL(url){
    return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/.test(url)
}
console.log(checkURL('http://localhost.com')) // true

浏览器输入url后发生了什么?

重点!

(1). 解析URL:~(不合法给搜索引擎解析)

(2). 缓存判断:~(判断请求资源是否存于缓存?如果存在且没有失效则直接使用)

(3). DNS解析:~ (域名系统服务器解析域名和 IP 地址之间映射关系。判断有无该域名ip缓存)->(本地DNS服务器向各级域名服务器发起请求-详见RFC文档)

(4). 获取MAC地址:~(得到ip地址和主机MAC地址进行数据传输)

(5). TCP三次握手:~(确认双方连接,构造request发送请求)

(6). HTTPS握手:~(如果使用https协议,还需进行TLS四次握手进行通讯加密传输)

(7). 返回数据:~(服务端将response沿着request建立的连接向客户端发送数据)

(8). TCP四次挥手:~ (判断keep-alive?无则进行并断开双方连接)

(9). 页面渲染:~

  • 浏览器首先会根据html文件构建DOM树,根据解析到的CSS文件构建CSSOM树(GUI渲染线程)
  • 如果遇到script标签,则判断有无defer和async属性(前者要等到整个页面正常渲染结束,才会执行(onload);后者一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染),因为js引擎线程与GUI渲染进程是互斥的,script的加载和执行都会造成页面渲染的阻塞。
  • 当DOM树和CSSOM树构建完后,根据它们来构建渲染树。渲染树构建好后,根据渲染树来进行布局。最后使用浏览器的UI接口对页面进行绘制

那就开始今天的学习叭!!!

R.gif

http

http,超文本传输协议,它通常运行在 TCP 之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。

一般来说,浏览器和服务器会根据最优情况选择http版本进行通信。

协议分析-发展:

1678336747046.png

且听我梳理:

http连接复用

回到前面看一个网页打开过程,从中提取耗时的部分:

  • DNS查询时间(一来一回,走UDP协议)- 网络IO
  • TCP建立连接握手 - 网络IO
  • request构造和发送完毕时间 - CPU运算、网络IO
  • response构造和发送完毕时间 - CPU运算、网络IO
  • 服务器关闭连接时间 - IO
  • 客户端接收数据渲染页面时间 - CPU运算

对于http1.0版本来说默认是短连接,即每一个http请求都会打开一个tcp socket连接,交互完毕就会关闭该连接。这就带来性能上的缺陷

举个简单栗子:

浏览器向服务器请求到html文件后默认关闭连接。而在解析html文件中,遇到img标签,会根据src属性再次向服务器发送下载图像数据的请求,对于网页文件包含js、css文件也会出现上述情况。

显然,访问一个包含许多图像文件的网页整个过程包含多次请求和响应,而每次连接知识传输一个文档和图像,但对于客户端和服务器端每次建立和关闭连接都是很费时的过程,而且带宽和延迟也会影响网络请求速度,严重影响性能。

于是,引入了keep-alive机制,也就是使客户端到服务端连接持续有效,避免了重新建立连接。http1.0需要手动配置 Connection: Keep-alive 字段,断开则需发送 Connection: close 字段。

前端ajax代码:

const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/api/data');
xhr.setRequestHeader('Connection', 'keep-alive'); // 设置Connection头部为keep-alive
xhr.setRequestHeader('Keep-Alive', 'timeout=60'); // 设置Keep-Alive头部,超时时间为60秒
xhr.send();

// 在需要断开keep-alive连接时,可以调用xhr.abort()方法来终止当前请求并关闭连接

后端koa代码

app.use(async (ctx) => {
  // 设置响应对象的Connection头部为close,表示在响应结束后关闭TCP连接
  ctx.set('Connection', 'close');
  ctx.body = 'Hello World';
});

而对于http1.1版本,默认保持了长连接,数据传输完成保持TCP连接不断开,等待在同域名下继续使用该通道进行传输。如需关闭keepalive需要手动配置(浏览器也会默认设置超时时间等措施关闭该连接)。

不过,这种持久连接会增加服务器的负担,服务器需要维持该TCP连接的状态。

虽然说http1.0也支持显示设置keep-alive来进行持久化连接,但是在HTTP/1.0中,Keep-Alive的实现并不是很一致,不同的服务器和客户端实现可能会有不同的限制和行为(连接、超时、状态、兼容性等限制),导致持久连接的效果不稳定。

因此,HTTP/1.0中的持久连接机制相对来说比较薄弱,与HTTP/1.1和HTTP/2相比,性能也相对较差。

而在http/2版本中进一步改进了连接复用机制,还引入了多路复用和流的机制(解决了Head-of-line blocking)

多路复用和流

Head-of-line blocking(HOL阻塞)是指在网络传输中,由于数据包的到达顺序不同,导致后续数据包必须等待前面的数据包传输完成后才能继续传输,从而导致传输效率下降的问题。

在TCP协议中,数据包是按顺序传输的,每个数据包都必须等待前面的数据包传输完成后才能继续传输,这就会导致HOL阻塞。例如,在HTTP/1中,浏览器通过单个TCP连接发送多个HTTP请求,如果第一个请求的响应数据包传输出现延迟,那么后续的请求必须等待第一个请求的响应数据包传输完成后才能继续传输,从而导致整个连接的传输效率下降。

多路复用(所有的请求和响应可以通过一个TCP连接并发完成)替代原来的序列和阻塞机制(建立多个TCP连接)

HTTP/2的流(Stream)是HTTP请求在同一个TCP连接上进行并发传输的基本单位,可以提高网络性能和效率,避免TCP连接数量过多和拥塞控制的限制,同时支持优先级和流控制,以及头部压缩(对HTTP头部进行压缩和解压缩,减少数据传输的大小)等功能。

数据被分割成一系列帧,包含了唯一标识符和一个关联的优先级值(服务器会优先处理重要的流),用于标识该帧所属的流,以及其他的控制信息和数据负载。这些帧可以以任意顺序发送,而且可以在同一个连接中的不同流之间交错发送,从而避免了HTTP/1.x中的队头阻塞(Head-of-line blocking)问题,提高了传输效率。

但需要注意的是,由于每个流都有自己的流量控制,因此在传输过程中可能需要等待其他流的数据传输完成,以确保每个流的数据传输速度都不会超过其流量控制窗口的限制。

总结:

http/1.1是标准化协议,被广泛认可并使用,它对比http/1.0,提供了很多新的特性,包括缓存控制,持久化连接,分块编码(将正文分成不分块编码同块进行传输,附加头部辨别),管道化请求(允许在一个tcp连接并行发送多个请求)大大提高了性能。

HTTP/2引入了多路复用、流和头部压缩机制,以进一步提高性能。此外,HTTP/2还支持服务器推送和优先级,这些特性在HTTP/1.x中是不存在的。

补充

刚才http/1.1提到了分块编码、管道化请求,那它和http/2的多路复用和流的概念有什么联系吗?

答:没有哈~它们是两种不同的技术。首先,分块编码是一项可选的技术,可以和流一起使用来提高网络性能和效率。

其次,http/2采用了全新的协议设计。(这就是为什么是http2而不是http1.2)

挺复杂的!http协议方面 1678346861571.png 写的我都懵了,下面尽量写简单点总结。

http为什么不安全

http协议不会对数据加密,传输的数据可以被网络上的任何人截获并读取。攻击者可以通过网络嗅探或中间人攻击等方式来窃取传输的敏感信息,例如登录凭据、信用卡信息、个人隐私等。

当年,一直记得打开浏览器,会先跳出贪玩蓝月的广告。。。

那为什么呢?其实就是一种http劫持技术(违法违法违法的!!!)因为使用的协议是http,代理运营商(如移动、电信等)拦截了我们发起的请求,在原始的http响应(无加密)中注入了广告信息。

https

http 运行在安全的 SSL/TLS 协议上,即HTTPS = HTTP + SSL/TLS,通过 SSL 证书来验证服务器身份,并为浏览器和服务器之间的通信进行加密。

加密流程

之前面某大厂,md面试官老逮着https加密解密流程问一堆,阿巴阿巴~~ 挂了

具体挺麻烦的,尽量讲清楚

对称加密

加密解密同时使用一个密钥

用js实现一个简单对称加密:

首先先了解一下位运算的异或 136. 只出现一次的数字 - 力扣(LeetCode)

1 ^ 1 // 0,也就是相同字符进行异或为0

那么来了:

const key = 'hyhyhynbnb'
function encrypt(str) {
    let encrypted = '';
    for(let i = 0; i < str.length; i++) {
        let charcode = str.charCodeAt(i) ^ key.charCodeAt(i % key.length);
        encrypted += String.fromCharCode(charcode);
    }
    return encrypted;
}
function decrypt(encrypted) {
    let decrypted = '';
    for(let i = 0; i < encrypted.length; i++) {
        let charCode = encrypted.charCodeAt(i) ^ key.charCodeAt(i % key.length);
        decrypted += String.fromCharCode(charCode);
    }
    return decrypted;
}
console.log(decrypt(encrypt('hyabc')));

上述代码只是将字符串编码Unicode值与密钥进行简单的位运算。

对同一个密码进行两次加密解密改动的位运算后消除原先的改动,也就是 key^key ~ 0

对于对称加密,存在密钥配送问题。对于同一套算法(一般来说,算法是公开的),只需要截取到密钥,那加密就无意义了。

请不要做即使密码被别人窃取了也不要紧,根本不知道怎么用的假设~~

简单的情况没有密码都能被破解,更何况密码和数据都被窃取掉的情况下呢!而且在算法领域,忌讳独创一门自以为安全的算法,单靠隐藏算法细节达到加密的目的是非常非常危险的!!!只有经过时间检验(看看别人是否能破解)才能用来加密

非对称加密

其实我一直有个疑惑,对于非对称加密,是怎么进行加密解密的呢?怎么滴,要用两把不同的钥匙打开同一把钥匙?? 也是折磨了我好久(找了好多非对称加密算法,无一例外、看不懂嘿嘿、涉及到了复杂的大质数分解、离散对数等数学知识,不懂,真的不懂,放过连高数差点都挂的uu叭)。

后面也是找到了张电路图,茅塞顿开,感觉不同不过也差不多叭~ 1678352009284.png

公钥和私钥 具体的,会根据特殊规则生成两把钥匙(私钥公钥),虽然理论上两把钥匙可以相互转化的,但是一般生成钥匙的时候都会给出特殊条件,也就是在实际使用过程,两者通常不会互换。

私钥自己保留,公钥发给通信方。也就是说公钥是公开的,每个人都可以持有公钥并对数据进行加密,而解密只能通过私钥来进行解密。

:通过非对称加密进行通信时,通信双方分别拥有自己的公钥和私钥(通过同一套非对称算法生成)。在通信过程中,一方使用对方的公钥来加密信息,然后将加密后的信息发送给对方,对方使用自己的私钥来解密信息。

非对称加密一定安全吗?

给个具体场景:

这里也就回到刚才的劫持信息并注入广告问题了:假设 HYHYHY 和 hyhyhy 在进行网络通信(通过非对称加密传输),有个家伙坏偷偷劫持了一方发送的信息,然后用同一套非对称加密算法生成假的公钥和私钥,并用公钥加密自己想要获取的信息,然后装成某一方并发送,用秘钥解密获取到自己想要的信息。

中间人攻击:攻击者通过在通信过程中插入自己的假公钥来进行中间人攻击。当发送方使用被篡改的公钥加密信息时,攻击者可以使用真实的私钥来解密信息,然后再用被篡改的公钥加密信息,并将其发送给接收方。在这个过程中,攻击者可以窃取和修改加密信息,并阻止接收方检测到这些修改。

这就需要数字证书来保证双方身份了。而https也是这样的。而且为了保证数据不被劫持破解,需要将http协议在SSL/TLS协议(混合加密协议:对称加密和非对称加密结合)上

https具体加密步骤:

HTTPS 协议使用数字证书对通信双方进行认证,数字证书包含服务器的公钥和其他身份信息,是由受信任的证书颁发机构(CA)颁发的。客户端在建立连接时会验证服务器发送的数字证书是否合法和真实,以确保客户端与服务器建立的是安全的通信连接。

  1. 客户端向服务器发起 HTTPS 请求。
  2. 服务器将自己的证书发送给客户端。证书中包含了服务器的公钥和身份信息,以及证书颁发机构的签名。
  3. 客户端验证服务器的证书是否真实有效。客户端会检查证书的有效期、颁发机构是否可信等信息,以确保证书的真实性。
  4. 客户端生成一个随机的加密密钥(称为“对称密钥”),然后使用服务器的公钥对该密钥进行加密,并将加密后的密钥发送给服务器。
  5. 服务器使用自己的私钥来解密客户端发送的加密密钥。
  6. 服务器使用客户端发送的对称密钥来对数据进行加密,然后将加密后的数据发送给客户端。
  7. 客户端使用之前生成的对称密钥来解密服务器发送的加密数据,并对数据进行验证,确保数据的完整性和真实性。

1678370220703.png

在以上流程中,客户端和服务器之间的通信数据都是通过对称密钥进行加密和解密的,因此数据的传输速度相对较快,同时也保证了数据的安全性和机密性。证书的验证过程保证了通信双方的身份,避免了中间人攻击。因此,HTTPS 协议可以有效地保护用户的隐私和数据安全。

补充:

如果攻击者能够使用相同的算法和密钥对生成一个有效的证书,那么他就可以欺骗客户端,使其认为攻击者是合法的服务器,从而进行中间人攻击。

为了防止这种情况的发生,数字证书中包含了证书颁发机构(CA)的签名。证书颁发机构是一个受信任的第三方机构,负责验证证书的真实性,并将自己的数字签名附加到证书上。客户端在收到证书时,会使用证书颁发机构的公钥来验证签名的有效性。如果签名有效,则认为证书是有效的,否则就会认为证书是伪造的。

因此,攻击者无法伪造有效的证书,因为他无法获得证书颁发机构的私钥。同时,浏览器内置了一些受信任的证书颁发机构的公钥,可以用于验证证书的有效性,从而保证通信的安全性。

转http为https

简单来说,就是先去购买证书(从各大 SSL/TLS 证书颁发机构(CA)购买或申请免费证书),然后将证书上传到服务器,并用nginx配置一下再进行反向代理。

https补充

非对称加密怎么实现的?

加密和解密用的不是同一个密钥(公钥,私钥),也就是说用公钥加密过的数据不能用公钥进行解密。

如下:知道x的值,我们可以很容易得出y的值。对于知道y的值,计算机要挨个尝试,通常认为取模运算不可逆

5^x mod 31415926535... = y ?

x=p*q,结合欧拉定理可以推出pq等式(数论)

加密流程

tcp三次握手

tls四次握手

  • 第一次握手客户端告知服务端其支持的加密协议的版本如TLS1.2,和加密套件如RSA,同时会向服务端传输客户端随机数

  • 第二次握手服务端确定加密方式和套件,并向客户端传输服务器证书和服务器随机数

  • 第三次握手客户端从服务器证书中取出公钥,再生成第三个随机数premasterkey,用公钥加密并发送给服务器,客户端还将三个随机数计算生成会话密钥,再讲通讯数据生成一个finish报文摘要,并用会话密钥进行加密发送给服务器进行校验

  • 第四次握手服务端通过私钥解密得到premasterkey,此时服务端也获取到了三个随机数,用同样的算法如RSA生成一个会话密钥,同样生成finish报文摘要传给客户端进行校验

  • 对称加密通信(后续的对话都是通过生成的秘钥来进行通信加密)

通过三个随机数生成的会话密钥来实现对称加密解密

三个随机数

client_random,server_random(公开的),

pre_master_key(通过公钥生成,不能被破解)

为什么不直接传递公钥?而要用CA服务器证书传递公钥?

因为前两个随机数是公开的,只有premasterkey是通过公钥生成的,在公钥传输过程中,有可能被黑客替换成自己的公钥,在第三次握手时,客户端会根据假公钥生成premasterkey,黑客再通过私钥解密获取到,这样就得到了三个随机数就可以生成会话密钥了

混合加密

公钥CA认证,服务器证书本质上是用CA私钥加密过的服务器公钥,客户端可以通过CA公钥解密获取服务器公钥

客户端验证

这里CA加密主要是为了避免发送服务器公钥的时候被人替换导致客户端获取到假的公钥,而不是怕别人获取到公钥。(因为服务器公钥通过CA私钥加密的,没有私钥是无法替换假公钥的)

如何获取到CA公钥

直接内嵌在浏览器内核或者操作系统内核中,因为如果都向CA官网发送请求公钥,官网肯定得崩。能颁发证书的机构不多。

为什么不直接用非对称加密

非对称加密需要耗费一定的计算量,比对称加密慢,带来性能问题。

代理服务器

嘿嘿,刚从一个大佬那学到一堆知识,赶紧记录巩固一下!! 1678361044755.png

之前的文章中也讲过代理服务器(跨域转发http请求,避免同源策略的影响),这里清楚讲一下正向和反向代理。

反向代理

代理的是服务端

而常说的Nginx就是一款高性能的Web服务器和反向代理服务器。

反向代理是一种代理模式,用于隐藏真实的服务器地址。反向代理的主要作用是负载均衡和安全防护。通过反向代理服务器,可以将请求分发到多个后端服务器。

一般来说,访问IP地址后面跟了个端口号,例如 http://192.168.1.100:8080, 可能该 IP 地址上运行的 Web 服务器并非直接对外提供服务,而是通过反向代理服务器进行代理。这时,反向代理服务器会接收到客户端的请求,然后将请求转发给该 IP 地址上的 Web 服务器,浏览器获取到返回的html进行渲染。

所以反向代理用于代理服务器资源的访问

正向代理

代理的是客户端 可以代理客户端向服务器发送请求,并将响应转发回客户端。

如图:

我们在本机开启手动设置代理,然后输入服务器(开启了正向代理)的ip地址和端口(由服务端设置),并连上内网,我们就可以访问到该服务器,然后我们对http的请求(由服务端设置)就会由该服务器代理转发并返回。

我们将http请求发送给通过另一台服务器,另一台服务器通过koa的 ctx.request.ip 属性来获取客户端的 IP 地址。会发现获取到的ip地址不是我们本机ip地址了!哦吼吼,这样我们就可以嘿嘿嘿~~~

不过你在本机的所有http请求都可以通过该服务器抓包(也就是可以知道你访问某些网站)。 也就是说正向代理并不安全,不会进行加密,但是轻便且易配置

匿名浏览器就可以通过正向代理实现(其中一种方法)

注:暗网使用的是一种叫做 Tor 的匿名网络,它通过多重加密和路由机制来隐藏用户的真实 IP 地址和位置信息。并不是正向代理。

注:校园网不是正向代理,但是校园网的网络环境会使用代理服务器来管理和控制学生和教师的网络访问。

这就是不能偷偷用校园网看好东西的原因

虽然说运营商也可以抓包,查看你的访问记录,但是对于运营商来说,何必呢?不过学校就不一样了,学校一般会进行监控(记录某人访问的不良网站,吼吼这样就没意思了)

注:文明上网

vpn和代理的区别

一直有个疑惑,就是vpn是怎么实现的呢?

VPN(Virtual Private Network,虚拟私人网络),刚才说了,VPN和正向代理都可以用于隐藏你的真实IP地址,并通过更改你的网络流量路径来实现匿名上网

防火墙会拦截一些ip地址限制访问,而VPN 是一种可以绕过防火墙限制的技术,它通过加密和隧道技术,将用户的网络流量从本地计算机发送到远程 VPN 服务器,然后再将流量发送到互联网上。这样,当用户使用 VPN 时,所有的网络流量都会经过 VPN 隧道,防火墙只能看到加密的流量,无法检测到用户的真实 IP 地址和所访问的网站。

总的来说,VPN 通过加密、隧道、身份认证等技术手段,将公共网络上的通信转化为安全的、私密的虚拟网络,使得用户可以在这个虚拟网络中安全地传输数据和访问网络资源。

注:文明上网 ~ 私自使用vpn违法违法!

总结

终于!!完结撒花! 056A64CF.gif 祝各位拿到满意的offer!!