目录
http的缺点
https
安全与加密
运营商挟持
常见的加密方式
对称加密
非对称加密
数据摘要(数据指纹)
不安全加密策略
1 只使用对称加密
2 只使用非对称加密
3 双方都是用非对称加密
4 对称加密和非对称加密
解决方案
CA证书
http的缺点
我们可以使用 postman 来抓取一个 http 报文,或者是使用 fiddler 来抓取局域网也任意一个 http 报文,我们就能发现,这些报文竟然都是明文传送的,可以说是完全透明的,那么只要被同局域网内的其他人抓包,那么就相当于泄露了,不管是以什么方法提交的http报文,他们在网络中都是明文的。尤其是未来我们使用HTTP协议进行用户信息的提交,不管是GET还是POST提交,他们都是明文的,被抓到包就泄露了。
我们的报文在网络中是明文的,对于一些重要的的数据,如果被不法分子拿到,那么就泄露了。所以我们必须要保证数据在网络传输中的安全,于是就引入了https协议
https
https 其实就是在http协议和传输层协议之间加了一层软件,叫做 ssl/tls ,也就是我们说的加密层。
正常http协议请求或响应封装完之后,就直接交给 tcp 进行传输控制了。后面的协议也不会做任何有关数据加密的工作,那么http报文就明文被发送到了网络中。
而https协议则是,在http协议的基础上。形成 http 报文之后,先交给 加密层进行数据的加密,然后再交给传输层进行传输控制。
先不管具体是怎么加密的,我们的报文在 http 层面还是明文的,我们的程序就按http的来处理就行了,而当这个报文交付到传输层以及最终发送到网络中时,这个报文是已经被加密过得了,那么就算在中间被人截胡了,拿到的也是一个加密之后的报文。不管中间是否被截获,对方收获的报文在传输层进行解包之后,会先交给 https 进行解密,那么之后我们又能读到原始的 http 报文,那么就保证了在数据传输过程中的一定的安全。
当然实际上 https 和http是两种不同的协议,只在技术上有一定交集,比如加密前的报文是相似的。未来 tcp 协议可以通过http和https所绑定的端口号的不同,来选择将报文交付给那个端口,交付到对应的协议中进行处理。
安全与加密
什么是加密?
加密其实就是相对于明文传送来说的,明文就是指要传输的消息本身,我们的http就是明文传送的,而相对应的,对明文进行一系列变换,那么就能生成密文。这个转换就是加密的过程。
而加密并不是说就完了,有加密就必须还要有解密,解密就是将密文通过一系列操作转换为原始的明文。
我们拿一个最简单的例子,比如我们要传输的数据是 x (假如就是一个整数),那么如果我们直接将这个原封不动封装到报文中,那么就是明文传送。x就被称为原始数据。 而如果在数据通信之前,我们的客户端和服务器事先约定好,双方在发送和接收数据之前,先必须先进行一次异或操作,双方的异或的值必须实现协商好,比如客户端在发送之前,不直接传送x,而是传输 x^a ,而服务器拿到这个加密后的数据 y 之后,首先要进行 y^a 得到原始数据。
那么即便在网络传输过程中,我们的报文被截获了,数据也并不是原始数据,而是经过加密的数据。
那么我们就把上面的 a 称为密钥。把 x 称为 明文,把 y 称为 密文。对原始数据加密钥的工作就是加密。
在加密和解密过程中,往往需要一个或者多个中间数据,辅助进行这个过程,这样的数据称为密钥。
当然,在实际中的加密和解密过程肯定是要比这个复杂的多的,不可能就是简单的异或操作。
运营商挟持
运营商作为我国网络基础设施的搭建者,在网络的转发中发挥着不可替代的作用,我们所有的网络数据的传输都是要经过运营商搭建的硬件设施,不管是网线还是路由器还是基站等。当然如果仅仅是在一个局域网中进行数据的转发,那么可能就只需要经过网线或者交换机,甚至都不需要经过路由器,就更不要说运营商的服务器了。
但是我们一般访问的服务器都不可能跟我们的设备位于同一局域网,那么就必然是要经过运营商的设备,或者说一般要经过公网,其实我们要讲的就是: 在我们的设备所处的局域网 和 服务器之间,可能隔着 公网或者运营商,我们的报文都是要先经过公网或者运营商,然后由运营商转发到对应的服务器(这一点在我们学到ip层以及链路层时,学习NAT技术之后就会很明显)。那么与此同时,服务器返回给我们的响应也需要先经过公网或者运营商,然后由运营商逐层转发到我们的设备。
那么运营商在帮助我们将报文转发给服务器和将服务器的报文转发给我们的时候,那么运营商同样能对我们的报文本身做一些修改或者其他的操作。假如我们使用的是 http 请求明文传送,如果我们向服务器申请的是一个下载链接,该链接就对应了我们要下载的软件的 url ,那么当服务器返回这个链接给我们的时候,首先也要经过运营商,而我们的下载链接本质上就是字符串,如果我们如果采用明文传送,那么就很有可能被运营商修改,比如可以被运营商将该链接替换为另一个链接,然后再将原来的报头都封装回去,再根据转发的策略转发到到我们的设备上,那么最终我们收到的就不是我们所期望的链接,而是被运营商修改之后的链接了。
这就是运营商劫持。
其实不仅是运营商,在我们和服务器之前还可能存在其他的中间人攻击,因为报文在网络中的传送其实并没有我们想象的那么安全,他也是可能被别人捕捉的,捕捉到对应的报文之后,他甚至还能重新将报文封装起来再发给我们,这对于我们普通用户来说是十分不友好的。
运营商在网络中承担的角色就是基础设施的提供者,任何个人或者企业或者组织想要入网,都需要用到运营商所搭建的基础设施,所以所有的数据必须要经过运营商,这是无可避免的。
既然我们的数据在网络中可能被运营商劫持,也可能被其他的黑客以类似的方式劫持,那么就说名了,在我们的互联网中,明文传送是十分危险的事。
而https 就是在http的基础上多加了一个加密和解密的过程,以此来保证用户的数据的安全。
常见的加密方式
对称加密
对称加密指的是 通信双方使用同一个密钥进行加密和解密。
他的特征就是加密和解密所用的密钥是一样的。
因为双方的加密和解密所用的密钥是同一个,那么加密和解密的速度是比较快的。
当然,我们也要确保这个密钥不能被中间人获得,不然就加密就白做了。
常见的对称加密算法:DES,3DES,Blowfish
对称加密的特点: 算法公开,计算量小,加密速度快,加密效率高。
非对称加密
使用两个不同的密钥分别进行加密和解密。 两个密钥分别是 公开密钥(公钥) 和 私有密钥(私钥) ,由一个公钥和一个私钥形成一堆非对称加密的密钥,那么其中一个进行加密,能够适应另一个进行解密。
公钥一般是向民众公开的,任何人都可以获取,而私钥则必须有通信中的其中持有私钥的一方保管好,不能让别人得知。
公钥和私钥是配对的,我们可以使用其中一个进行加密,然后使用另一个进行解密。
比如:我们使用公钥(私钥)进行加密形成密文,然后对方使用私钥(公钥)进行对密文解密得到原始报文。
至于为什么使用其中一个进行加密,另一个用来解密能够得到原始报文,这就不是我们要考虑的事情了,这涉及到了数论的相关知识。
不管怎么说,如果我们使用私钥进行加密,那么就算中间人截取了我们的报文,也必须要有与这个私钥配对的公钥才能进行解密,就算中间人获得我们的公钥将报文进行解密和修改了,由于他无法得知进行加密的私钥,那么他也无法重新对修改后的报文进行加密,那么这个数据其实对于接收方来说就是丢包了,而不会说收到被别人修改之后的数据。
而如果使用公钥加密,那么有配对的私钥才能对报文进行解密,那么就算报文被中间人劫持,他也无法节目得到原始报文。
非对称加密的最大的缺点究竟是 运算速度非常慢,比对称加密慢得多。
但是在有些场景下他也无可替代。
那么怎么理解一个数据加密之后就是安全的呢?怎么才算安全?
首先我们要明白一点,在计算机世界不存在绝对的安全,任何加密的数据都是可以被破解的,只是消耗的时间和成本的不同。
所以我们所说的安全性都是从算力成本的角度来说的。
如果我们不采取任何加密措施,也就是明文传送,那么对方随随便便就拿到了我们的数据。而如果加密的话,如果我们数据本身的价值不高,而黑客要破解我们的数据的代价可能远超数据本身的价值,这时候我们就称这个加密是安全的。
数据摘要(数据指纹)
数据摘要,其基本原理就是利用单向的散列函数(比如哈希函数)对信息进行运算,生成一串固定长度的数字摘要(本质就是一个固定长度的字符串)。
其实简单理解,就是可以将一个数据(可以很大很大),使用一些算法,比如通过类似哈希函数,生成一个固定长度的字符串,这个字符串唯一性非常强,冲突的概率非常非常低,我们可以认为他就是一个唯一的字符串。(一般是 32 字节或者 40 字节的字符串,也就是 2^128 ,2^160,我们可以认为不会冲突)。
由于摘要的唯一性,我们也称数据摘要为数据指纹。
而如果我们对原始数据做任何小的修改,最终都会导致重新进行数据摘要之后形成的字符串的差异非常明显。
其实我们前面所讲的 session id 就是通过数据摘要来形成的,将我们的 用户信息 进行生成算法生成的一个具有唯一性(至少在该服务器必须要唯一)的字符串最为 cookie 文件名,然后返回给用户。
常见的数据摘要算法:MD5
我们使用哈希算法进行摘要也可以称为哈希摘要。
摘要严格意义来说并不是加密的算法,因为加密必须要能够解密,而我们进行数据摘要的算法是单向的,不可逆(比如我们的哈希函数也是不可逆的)。
那么数据摘要有什么作用呢?
我们举一个简单的例子,比如我们的百度网盘的秒传功能。
当我们要将数据上传到百度网盘,其实就是通过网络将数据发送到对应的存储集群中。但是你真的觉得每一次上传数据在对应的服务器中都真的会为你找一个空间将所有数据进行拷贝吗?百度网盘的用户量是十分大的,每个用户都会进行资源的上传,这就意味着,在百度网盘中的存储设备中,会存在大量的重复资源,而这种情况是十分浪费的,其实相同的资源只需要存在一份,那么将来需要这个资源的用户都去访问这个这一份就行了,没必要存在多份,当然在用户看待必须让他们觉得这份资源是他们所独有的,这个我们不关心了。
但是我们怎么判断要上传的资源在网盘中已经存在相同的资源了呢?数据摘要
其实我们在将资源上传到网盘之前,在我们的客户端本地首先会对我们的资源进行哈希摘要,并不会直接就进行资源的传输,而是先将资源的摘要发送给服务器,由服务器进行判断,看在服务器中是否已经有了相同的资源,百度网盘的服务器中肯定是维护了所有的资源的数据摘要的,数据摘要是怎么来的也很简单,当一个资源在网盘中不存在的时候,就需要真正上传,那么他的数据摘要就会被维护起来。 如果我们的资源的数据摘要在服务器中已经存在了,那么就认为在网盘中已经存在系统的资源,那么其实我们的客户端就不会真正进行上传的操作,在用户看来在他的网盘空间中也保存了该数据,但是实际上可能是通过软连接或者硬连接的方式,来找到真正的资源。而如果服务器没有找到相同的摘要,那么就认为没有该资源,就需要上传。
当然在我们的用户看来,不管客户端是否真正进行上传,我们都只能眼巴巴地盯着客户端显示的慢的一批的上传速度,对应的秒传功能也必须要开通会员之后才能使用。这其中我们也很容易想明白,无需多言。
所有摘要地第一个功能就是对比双方摘要判断两个资源是否是同一份资源。
第二个场景就是在我们的用户信息的保存上:我们的用户信息是通过加密之后交给服务器,服务器在进行解密操作,拿到原始的用户信息。当我们进行注册的时候,其实就是将新增的用户信息保存到服务器的数据库中。而当我们要进行登陆的时候,就是要检测输入的用户信息是否在数据库中存在。
但是这里会存在一个问题,就是涉及到用户信息这类比较私密的信息,必须进行加密处理,即使在服务器内部,我们也不能是直接明文保存。
原因有二:1 如果不加密的话, 用户表泄露,那么所有用户信息就是明文泄露了。
2 企业内部人员我们也不能让其直接明文能够随便看到用户信息。
同时,保存在数据库中的信息,一般长度是固定的,便于设计表结构。
所以在实际上,我们的用户表在设计的时候,并不是直接保存明文的用户信息,而是在注册时,对用户的密码进行摘要,形成一个固定长度的字符串在保存到数据库中,当然用户名还是可以设计成明文的。
对于用户密码这类小文本信息我们也是可以进行数据摘要的,他的唯一性并不会因此而破坏。
那么未来我们在登陆的时候,首先在服务器需要使用相同的算法进行数据摘要,然后拿着摘要出来的字符串在用户表中查找有没有相同的摘要,如果有,就说明用户表中有该用户,那么身份认证成功。
由上可知,数据摘要就是为了对比而产生的,对比两个文件或者两段数据是否是完全相同的。
同时,这个数据摘要在本文的后半部分有大用。
不安全加密策略
在这个部分我们会讲几种加密的策略,以及分析他们的安全性和优缺点。
我们在网络通信中,要解决的问题是什么?
数据被监听和数据被篡改,其实也就是要防止数据被监听,篡改是基于监听之上的
第一种加密策略:
1 只使用对称加密
在对称加密中,同学双方持有相同的密钥,加密和解密都使用这个密钥。
使用对称加密的时候,由于在网络中传输的报文都是经过加密的,只有通信双方持有加密和解密的密钥,那么在通信的过程中,即便我们的报文被黑客截取了,他也无法破解这个报文,因为他没有对应的密钥。
但是真的这么简单吗? 首先我们要明确一点:
首先,我们的服务器其实不止服务一个客户端,与此同时,服务器与每一个客户端进行通信的时候所使用的密钥都必须是不同的,这一点我们不需要多解释。那么服务器就需要维护多个密钥与对应的客户端的关系。
与此同时,如果一个新的客户端与服务器建立连接,在建立连接之前,双方是没有对方的密钥的,建立连接之后通信之前,双方其实需要进行密钥的协商(ssl握手),简而言之就是由一方生成一个对称加密所需的密钥,他要让对方知道,也必须通过网络进行发送,这时候由于还没有完成加密的准备工作,那么其实就只能明文传送了。
而我们将密钥通过网络明文传送,那么中间人或者黑客就能直接拿到我们对称加密的密钥。
中间人也拿到这个密钥,那么我们后续的加密通信其实就形同虚设了,因为他也有我们加密解密所需的密钥S1,能使用这个密钥对报文进行解密,修改报文之后再使用该密钥S1进行加密,那么对端收到报文之后其实是不知道报文被修改了。
所以单纯使用对称加密不安全。
同时,我们也知道了,在密钥协商阶段,我们也必须要想办法讲密钥进行加密处理或者一定的安全机制,不能让密钥在网络中裸奔。
2 只使用非对称加密
非对称加密有一个特点,使用一对密钥,公钥加密只能私钥解密,而私钥加密只能由公钥解密。
那么我们假设两台主机使用非对称加密,那么一方需要生成一对公钥和私钥,那么他这时候是将私钥发给对方还是将公钥发给对方呢?
注意,私钥是必须只能有自己知道的,哪怕你和对方通信,你也不能把私钥给对方。
客户端将自己生成的一对密钥中的公钥通过网络明文发送给服务器,而自己则保留私钥。 那么同样的,中间人还是能够得到这个公钥。
那么在密钥协商之后,我们的主机A持有私钥S1,而中间人和主机B都持有公钥S2
那么从主机A发给主机B的报文,需要经过私钥S1进行加密,同时只能由S2进行解密,那么其实中间人是能够进行解密得到原始报文的。当然这时候中间人无法对其进行修改,因为如果修改了,那么就需要重新加密,而从A到B的报文只能使用S1进行加密。但是中间人还是可以通过解密拿到你的原始报文,因为他可以将A发出的报文拷贝一份,对拷贝的报文进行解密而保留一份加密的报文用来发给主机B,从而不会被双方察觉到。 这时候中间人其实也就监听了A发送给B的报文。
而如果是从B发送给A的报文,使用公钥S2进行加密,那么就只能使用私钥S1进行加密,而S1只有主机A有,那么中间人即使拿到了这个加密的报文,也无法进行解密。
所以目前看来只使用非对称加密只能保证一个方向上的安全,而无法保证双向的安全。
但是,其实非对称加密对一个方向的安全也保证不了。
怎么说呢? 我们的中间人其实不止能够进行密钥的窃取,不要忘了,密钥协商阶段是明文的,它也可以对密钥协商的报文进行替换。
如图:我们的中间人在通信双反进行密钥协商的时候,其实可以截取协商报文,然后自己再生成一对非对称加密的密钥对,然后将自己生成的这个公钥发送给对方。
这时候,主机B收到了一个密钥,他知道是公钥,同时在他看来就是A所发给他的公钥,但是其实中间已经被替换了。
这时候会造成什么后果呢?
A->B:
B->A:
这时候双方的通信的报文都在中间人的掌握之中,中间人可以对其进行篡改。因为他能解密能加密,且通信双方无法察觉
3 双方都是用非对称加密
双方都是用非对称加密,意思就是 首先双方都生成一对非对称加密密钥。然后都将自己的公钥发给对方。
那么往后,A给B发消息的时候要使用 B 给的公钥进行加密,B收到之后使用私钥进行解密。同时B给A发消息的时候使用A的公钥进行加密,A收到之后使用私钥进行解密。
这其实还是和上面没什么区别,因为这时候中间人还是可以截取双方的公钥,替换为自己的公钥发给对方,这时候无非就是中间人多生成一对密钥的事。
这时候其实还是和上面的问题一样,双方的报文都能够被中间人截取,并进行解密和加密,同时A和B都不知道有中间人的存在。
同时,过多使用非对称加密有一个最大的缺点,效率太低,速度非常慢。当然这里的安全性也并没有得到保证。
4 对称加密和非对称加密
为了解决第3种方案的速度慢的问题,于是就有了这种方案。
首先我们知道只使用对称加密的缺点就是他的公钥只能明文传送,能够被截取。
而非对称加密的话速度太慢。
那么如果我们这样做呢?
首先A生成一对非对称加密的密钥对,进行密钥协商,将公钥明文传送给B。
而B生成一个对称加密的密钥,把这个密钥通过A给的公钥进行加密,发送给A。
那么从此往后,A和B之间的通信就使用对称加密的密钥,那么效率自然就高了。这里使用非对称加密的作用就是确保对称密钥的传送的安全性。
但是想想还是很美好,但是还是一样的问题,如果中间人在双方继续非对称加密时的 公钥的交换时,就对其进行了公钥的替换,那么还是没用。
因为我们在方案 2 就已经知道了,非对称加密其实无法保证任意一个方向的安全性。
解决方案
前面这些方案其实都已经使用了加密,而他们之所以出现不安全的问题,本质其实还是因为 第一次进行公钥传送的时候,是明文的,中间人是可以截取并且进行替换的,但是通信双方或者说公钥的接收方却不知道他所收到的公钥是否合法/正确。
所以我们的解决方案要围绕着让客户端(因为一般是服务器生成密钥对,给客户端发送公钥)能够有能力辨别服务器发回来的公钥是否合法。
其实这个问题并不是很好解决的,我们首先要引入一些新的概念。
CA证书
首先,服务器不是想用 https 就能用的,他必须先向CA机构中申请一份数字整数,数字证书中包含申请者信息,公钥信息等。
服务器在密钥协商的时候,直接将整数发送给客户但浏览器,浏览器从证书中获取公钥就行了。
证书的存在就能证明客户端收到的公钥的权威性。
如果客户端收到的CA证书不存在或者说CA证书过期,我们的浏览器会有提示信息的,相信我们在平常的冲浪中也遇到过这种情况。
CA机构是颁发证书的权威机构,当然并不是只有该机构能够颁发证书,由CA机构认证过的子机构都有颁发证书的权力,一般各个地区都有对应的子机构,不过这也不是我们需要关心的。
我们的 https 服务器在上线之前,首先要完成三个工作:
1 制作一个证书签名请求文件( CSR ) , 在制作这个文件之前,申请者首先要生成一对非对称的密钥对,然后将公钥放到这个文件中,同时这个文件中还包含了诸如 域名,申请者信息,联系地址等等.注意私钥还是有个人持有,不需要放到这个文件中。
2 将证书申请交给给CA认证机构进行审核。这个过程可能需要一定时间,因为CA机构需要验证你的信息是否正确等,来确保申请者的合法性。
3 审核完毕之后,申请者会受到证书的下载请求。 那么就可以将证书下载安装到自己的 https 服务器中了。
这是获取一个CA证书的流程。
一个CA证书包含:颁发机构,申请者,版本,摘要算法,数字签名,公钥,有效时间,域名,签名哈希算法,颁发机构的公钥等等内容。
其中,最重要的就是这个 数字签名 和 公钥。
那么CA证书是如何保证 公钥的安全性的呢? 这个公钥是在证书中明文保存的,有没有可能被中间人修改呢?
这就不得不提到这个数字签名了。
数字签名是怎么形成的呢?
首先我们要对一个数据(比如证书中的明文数据) 使用摘要算法得到一个不可逆的散列值,这个摘要就是数据的指纹,然后证书颁发机构使用他自己的私钥对这个 摘要进行加密,加密之后的摘要就是我们所说的 数字签名。
那么浏览器如何验证收到的证书是否被修改呢?
首先浏览器会将整数的明文数据和数字签名分离 ,然后对明文数据 使用相同的哈希摘要算法(在证书中会指明用哪个算法) 得到一个数据摘要。
同时,对证书中的数字签名使用颁发机构的公钥进行解密,得到一个数据摘要。
然后对比这两个摘要是否相同,如果不相同,就说明收到的证书被修改了,那么不信任该证书。而如果相同,则说明该证书没有被修改,那么我们就可以拿到证书中的公钥,这个公钥一定是没有被修改。
数字签名的本质或者说对数据摘要加密 就是为了防篡改。对证书中的任意数据进行篡改都会导致生成的摘要和解密后的摘要对不上。
为什么要对数据进行摘要,然后对数据摘要进行加密,而不直接对原始数据进行加密呢?
原始数据太长,加密速度慢。而是用数据摘要,不会影响这个证书的唯一性,同时缩小了要加密的数据的长度,提高了效率。
中间人如果对明文数据比如公钥做修改,那么就势必导致摘要发生变化,虽然中间人也能将数字签名解密成摘要,但是他无法重新生成数字签名,因为他没有对应的公钥,那么最终客户端的验证就能得知证书被修改。
那么如此一来,证书就能保证我们的客户端收到的公钥一定是合法的服务器的公钥。不会存在被中间人掉包的可能性。
那么这时候要怎么做呢?我们还是要知道,中间人虽然不能修改证书,但是他是能得到公钥的信息的。
这时候,已经能保证 客户端 发给 服务器的报文的安全性。
那么这时候就很简单了,我们的客户端生成一个对称加密的密钥,然后将密钥报文使用S2加密发送给服务器。 当然这个对称密钥的加密报文也可能被中间人截取,但是他这时候却无法对我们的报文进行解密,也就无法得知我们的报文中是什么内容了,自然就无法修改。不考虑客户端和服务端之间的联系直接被中间人全部掐断,这时候服务器就一定能收到客户端所生成的对称加密的密钥。
这时候双方就能够进行对称加密的通信了,因为中间人无法得知双方对称加密的密钥,自然也就无法得知报文内容。
总结:
证书的作用是为了保证非对称加密的密钥协商阶段的安全(让客户端收到正确的公钥)
非对称加密是为了保证对称加密的密钥传输的安全。
而对称加密是为了提高效率,同时也保证了报文的安全。