前言: 文章主要借鉴神三元的部分参考资料以及自己对问题的理解,主要为了使自己的理解更加深刻,以及更好的发现自己知识层面的漏洞.
由于浏览器和web协议息息相关,而且本篇主要以web协议为主,(浏览器加分项,更好的理解前端的工作)所以会比较有穿插的讲解.
1、浏览器的多进程?(以主流的chrome为例)
浏览器是有多进程构成的.在所浏览器的进程之前先说一下进程和线程的区别?
1、进程和线程都是在操作系统层面上的.
2、进程是资源分配的基本单位,线程是任务调度和执行的基本单位.
3、线程是运行在进程之上的,共享进程数据的.
4、当一个线程崩溃时,整个进程都会奔溃.
5、进程之间是相互独立的,通过IPC进行进程间通行.
6、当进程被关闭后,操作系统会回收所有资源.
单进程->多进程
在浏览器早期是采用单进程架构的,这意味着多个标签页,html解析和渲染,js执行,插件运行,网络请求都在一个进程之上.这样做会造成.
1、不稳定:当一个标签页上的渲染线程崩溃或者插件崩溃时,造成这个进程崩溃.
2、不安全:对内存的读取等操作也运行在一个进程上,可能造成恶意插件获取用户信息,产生安全性问题.
3、不流畅: 所有页面的渲染和js执行都在一个线程上,意味着同一时刻只有一个页面可以执行.如果js代码无法退出(while循环),整个浏览器将变得卡顿,最后失去响应.
4、内存泄漏: 通常浏览器内核时非常复杂的,在关闭一个复杂页面时不能形成很好的垃圾回收,就会造成内存泄漏,那么该问题会随着浏览器的执行时间,变得越来越卡顿.
多进程架构:
为了解决这些问题,浏览器采用了多进程架构.
1、浏览器主进程,主要负责控制进程间通信问题,以及对重要文件的读取
2、网络进程(这个其实可以算在浏览器主进程之上),用于网络请求.
3、插件进程,(管理插件,防止恶意攻击,使用安全沙箱.)
4、渲染进程(重点!v8和blink都运行在渲染主线程之上,并且是互斥的(这也是说js是单线程的原因),使用安全沙箱)
5、GPU进程,用于合成图片的.
* 根据浏览器的多进程架构,每打开一个页面,都会产生一个渲染进程(同一站点或者经过处理除外),这样就使得每一个页面渲染解析和执行js时,是相互分离的.
* 当一个页面奔溃时,其他页面不会产生影响.并且给渲染进程套上了安全沙箱,控制它的访问权限,防止有人用js脚本读取用户信息.(插件进程也如此)
* 至于内存泄露问题,当一个页面被关闭时,他的渲染进程资源被回收,也就不存在内存泄漏问题了.
不过这样的多进程也意味着更高的资源占用,以及浏览器架构的复杂程度加深,耦合度较高.
2、说一下OSI7层和TCP/IP五层?
IOS7层: 物理层->数据链路层->网络层->传输层->会话层->表示层->应用层
物理层: 二进制文件传输.
数据链路层: 帧传输、错误检测
网络层: 路由寻址: IP、ICMP、RIP、OSPF、BGP、IGMP
传输层: 端对端的连接TCP、UDP
会话层:解除或建立与别的接点的联系 没有协议
表示层:数据格式化,代码转换,数据加密,没有协议
应用层:文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet
TCP/IP五层: 物理层->数据链路层->网络层->传输层->应用层
参考资料: (blog.csdn.net/qq_38350514…)
3、如何保证页面数据被安全完整的传输?
通过IP层将数据包送达指定的主机
通过传输层将数据包送达指定的进程.UDP协议和TCP协议
4、UDP协议和TCP协议的区别?
- 1、它们都是建立在传输层的协议.
- 2、UDP协议传输速率较快,但是可能会造成数据包的丢失,并且无法控制和重传.并且无法对乱序的数据包进行组包.应用于对数据完整要求不高,但是传输速率快的应用程序,(游戏,视频播放)
- 3、TCP协议是面向连接的、基于字节流的安全传输协议.TCP在建立时会进行三次握手,断开时会进行四次挥手,所以说它是面向连接的,并且还有重传机制,对于丢失的数据包会进行重传,可以对乱序到的数据包根据序列号进行组包.(具体会重点讲)
TCP
1、TCP协议的任务?
• 主机内的进程寻址
• 创建、管理、终止连接
• 处理并将字节(8bit)流打包成报文段(如 IP 报文)
• 传输数据
• 保持可靠性与传输质量
• 流控制与拥塞控制
2、TCP三次握手?
- 握手的目的是: 1、同步序列号 2、交换MSS(最大报文段)、窗口大小信息、指定校验和算法等
- 握手的过程.如图一(SYN表示同步,ACK表示确认.)
- 三次握手的具体流程,如图二
- 首先客户端处于close状态, 服务器端处于close->listen状态.
- 客户端发送序列号SYN,自己处于SYN-SENT状态
- 服务端接受消息后,发送自己的SYN以及ACK(客户端的SYN+1).然后变为SYN-RECEIVED
- 然后客户端收到消息后,在发送ACK(服务端发来的SYN+1) 进入established
- 服务器端接受到后,进入established 可能你有点晕,讲一下自己的理解:
- 比如我叫黄Y,你叫宋Q(我的室友😁).
- 假如我是黄Y,我和宋Q说:“嘿,我叫黄Y”. --- client发送SYN
- 那黄Y怎么知道他听到我说话了呢,而且出于礼貌宋Q也应该自我介绍.
- 那宋Q就说了:“好的,我知道你叫黄Y了,我叫宋Q”. --- server发送SYN+ACK
- 这时宋Q就不开心了,丫的,我告诉你我叫宋Q了,你也不说你听没听到.
- 黄Y就又说了:“我知道你叫宋Q了” --- client发送ack
- 之后他们就是好兄弟了.
其实就是对于双端的接受消息和发送消息的检测.
那这时就知道了为了要三次握手而不是两次握手(少了最后一次,服务端就无法知道客户端接受消息的能力),又为什么不是四次握手(三次已经可以了,再多一次浪费资源)
图一-
图二-
2.1 三次握手可以携带数据吗?
TCP标准规定,第三次握手时,可以携带数据,因为此时客户端已经处于established,可以发送数据,相对安全,并且还提高了效率.
3、说一下TCP协议的四次挥手?
- 首先client端发送FIN,进入FIN-WAIT-1状态,此时只能接受消息不能发送消息.处于半关闭状态.
- server端接受到后,发送ACK给client端,变为CLOSE-WAIT状态.
- server端再发送FIN给Cclient端,表示断开连接.进入LAST-ACK状态
- client端在收到FIN后返回ACK,表示确认收到,进入TIME-WAIT状态,在等待2MSL没有收到重发请求后关闭连接.
3.1、为什么要等待2MSL?
- 因为1MSL表示报文最大存活时间,等待2MSL是为了确保报文能够达到Server,并且如果Server要求重-发或者还有数据携带,能够到达Client端.
- 如果不等待2MSL,那么如果在当前Client端口被另一程序占用,这些消息就会被发到另一个程序中,造成数据包混乱.
3.2、为什么是四次挥手而不是三次?
- 在Server端进行第一次挥手第二次挥手之间可能还有数据时需要发送的、而发送FIN表示自己不再发送数据了,所以需要等待数据发送完毕后,再进行第二次挥手.
- 如果Server端没有数据需要发送了,那么Server端的第一次和第二次挥手是可以被合并的.
4、半连接队列和全连接队列?
4.1 TCP饿死?
- 抛砖引玉,TCP饿死指的是在数据通道中,UDP的传输是没有流量控制的,就像一个愣头青,会不断的往通道内传输,而TCP就有礼貌了,它通过拥塞窗口进行流量控制,当通信通道的数据溢出时就会影响TCP的传输.
4.2 DDOS/DOS?
- 而DOS/DDOS就是利用了这一特性,通过对服务器发送大量UDP,导致整个通道无法进行大量的服务.
4.3 半连接和全连接队列.
- 在Server端从Close->listen状态时,会产生半连接和全联接两个队列.
- 半连接队列用于对Client发送第一个SYN后,进入缓冲区.
- 全连接队列时在Client发送ACK后,会进入全连接队列,等待被应用取走
4.4 SYN flood?
syn flood指的是攻击者模拟大量假的IP,发送SYN,而这些连接会被送入半连接队列,当半连接队列满时,就无法再接受连接,从而影响TCP的接受,并且在收到SYN会,会发送ACK和SYN,由于IP不存在,触发TCP重传机制,耗尽服务器资源.
- 优化手段: 1、增长半连接队列
-
2、减少SYN+ACK的重传次数,减少浏览器资源消耗. -
3、使用syn-cookie,在第一次连接时,不分配资源,知道客户端发送ack时,验证cookie在分配资源.
4.5 ACK flood?
ack flood指攻击者发送大量的ack确认包给服务端,服务端查询查表后发现没有这样的连接,(可能是上一次连接时留下的问题),发送RST和ACK,表示“不理你了”,从而消耗client资源.
5、TCP报文结构?
- 1、源端口和目的端口(源端口、目的端口、源IP、目的IP构成一个连接)
- 2、序列号(SYN),占用四个字节在0-2^32之间.循环使用.
-
作用: 1、握手时同步初始序列号 2、保证数据包正确的组装顺序 - 2.1 初始化序列号
-
在握手时同步,并且为了保证初始序列号的安全性,采用动态增长的算法,使它不可被猜测. - 3、确认号: 表示在这之前的报文都已经被收到了,期待下一次发过来的序列号.
- 4、数据偏移: 确定数据报文开始头部和报文头部的偏移(TCP报文的头部和数据开始的头部是不一样的)
- 5、标志位:
-
URG: 表示紧急指针,需要快速发送. ACK: 确认报文段 PSH: 表示高优先级,不要被缓存,应该尽快被传输到应用程序 RST: 表示需要断开并重新建立连接(复位报文段.) SYN: 指明同步报文段 FIN: 表示结束报文段 - 6、窗口大小:表明当前TCP接受缓冲区允许接受的数据量,占用两个字节,实际是不够的,所以在选项中引入了窗口缩放因子.
- 7、校验和: 数据校验,丢弃有错误的数据,等待重传.
- 8、选项: MSS(最大报文段)、窗口缩放因子、TimeStamp(时间戳)
6、TCP的快速打开的流程(TFO)?
在首次三次握手时,首先发送带有Fast cookie(为空)的SYN,在客户端再一次接受到SYN时,生成一个cookie(存放在报文的fast open选项中),然后客户端收到cookie后保存下来.
在后面进行握手时,携带cookie和htttp进行握手,server验证cookie的合法性和有效性,如果匹配,则直接发送http响应,不需要等到客户端返回ack,建立连接才能返回响应了.
减少了一个RTT(往返时延)
7、TCP的时间戳的作用?
- TCP的时间戳解决了:1、计算RTT 2、防止序列号回绕的问题.
- 先来看计算RTT的问题: 如果不存在时间戳,那么当一个数据包发送时,我们只能通过在接受到ACK的时间和发送的时间之差来获取RTT,但是这里就需要考虑一个问题,那就是数据包丢失与重传机制.分两种情况
如果以首次发送的时间为开始时间,并且数据包丢失了,那么势必会使接受到ack的时间变迟,从而增大RTT.
如果以重发的时间为开始,那么如果只是客户端以为数据包丢失,而实际是来的数据包已经在路上了,那么就会造成,收到ack的时间正确,但是发送数据包的时间变为了重发的时间,从而缩小了RTT.
而时间戳就很好的解决了这个问题,它在数据包本身内存放了发送数据包的内核时间.由timestamp和timestamp echo组成,timestamp发送数据包时的时间,timestamp echo存放该对端发送数据包时的时间.通过timestamp和timestamp echo的往返就可以计算出RTT了.
- 以及序列号回绕问题: 之前说过序列号是有4字节组成,循环使用的.
那么如果序列号只有0-3的时候,并且在发送序列号1的数据包时,由于网络问题,数据包被滞留了.
到序列号再次循环到1的时候,恰好滞留的数据包被发送了,这时就会造成序列号混乱,这是由于序列号的不唯一性引起的
时间戳完美的解决了这个问题,因为时间是可以作为唯一标识符的.
- 以上时时间戳的常用用法,当然对于时间戳较早的数据包,时间戳还有判断是否需要重发.但是不是很经典,一般也不需要特别深入.
8、流量控制?
流量控制主要通过发送窗口和接受窗口来确定能够接受的数据,从而做到流量控制.
发送窗口主要由四部分内容组成.
1、发送并确认的.
2、发送未确认的.
3、未发送等待发送的
4、未发送不可发送的.
接受窗口:
1、收到并确认的.
2、收到未确认的
3、溢出的.
控制过程: 首先初始化两个窗口大小,然后发送窗口内被放入要发的数据,并减少可用窗口,当接受窗口接受到数据后,会有一部分被确认,而未被确认的留存在了缓冲区,那这时,接受窗口就会让发送窗口缓缓,发送窗口就会减少缓冲区的大小.从而做到流量控制.
9、拥塞控制?
拥塞控制的四种手段:
1、满启动.
2、拥塞避免.
3、快速重传
4、快速恢复.
1、满启动:
首先说一下拥塞窗口(cwnd),通告窗口(接受窗口rwnd)
它们决定了发送窗口 = Min(cwnd,rwnd);
拥塞窗口说发送端本身对自身的限制.
通告窗口时接受端对发送端的限制.
在没收到一个ack时,拥塞窗口(cwnd)会扩展一倍.
但是这种成倍的增长必定有东西会限制它---满启动阀值.
2、拥塞避免:
当达到满启动阀值时,拥塞窗口(cwnd)就会由成倍的增长变为线性的增长,从而达到了拥塞避免的效果
3、快速重传:
如果在发送数据段的过程中,产生了失序的数据段.
1、若报文丢失,会产生连续的失序ack
2、网络和硬件设备导致的产生少了失序的ack
3、若报文重复,产生少量的ack
则会使后续的数据包也失效,这时,快速重传的作用就出现了
接收方:
1、当接收方接受到一个失序数据段时,立刻发送它所期待的ack.
2、当接受到填充失序缺口的数据端时,立刻发送下一个它所期待的.
发送方:
当接受到三个重复的ack段时,不在等待重传定时器(以及丢失了),立刻重发报文段.
如图一
也就是说在接收方接收到ack时,会正常的再继续发送,但是如果数据包丢失了,那么会造成ack重复的问题,而接收方一旦发现重复(数据包失序),就会立刻发送重复的ack,而发送方在三次接受到ack时,发现了不对劲,ack重复了,就知道了这个包丢了.就会立刻的重复该数据包.
选择性重传就是只在接受到那些无序的包数据包时,会被记录下来这些包已经到达,当发送端重发到达后,这些数据包不需要再发了,直接从这些之后发就好了.
4、快速恢复:
在进入快速重传且未失序ack到达之前,进入快速恢复阶段
发送端做出如下改变:
满启动阀值变为拥塞窗口的一半
每收到一个重复的ack,拥塞窗口加1
当新数据ack到达后,拥塞窗口变为阀值
图一---
HTTP篇
1、HTTP的请求行和响应行格式?
- 请求方法 + 路径 + http版本构成请求行.
- http版本+ 响应码 + 响应信息描述构成响应行.
2、HTTP的请求方法?
GET: 获取资源. POST: 提交资源 OPTIONS: 进行跨域时的预检请求,提交响应头,服务端进行要求匹配成功,成功则发送响应体. HEAD: 获取资源的元信息,不会返回响应体.可用于检测超链接的有效性、可用性和最近修改等. PUT: 更新资源. DELETE: 删除资源. ....
3、HTTP请求的特点?
1、明文传输.对于调试时的可读性友好,但是也造成了第三方窃取的问题 2、无状态.无法记录上下文状态. 3、灵活可扩展,只规定了基本的结构,没有严格的约束,更好的实现了向前兼容.
4、GET和POST的区别?
- 1、协议格式的不同,GET请求是存在于URI中的,采用ASCII码格式,对于界定值和非ASCII码会进行转义(% + 两位十六进制的数),POST请求没有格式限制.
- 2、从前后端角度来讲: 前端: 在js代码中,对于两个请求的构造方式不同. 后段: 从REST架构下看,GET和POST的API设计不同.
- 3、从安全性看: GET请求是在URL中的明文传输,而POST请求则是在请求体体中的,POST的请求较于GET是更加安全的.对于重要的用户信息等,需要采用POST请求.
- 4、从幂等的角度看,GET请求是具有幂等性的,而POST是不具有的(幂等指的是请求产生的副作用相等.)
- 5、从应用场景看,GET是用于获取资源,POST是用于更改资源,因此防火墙更多的针对POST请求,并且在跨域上,POST请求也比GET请求要复杂,(OPTIONS的预检请求).
- 6、get请求会被浏览器主动缓存cache,而post请求则不会.
5、HTTP的发展史(大篇幅)?
- HTTP1.0 -> HTTP1.1 -> HTTP2.0 -> HTTP2.0 + QUIC
5.1、HTTP1.0出现的问题?
-
1、长连接问题: 在HTTP1.0中是不存在长连接的. 而前面提过TCP在建立连接和断开连接是需要是需要三次握手、四次挥手的,中间还有慢启动的问题. 这意味着每次HTTP请求就要重写建立TCP连接,导致性能下降问题. 2、带宽消耗问题: 例如客户端只是需要服务端的一部分,服务端却把所有的信息都返回来了,并且不支持断点断续的,这意味着如果请求大的包体时中断了,需要重新请求. 3、缓存优化的问题: 主要使用Expires和if-modified-since作为缓存标准. expires: 定义过期的时间,在服务端定义,以客户端的内核时间校验,如果客户端的时间不准确,缓存将无效. if-midified-since: 在请求体中,对应响应的last-modify,表明最后的修改时间,比起expires,它是都在服务端进行校验的,但是还是存在只针对时间,没有针对文件本身,并且如果在短时间1s内对文件进行多次修改是没有差别的.再比如只是时间变了,内容不变问题.
5.2、HTTP1.1的优化?
-
1、HTTP1.1中出现了长连接Connection: Keep-Alive,默认开启. 在使用该字段进行http请求时,如果请求结束后,有一个keepAliveTimeOut的时延,在这个时延内,再次请求将复用TCP连接. 在 HTTP1.1中,开启了长连接对TCP复用进行了优化,但是一个TCP连接还是只能处理一个HTTP请求,而如果一个HTTP过于耗时,则会造成后面的阻塞,这就是队头阻塞问题. 所以同时出现了并发连接和域名分片的技术解决 并发连接: 可以开启多个TCP长连接(chrome最多6个),提高并发连接 域名分片:一个域名对应多个TCP长连接,分出多个二级域名指向同一个服务器. -
2、带宽消耗优化并且支持断点断续,可以支持head请求,当head请求符合要求返回100后再发送请求体. -
3、缓存优化: 配合if-range的if-unModifiy-since,为了保证断点断续在请求的过程中文件不发生修改(如果拿到的数据在中途被修改了,就没有意义了,返回412) 用于优化if-modified-since的Etag,Etag表示对文件进行hash,而hash算法具有唯一性,可以确保当文件进行修改时,Etag一点发生变化.
5.3、HTTP2.0的优化?
虽然http1.1在性能上做了很多的优化,但是还是出现了部分的问题.
- 1、由于HTTP的无状态特性,HTTP的状态无法被记录,所以每次都需要携带大量重复的头部信息.
- 2、一个请求对应一个响应,对于js,jpg等文件请求,请求耗时,根本原因:服务器无法主动推送.
- 3、随着带宽的增加,延迟没有显著的降低.原因:并发数量有限,同一个连接依然存在队头阻塞问题. 优化:
- 1、头部压缩: HTTP对HTTP头进行压缩,并且在服务端和客户端建立key-value表,对相同的头部值只需要发送key就可以了,大大了节约了资源浪费问题(但是也减少了对于http报文的可读性).
- 2、支持服务端的主动消息推送.
- 3、多路复用: 二进制分帧:
-
一条TCP连接包含多条**stream**流,流则是又message构成,**message**由frame帧构成,每个**数据帧**则对应http的请求通过二进制压缩后的结果(head帧「对应一个流」和data帧「多个data帧对应一个流」). 同时每个流又具有ID和优先级,通过优先级可以获取优先资源,通过ID则可以将无序的数据流拼接(数据流内的frame需要有序),从而获取数据 并且stream流的ID是推送依赖性请求的关键.由客户端建立的请求ID为奇数,服务端主动推送的为偶数 - 4、并且只使用一条TCP连接,比起HTTP1.1的并发连接,节省了对服务器的性能影响.
虽然HTTP2解决了HTTP层面上的队头阻塞问题,但是TCP依旧存在队头阻塞问题,并且由于TCP的可靠性,所以TCP无法解决队头阻塞
5.4、HTTP2 + QUIC(HTTP3)的优化?
- 1、采用UDP传输报文,UDP没有队列的概念,也就没有队头阻塞的问题了.
- 2、并且TCP由源端口、目的端口、源IP、目的IP构成一个连接,一旦一个元素发生变化(流量到wifi的切换等),就需要重新进行三次握手,但在UDP中,则可以采用64位随机ID来表示一个连接,只要ID不变化,就不需要重写连接.
- 3、对于TCP拥塞控制的优化等.
6、cookie和session篇?
cookie和seesion也是被问的比较多的.而且cookie涉及的内容较多,这里单独写一下
- cookie和seesion的区别?
- session是一种用于解决http因无状态而无法记录上下文的会话技术,当用户在浏览购物车等界面时,服务端需要了解标识用户,这是就需要用到session来进行回话跟踪,每个用户被用一个sessionID所标识,并保存在服务端.
- 那么这个sessionID又是如何进行同步的呢? 这时就用到了cookie技术了,在发送请求时,服务端可以将sessionID作为cookie发送给客户端用于保存,再进行操作时,携带这个sessionID发送请求,从而跟踪用户,「所以在一般的应用中都是使用cookie实现了对session会话的跟踪」
- 那么cookie如果被禁用了呢? 这时还可以通过URL的query中填入诸如sid等字段来标识用户.
- 同时cookie还可以用于保存上次的登陆信息,对于重复填写某些内容进行了优化,方便用户.
- 总结一下:
-
session就是以类似表的形式跟踪会话的数据结构. cookie是保存在客户端的,可用于保存用户信息,简化用户操作的技术,同时也是session跟踪的一种实现.
你以为这就结束了?那你的offer就没了 针对cookie,还衍生出来一系列安全性,实效性等问题.再来扒一下cookie这个字段的属性吧.
- 1、exprires和max-age用来解决cookie的实效性问题,expries在上面说http时说过了,max-age则是表示能被缓存的时间(同时存在时http1.0只认识expires,在http1.1中优先使用max-age)
- 2、domain和path,分别表明cookie可以使用范围的域名和路径.
- 3、secure表示只能用于https的传输.
- 4、httponly表示只能用于请求,不能被js读取,这个要再说一下了.
-
XSS攻击: 跨站脚本攻击. 产生问题: 1、窃取cookie. 2、注入事件监听,获取键盘按键从而盗取信息,再发送给第三方. 3、生成虚假DOM.让用户点击 4、生成浮窗广告. 分为文档型,反射型和存储型三种. 文档型: 在返回http响应时,往html中注入js脚本,这是非常危险的(js脚本可以拿到你的cookie发送给第三方,从而窃取用户资源) 反射型: 在URL请求中注入script脚本,并且后端没有做转义,直接将script返回给客户端,从而攻击用户,可能你会问,会有这种傻子自己干自己吗?,答案是可能有别人这个连接分享给你,然后攻击你. 存储型: 通过写入的API往网站后端的数据库写入script,并且后端未进行转义,当这些信息作为展示被其他用户读时,就可以获取用户信息了. 解决方案: 1、httponly,不让脚本读取cookie. 2、在后端对关键的字码进行转义过滤. 3、使用CSP(内容安全策略),禁止向第三方提交数据、禁止加载内敛脚本等. - 5、samesite表示对于第三方网站的请求是否允许携带cookie
-
strict表示不允许在当前域以外的网站发送cookie请求. lax表示只允许在第三方的get类型的请求中携带cookie none则没有限制. -
CSRF攻击: 跨站脚本请求. CSRF就是利用用户在页面A登陆状态,诱使用户在第三方页面下,发送对页面A的请求,而页面A会自动携带上cookie,从而导致服务端以为用户主动发起的类似交易的私密操作. CSRF可以是自动发起的(通过在网页上放img,并且img的src为请求URL),从而实现自动加载.也可以诱导用户点击(美女照片等). 防范CSRF攻击的措施: 1、使用samesite的strict,不允许cookie在第三方页面中,发送请求. 2、验证请求的来源,请求体中的Refer和Origin字段表明了请求的来源. 3、CSRF Token,通过验证token来表示操作是否被允许. - cookie的缺点:
- 1、只有4KB,比较小.
- 2、cookie紧跟域名,自动携带,造成性能浪费,可以通过设置(domain和path解决)
7、跨域问题?
跨域问题是前端被问的比较的多的问题了,来扒拉一下
URI?
- URI指的是唯一资源标识符.是由URL和URN组成的,URL指的是统一资源定位器,URN是统一资源名称.
- URL比较普及了,主要说一下URL的结构
- url = 协议 + 用户名密码(基本不用) + 主机 + 端口 + 路径 + query + 锚点定位
-
http:// + www.xiangjiao.com + :8080 + /niunai + ?sid=2 + #chi
跨域指的是非同源之间的请求是被浏览器限制的.
同源政策: 被请求的url的协议主机端口和发起请求的一致,称为同源.非同源的页面有以下的限制.
- 1、不可访问dom结构
- 2、不可访问cookie.
- 3、限制XmlHttpRequest的请求. 发送请求的行为是在渲染进程中发起的,但是浏览器为了防止第三方获取系统资源,所以渲染进程是有沙箱机制的,请求会通过浏览器主进程进行IPC(进程间通信)发送给网络进程,然后网络进程返回后通知浏览器进程,浏览器进程会检查跨域和cors字段,如果没有匹配那么跨域响应会被浏览器主进程拦截『拦截是发生在返回时的浏览器主进程的,而不是服务器的.』
解决跨域请求的几种方式?
1、CROS跨域资源访问.(重点)
- 为了安全性考虑浏览器引入了同源策略,但是确实对于实用性和可交互性造成了很大的问题.所以引入了CROS. 宽泛的说就是服务端可以决定哪些域,以及携带哪些请求头等信息,是被允许跨域访问的.
- 具体策略一: 浏览器将请求分为简单请求和非简单请求. 简单请求:
- GET/HEAD/POST 方法之一
- 仅能使用 CORS 安全的头部:Accept、Accept-Language、Content-Language、Content-Type
- Content-Type 值只能是: text/plain、multipart/form-data、application/x-www-form-urlencoded 非简单请求就是!简单请求😁.
- 对于简单请求的跨域,浏览器会携带Origin字段发送给服务端,而服务端会返回CROS字段-Access-Control-Allow-Origin(如果没有该字段并且跨域则直接throw error),这时浏览器对域返回的信息中就可以获得Origin和Access-Control-Allow-Orign,如果Origin属于该CROS字段则放行响应,否则进行拦截.
- 对于非简单请求的跨域,会首先发送预检请求OPTIONS,预检请求会发送Origin、Access-Control-Request- Method,Access-Control-Request-Headers;以表明自己将要发送的信息,预检请求会返回与之对应的Access-Control-Allow-Methods,Access-Control-Allow-Headers、Access-Control-Max-Age,以供浏览器判断是否可以将请求发过去,如果符合要求,那么Access-Control-Max-Age生效,再接下来Max-Age时间内不用发送预检请求了. 2、JSONP请求.
- JSONP是通过script标签的原理,通过get请求发送请求以及响应函数,并且在服务端触发响应函数,并且返回给客户端.(具体手写在手写篇中)
- CDN也是该原理. 3、Nginx反向代理.
- 代理就是一种针对服务器而产生的服务,分为正向代理(VPN)和反向代理(Nginx).
- 正向代理是帮助客户端拿到不可访问的网站信息.
- 反向代理就是帮助服务器,可用于负载均衡等优化服务器的,它的工作原理是当发起对服务器的请求时,为了缓解服务器的压力,会讲当前服务器分发给其他的服务器,从而实现负载均衡.
- 利用反向代理的这一点,就可以实现跨域了,首先向未跨域的服务器发送请求,然后该服务器在通过反向代理的方式,代理到目标服务器,目标服务器返回数据,从而使用户拿到信息并且未跨域. 4、webSocket.
- webSocket是一种双工技术,通过postMessage和onMessage监听和发送信息,可以实现跨域.
8、对HTTPS了解多少?
HTTPS实际是HTTP + (SSL和TLS),是用于解决http明文传输的不安全性特点而诞生的,SSL(Secure Sockets Layer安全套接层)出现到3.0之后被标准化为TLS(Transport Layer Security传输套接层)1.0
对称密钥加密?
- 首先浏览器将加密套件列表和浏览器端生成的随机数发送给服务器.
- 服务器接受到后,从加密套件列表中选择一种,并且连通服务端生成的随机数发给浏览器.
- 浏览器和服务器进行确认.
- 浏览器和服务器拿到相同的加密套件,两个随机数,就可以生成密钥了,之后就用密钥进行加解密.
- 漏洞: 再发送随机数的过程中是有可能被第三方获得的,也就是第三方有机会获取该密钥,从而破解信息的.
非对称密钥加密?
- 浏览器端将加密套件列表交给服务端.
- 服务端选择加密套件,并且生成公钥和私钥,将公钥连同套件交给浏览器端.
- 再进行确认.
- 之后浏览器端的数据由公钥加密后,发送给服务器,只有服务器的私钥才有能够解密的能力,即使第三方获取后,依然无法获取内容,从而保证了浏览器->服务器的安全性.
- 漏洞:
-
1、耗时,私钥解密公钥内容是比较耗时间的. 2、公钥可以被窃取,如果服务器向浏览器发送消息时,通过私钥加密,公钥解密,造成服务器信息的安全性问题.
组合加密?(RSA版本)
- 非对称密钥和对称密钥的混合.
- 首先浏览器端client-hello将「client-random」+非对称加密套件和加密对称套件发送给服务端.
- 服务端依然产生私钥和公钥,server-hello将私钥,「server-random」和套件交给浏览器端.
- 浏览器端再生成一个「pre-master」,通过公钥加密后传给服务端.
- 服务端解密并获取该数据.
- 双方同时拥有了这三个数,生成用于对称加密的密钥,之后就可以用该密钥进行加密解密数据了.
- 客户端会把之前的消息做个摘要,然后发送给服务端进行确认(验证篡改)
- 该密钥无法被获取,(随机数pre-master是通过非对称密钥加密生成的),也就无法进行组合生成最终的密钥
使用非对称加密传输密钥,使用对称密钥进行数据的加解密,解决了对称密钥传输过程中的安全性问题,解决了非对称密钥用于加解密数据时的复杂耗时问题.
服务端验证的问题?
-
现在我们依旧保证了数据传输的安全性了,但是怎么知道传输的对象不是个“间谍”呢?
-
如果攻击者通过DNS劫持将被访问服务器的IP地址更换了,我们怎么知道我们访问的网站是否有问题呢?
-
这个是要就需要机构来验证身份了,给服务器验证的第三方称为CA,颁布给服务器的身份证称为“数字证书”,并且服务器的公钥也被放在数字证书内,一同发给客户端进行验证.(并且服务器的证书时不可伪造的)
-
申请服务器证书的流程?
-
1、服务器有公钥和私钥,将公钥、公司信息、站点信息等内容提交给CA机构认证.(收费) 2、审核通过后,CA颁发数字证书,包含公司信息,序列号,有效时间等. 数字证书生成的细节? CA机构对明文信息进行HASH加密,生成信息摘要,在通过CA私钥进行加密生成数字签名(类似公章). -
浏览器对证书的验证?
-
浏览器端拿到了数字证书,上面有网站的明文信息,还有数字签名,服务器公钥等,将明文信息通过HASH + CA公钥生成数字签名A,再和数字签名进行对比,如果一致,表明CA未被篡改.(注意CA公钥和服务器公钥是不同的)
-
CA的公钥是如何获得的呢?
-
服务器除了发送网站的数字证书,还会发送CA机构的数字证书(内置CA公钥),那么CA公钥就被拿到了.
-
那么怎么判断CA的合法性呢?
-
如果在操作系统的内部有这些CA的数字证书,再将服务器返回来的进行对比不就可以了嘛,但是由于CA过多的问题,操作系统实际上认证了所有的根证书,这些根证书又可以去认证中间证书,中间证书又可以递归去认证,形成树状的证书链.
看完上面,应该对HTTPS有了比较好的了解,但是以上时RSA版本的,也是比较常见的,接下来说一下TLS1.2和TLS1.3在上面的基础上的变化.
-
首先使用RSA版本时,没有保证前向安全性,即如果私钥泄漏,就可以拿到之前的所有信息,截获所有报文.
-
来看看TLS1.2主流版本的非对称加密算法ECHDE吧.
-
首先来看一段加密套件.
-
TLS_ECDHE_WITH_AES_128_GCM_SHA256 -
看上面这段加密套件,「ECDHE」就是我们要就介绍的非对称加密算法,「AES」是对称加密算法,「GCM」是用于AES的分组工作模式.「SHA256」是用于对上述生成数字签名的HASH算法.
-
接下来就说一下ECHDE的工作区别吧.
-
ECHDE会在Server-hello时,再发送一个server-params,该参数是用来生成类似RSA中的pre-master的.
-
之后客户端再验证完数字证书后,也会发送一个client-params,这时,双方就拥有了两个params,可以使用这两个参数做ECHDE算法进行椭圆曲线计算的参数,从而生成pre-master.
-
之后就和RSA一样了.
-
*** 而ECHDE对比RSA,每次握手都会生成临时密钥对,从而保证了前向安全性.
-
*** 并且它可以在客户端发送完消息就发送HTTP报文,省去了一个往返时延(类似tcp的fast open).称为提前抢跑
TLS1.3的改进?
1、openssl 1.1.1 版本对 TLS1.3 的支持情况
Ciphersuites 安全套件
• TLS13-AES-256-GCM-SHA384
• TLS13-CHACHA20-POLY1305-SHA256
• TLS13-AES-128-GCM-SHA256
• TLS13-AES-128-CCM-8-SHA256
• TLS13-AES-128-CCM-SHA256 2、sessionID和session Ticket?
- 从上面的握手上可以看出,我们许多的RTT都是为了保证传输的安全性,那么已经可以保证安全的重复握手就是不必要的.
- sessionID: sessionID对应了上次用于数据传输的密钥,客户端在第一次握手时,服务端返回sessionId,下次进行握手时,携带该id查询服务器内部对应该id的密钥是否存在,如果存在直接复用.
- session ticket: 上面说到了sessionID,但是存储sessionId相关信息的一半存在于服务器内存中,大量的存储信息会消耗内存,并且当服务器要面向大量的用户时,就会采用nginx负载均衡,那么sessionId对应的信息在服务器之间又是不共享的,就需要重复的进行握手,「发现问题」: 现在的困扰都是来在于服务端的.怎么才能把问题转义呢🤔?
-
session ticket就是一种将session会话加密并且放在浏览器端,在复用时解密(每一台服务器都有私钥),获取里面的密钥的回话保存方式.
3、0RTT报文传输?
- 将发送sessionId的报文内加入加密的请求,服务器在验证sessionId未过期时,就会处理请求. 面临的问题: 如果第三方截取了加密的请求,那么它可以不断的重复发送请求来攻击服务器,这种攻击称为「重放攻击」,所以设置合适的sessionID和sessionTicket过期时间是很有必要的.
缓存
缓存是提高浏览器渲染速度的一种常用方式. 浏览器端缓存: 强缓存和默认缓存和协商缓存.
- cache-control字段:
-
max-age表示最大缓存时间(http1.1,优先级大于expries), public表示允许使用代理服务器缓存和强缓存, private表示不允许使用代理服务器缓存, proxy-revalidate表示无缓存向代理服务器发起请求, must-revalidate表示无缓存时向源服务器发起请求, no-cache表示不进行强缓存,直接进入协商缓存, no-store表示不进行强缓存也不进行协商缓存. s-maxAge表示代理服务器可缓存时间 - 缓存优先级:
- Memory Cache
- Service Worker Cache
- HTTP Cache (强缓存和协商缓存)
- Push Cache
-
Expries表示缓存过期时间(又客户端决定,存在纰漏)
-
last-modified 表示最后更新时间,可以根据是否更新时间是否变化从而判断是否使用缓存,但是存在短时间内更新该值不变(对应响应头的if-modify-since)
-
e-tag 表示内容的hash值,可以根据hash值来判断是否时使用缓存,对应响应头的if-none-Match
-
Age 表示已缓存的时间,当到达max-Age则向服务器请求.
-
响应头: if-unmodify-since,用来配合断点断续使用,如果数据更新则没必要再断点断续了,报错412
-
「强缓存」: 在第一次请求时,会根据响应头的max-age,expires等信息缓存在浏览器端,如果缓存未过期则使用浏览器端缓存.
-
「默认缓存(启发式缓存)」:当强缓存的字段都不存在时,可以根据响应头的Date和Last-modify字段的差/10作为默认缓存的时间.
-
「协商缓存」: 当本地缓存失效后,向服务器发送请求时,服务器会根据last-modified,eTag对应的if-modify-since和if-none-Match字段来判断文件是否被修改,如果未改变则返回304表示重新使用浏览器缓存,否则则发送请求数据,并更新字段.