14.HTTPS协议加密机制
1.为什么要加密
因为http的内容是明文传输的,明文数据会经过中间代理服务器、路由器、wifi热点、通信服务运营商等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了,他还可以篡改传输的信息且不被双方察觉,这就是中间人攻击。所以我们才需要对信息进行加密。最简单容易理解的就是对称加密。
2.加密的种类
1.对称加密
通信双方各持一个相同的秘钥,对通信的内容加密解密,这种加密方式优点就是加密解密速度快,效率高。
但是怎么能保证通信的双方都拿到相同的秘钥而不被其他人拿到呢,这就很难了= =
2.非对称加密
就是有两把秘钥,一把私钥,一把公钥;用公钥加密的内容只能私钥解密,同样私钥加密的内容只能公钥解密。鉴于非对称加密的机制,我们会有这种思路:服务器先把公钥直接明文传输给浏览器,之后浏览器向服务器传数据前都先用这个公钥加密好再传,这条数据的安全似乎可以保障了!因为只有服务器有相应的私钥能解开这条数据。
然而由服务器到浏览器的这条路怎么保障安全?如果服务器用它的的私钥加密数据传给浏览器,那么浏览器用公钥可以解密它,而这个公钥是一开始通过明文传输给浏览器的,这个公钥被谁劫持到的话,他也能用该公钥解密服务器传来的信息了。所以目前似乎只能保证由浏览器向服务器传输数据时的安全性。
3.改良版的非对称加密
既然一对私钥秘钥能保证一方面的通信安全,那用两队公钥私钥就能保证互相通信安全了 : )
1.某网站拥有用于非对称加密的公钥A、私钥A’;浏览器拥有用于非对称加密的公钥B、私钥B’。
2.浏览器像网站服务器请求,服务器把公钥A明文给传输浏览器。
3.浏览器把公钥B明文传输给服务器。
4.之后浏览器向服务器传输的所有东西都用公钥A加密,服务器收到后用私钥A’解密。由于只有服务器拥有这个私钥A’可以解密,所以能保证这条数据的安全。
5.服务器向浏览器传输的所有东西都用公钥B加密,浏览器收到后用私钥B’解密。同上也可以保证这条数据的安全。
的确可以!抛开这里面仍有的漏洞不谈(下文会讲),HTTPS的加密却没使用这种方案,为什么?最主要的原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心,而对称加密快很多。
4.非对称加密+对称加密
既然非对称加密耗时,非对称加密+对称加密结合可以吗?而且得尽量减少非对称加密的次数。当然是可以的,而且非对称加密、解密各只需用一次即可。
1.某网站拥有用于非对称加密的公钥A、私钥A’。
2.浏览器像网站服务器请求,服务器把公钥A明文给传输浏览器。
3.浏览器随机生成一个用于对称加密的密钥X,用公钥A加密后传给服务器。
4.服务器拿到后用私钥A’解密得到密钥X。
5.这样双方就都拥有密钥X了,且别人无法知道它。之后双方所有数据都用密钥X加密解密。
但是!这样会有另一个问题,中间人劫持替换了服务器给浏览器的公钥A,换成了自己伪造的公钥B,浏览器生成的对称秘钥X用公钥B加密后被劫持,劫持者用自己的私钥B’解密得到秘钥X,用之前劫持的公钥A加密后给服务器,服务器也会得到一样的秘钥X,但这时秘钥X已经泄露了= =
因此需要一个证明,证明浏览器收到的公钥确实是需要通信的服务器给的,类似于现实中张三向李四证明自己是张三一样,张三可以出具自己的身份证给李四,证明自己是张三;但是又有个问题,我不是张三但我伪造了一个张三的身份证,我好像就变成了张三了;这个时候身份证的真伪就必须有个权威机构来证明比如公安局,在公安局证明了手上的张三的身份证是真的的时候,你就是张三了。兜了一大圈,终于证明了我就是我了。
5.数字证书(CA证书)
互联网中,CA机构就像是公安局,数字证书就是服务器的身份证,证书里包括了证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,证书就如身份证一样,可以证明“该公钥对应该网站”,浏览器从证书里取公钥就行了。
但证书是明文传递的,就像之前的公钥一样,因此需要一个不能伪造的标记证明CA证书的真实性;这里的解决办法和上面的token的做法差不多,CA证书除了有网站的信息的明文外,还会附带有一个由CA机构私钥加密明文内容的签名,这两者共同组成了数字证书。
数字签名的制作过程:
1.CA拥有非对称加密的私钥和公钥。
2.CA对证书明文信息进行hash。
3.对hash后的值用私钥加密,得到数字签名。
浏览器验证过程:
1.拿到证书,得到明文T,数字签名S。
2.用CA机构的公钥对S解密(由于是浏览器信任的机构,所以浏览器保有它的公钥。详情见下文),得到S’。
3.用证书里说明的hash算法对明文T进行hash得到T’。
4.比较S’是否等于T’,等于则表明证书可信。
有一点,CA机构的公钥是否可信的问题,操作系统或浏览器一般会预装一些他们信任的CA机构的数字证书,也就是我们常看到的根证书,根证书则包含了该CA机构的公钥,用于浏览器和该CA机构信任的web服务器通信,类似于一个信任链,浏览器信任根证书里的公钥,发布该公钥的CA机构信任它认证的web服务器。
另外,不知你们是否遇到过网站访问不了、提示要安装证书的情况?这里安装的就是根证书。说明浏览器不认给这个网站颁发证书的机构,也就是没有该机构的根证书,你就得手动下载安装(风险自己承担 : p)。安装该机构的根证书后,你就有了它的公钥,就可以用它验证服务器发来的证书是否可信了。
6.HTTPS协议的会话保持
看完上述基于HTTPS协议加密的通信,会觉得过程很繁琐,如果每次请求在SSL/TLS层进行握手阶段,都要经历一次密钥传输过程会非常耗时,那怎么达到只传输一次呢?用session就行。
服务器会为每个浏览器(或客户端软件)维护一个session ID,在TSL握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session ID下,之后浏览器每次请求都会携带session ID,服务器会根据session ID找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了。
不由得感叹一句,网络安全真的很难得啊 = =
15.关于IE9浏览器CSS文件大小限制问题
前两天搭完新项目的环境跑在chrome浏览器是正常的,但在IE9里面样式失效了,具体表现就是写在vue文件中style标签里的样式不起作用,但在行内或是外联的CSS样式是可以的= =
找了资料和研究了一哈,根本原因是在IE9里面单个CSS文件大小不能超过234kb,超过的部分会被浏览器忽略,由于项目框架引入了iview组件,iview的css文件较大,因此写在style标签里的样式被忽略了。
所以可以把引用iview组件的css的操作从main.js转移到static里的style.js来引用,类似于引用common.css的做法。
webpack-server.js // 打包配置文件
entry: {
app: ["webpack-hot-middleware/client", "babel-polyfill", "./src/main.js"],
style: ["./static/js/style.js", "webpack-hot-middleware/client"]
} // 入口文件加入了style.js
static/js/style.js // 引入样式的js文件
import '../css/common.css'
这样做确实可以解决IE9里面css文件过大导致样式失效的问题,但是和我一开始想用切割打包后的css文件的做法不一样= = emmmmmm猜想应该是放在static文件夹里的文件打包的时候webpack都会自动压缩,所以文件大小要小很多。
16.计算机网络小结
经过一系列神奇的事情,我又来更新一下最近的感触 : ) 作为前端还是需要知道关于计算机网络的一些协议的,痛心疾首啊T T
1.计算机网络协议架构
OSI(Open System Interconnect)开放式系统互联,一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互联模型。
最早的时候网络刚刚出现的时候,很多大型的公司都拥有了网络技术,公司内部计算机可以相互连接。可以却不能与其它公司连接。因为没有一个统一的规范。计算机之间相互传输的信息对方不能理解。所以不能互联。
ISO为了更好的使网络应用更为普及,就推出了OSI参考模型。其含义就是推荐所有公司使用这个规范来控制网络。这样所有公司都有相同的规范,就能互联了。
不同协议在最初OSI模型中的位置:
7 | 应用层 | 例如HTTP、SMTP、SNMP、FTP、Telnet、SIP、SSH、NFS、RTSP、XMPP、Whois、ENRP |
---|---|---|
6 | 表示层 | 例如XDR、ASN.1、SMB、AFP、NCP |
5 | 会话层 | 例如ASAP、TLS、SSH、ISO 8327 / CCITT X.225、RPC、NetBIOS、ASP、Winsock、BSD sockets |
4 | 传输层 | 例如TCP、UDP、RTP、SCTP、SPX、ATP、IL |
3 | 网络层 | 例如IP、ICMP、IGMP、IPX、BGP、OSPF、RIP、IGRP、EIGRP、ARP、RARP、 X.25 |
2 | 链路层 | 例如以太网、令牌环、HDLC、帧中继、ISDN、ATM、IEEE 802.11、FDDI、PPP |
1 | 物理层 | 例如线路、无线电、光纤、信鸽 |
第7层应用层—直接对应用程序提供服务,应用程序可以变化,但要包括电子消息传输;
第6层表示层—格式化数据,以便为应用程序提供通用接口。这可以包括加密服务;
第5层会话层—在两个节点之间建立端连接。此服务包括建立连接是以全双工还是以半双工的方式进行设置,尽管可以在层4中处理双工方式;
第4层传输层—常规数据递送-面向连接或无连接。包括全双工或半双工、流控制和错误恢复服务;
第3层网络层—本层通过寻址来建立两个节点之间的连接,它包括通过互连网络来路由和中继数据;
第2层数据链路层—在此层将数据分帧,并处理流控制。本层指定拓扑结构并提供硬件寻址;
第1层物理层—原始比特流的传输,电子信号传输和硬件接口数据发送时,从第七层传到第一层,接受方则相反。
上三层总称应用层,用来控制软件方面;下四层总称数据流层,用来管理硬件,数据在发至数据流层的时候将被拆分。根据PDU (协议数据单元):在传输层的数据叫段(segment),网络层叫包(packet),数据链路层叫帧(frame),物理层叫比特流(bit),其他更高层次的数据则是报文(message)
OSI中每一层都有每一层的作用。比如网络层就要管理本机的IP的目的地的IP。数据链路层就要管理MAC地址(介质访问控制)等等,所以在每层拆分数据后要进行封装,以完成接受方与本机相互联系通信的作用。
2.下层协议
互联网是由一整套协议构成的,规定了在不同通信层的要求。
1.Ethernet(以太网)
互联网中最底层的是以太网协议,它规定了电子信号如何组成数据包(packet),解决了子网内部的点对点通信。
2.IP协议
上面的以太网协议可以解决一个局域网内的点对点通信,但是不能解决不同局域网之间的通信,IP协议就是为了解决这种情况。
如上图所示,IP协议可以连接多个局域网
IP协议定义了一套自己的地址规则,称为IP地址。它实现了路由功能,允许某个局域网的A主机向另一个局域网的B主机发送消息。
我们买的路由器就是基于IP协议,局域网之间需要靠路由器连接;路由器背部有很多网口,其内部有一张路由表,规定了A段IP地址的出口a,B段IP地址的出口b……通过这套“指路牌”实现了数据包的转发。
这张路由表注明了不同IP段目的地的数据包,要发送到哪个端口(interface)
IP协议只是一个地址协议,并不保证数据包的完整,如果路由器丢包(路由器内存满了,新进来的数据包就会丢失),就需要发现哪一个数据包丢失,以及重新补发这个数据包。这就需要依靠TCP协议了。
简单来说,TCP协议的作用就是保证数据通信的完整性和可靠性,防止丢包。
3.TCP协议
1.数据包大小
以太网数据包(packet)大小是固定的,最初是1518个字节,后来增加到1522个字节。其中1500个字节是负载(payload),22个字节是头信息(head)。
IP数据包在以太网数据包的负载里,也有自己的头信息,最少需要20字节,所以IP数据包的负载最多是1480个字节。
IP数据包在以太网数据包负载里,TCP数据包在IP数据包负载里
TCP数据包在IP数据包的负载里,它的头信息最少也需要20个字节,因此TCP数据包的最大负荷是1460个字节。由于IP协议和TCP协议往往有额外的头信息,所以实际的TCP数据包大概是1400个字节。
2.TCP数据包编号(SEQ)
一个包1400字节,那么一次性发送大量数据,就必须分成多个包。比如,一个10MB的文件,需要发送7100多个包。
发送的时候,TCP协议为每个包编号(sequence number,简称SEQ),以便接收的一方按照顺序还原。万一发生丢包,也可以知道丢失的是哪一个包。
例如第一个包的编号是一个随机数。为了便于理解,这里就把它称为1号包。假定这个包的负载长度是100字节,那么可以推算出下一个包的编号应该是101。这就是说,每个数据包都可以得到两个编号:自身的编号,以及下一个包的编号。接收方由此知道,应该按照什么顺序将它们还原成原始文件。
当前包的编号是45943,下一个数据包的编号是46183,由此可知,这个包的负载是240字节。
3.TCP数据包的组装
收到TCP数据包以后,组装还原是操作系统完成的。应用程序不会直接处理TCP数据包。对于应用程序来说,不用关心数据通信的细节。除非线路异常,除此之外收到的总是完整的数据。应用程序需要的数据放在TCP数据包里面,但要把TCP数据变成应用层可识别的数据,就要有自己的格式(比如HTTP协议)。
TCP并没有提供任何机制,表示原始文件的大小,这由应用层的协议来规定。比如,HTTP协议就有一个头信息Content-Length,表示信息体的大小。对于操作系统来说,就是持续地接收TCP数据包,将它们按照顺序组装好,一个包都不少。操作系统不会去处理TCP数据包里面的数据。一旦组装好TCP数据包,就把它们转交给应用程序。TCP数据包里面有一个端口(port)参数,就是用来指定转交给监听该端口的应用程序。应用程序收到组装好的原始数据,以浏览器为例,就会根据HTTP协议的Content-Length字段正确读出一段段的数据。这也意味着,一次TCP通信可以包括多个HTTP通信。
4.发送窗口
接收方每收到两个TCP数据包,就要发送一个确认消息。“确认”的英语是 acknowledgement,所以这个确认消息就简称ACK。
ACK 携带两个信息:
1.期待要收到下一个数据包的编号
2.接收方的接收窗口的剩余容量
发送方有了这两个信息,再加上自己已经发出的数据包的最新编号,就会推测出接收方大概的接收速度,从而降低或增加发送速率。这被称为“发送窗口”,这个窗口的大小是可变的。
上图的传输步骤:
client:我想要下一个数据包的编号是1,长度是360个字节
server:数据给你,下个数据包的编号是361,我的发送窗口最大是120bytes
client:我想要下一个数据包编号是361,长度是120个字节(按照你的要最大限度)
server:数据给你,下个数据包的编号是481,我的发送窗口最大是120bytes
…
我自己总结了一下SEQ和ACK的含义:
SEQ是我这次要从哪个编号开始要数据;ACK是我下次要从哪个编号开始给数据
5.数据包丢失处理
TCP协议可以保证数据通信的完整性,这是怎么做到的?
前面说过,每一个数据包都带有下一个数据包的编号。如果下一个数据包没有收到,那么ACK的编号就不会发生变化。
举例来说,现在收到了4号包,但是没有收到5号包。ACK就会记录,期待收到5号包。过了一段时间,5号包收到了,那么下一轮ACK会更新编号。如果5号包还是没收到,但是收到了6号包或7号包,那么ACK里面的编号不会变化,总是显示5号包。这会导致大量重复内容的ACK。
如果发送方发现收到三个连续的重复ACK,或者超时了还没有收到任何ACK,就会确认丢包,即5号包遗失了,从而再次发送这个包。通过这种机制,TCP保证了不会有数据包丢失。
hostB没有收到100-120这段编号的数据包,会重复发ACK=100,触发hostA重发数据包