前言
昨天我们聊到了HTTP协议的各个版本的一些不同之处,今天我们来看看HTTP协议的加密版HTTPS协议是怎么在和黑客积年累月的斗争中发展起来的
1.HTTPS概述
相信大家都知道我们传输数据时,是离不开HTTP协议滴,HTTP采用明文传输的方式,令网络中传输的数据处于一种随时会被窃取、修改、替换的状态
因此HTTPS协议应运而生,HTTPS是在HTTP上建立SSL加密层,并对传输数据进行加密,是HTTP协议的安全版。
HTTPS主要作用是:
(1)对数据进行加密,并建立一个信息安全通道,来保证传输过程中的数据安全;
(2)对网站服务器进行真实身份认证。
2.HTTPS加密方式
大家都知道HTTPS协议做作用是加密,关键在于如何实现的呢?
2.1对称加密
现在有两台设备A、B,A想要对B发送数据,但不想直接发送未加密报文m,于是生成一个密钥k,将要将发送的报文m和密密钥k输入到加密算法KA中,得到加密报文c(便于读者理解此处我们以凯撒密码为例,虽然日常的对称加密大多采用AES加密算法,后续会聊到),c = KA(m, k)
凯撒密码的原理是,将明文报文中的每个字母用字母表后的第k个字母进行替换(允许回绕),比如当密钥k为3,明文报文“i love you”就会变为“I oryh brx”
此时A只对B发送自己的加密密钥k、加密方式、加密报文c,接收到这些信息的B,就可以通过将加密密文c、密匙k输入到解密算法中,得到原始报文m。(m = KB(c, k)),解密算法与加密算法都在都在网上公开可查询
如果在不知道密匙和加密方式的情况下,嗅探到了A、B间的通信。获取了A发送给B的加密报文,也只是一堆乱码,毫无用处(密匙k和加密方式只有A、B间第一次通信时,才会发送给B,后续数据传输不再发送密匙)
中间人拦截
破解的方法也极为简单,只要黑客截取第一次A发往B的加密密钥k、加密方式,之后黑客截取到A、B间通过该密钥和加密算法的加密报文,都可以直接破解,加密加了个寂寞。
事实上,大多数黑客,甚至一些新手借助黑客工具,都可以实现这种攻击方式
AES加密算法(分组加密技术)
对称加密中常见的加密算法,其原理是,生成一个密钥k,将需要加密的密文划分为k比特的块,比如k=64,则报文被划分为64比特的块,每块被独立加密,请看如下例子:
假设k值为3,则报文010110001111被加密成为101000111001
k为三时,其中一种加密表
| 输入 | 输出 |
|---|---|
| 000 | 110 |
| 001 | 111 |
| 010 | 101 |
| 011 | 100 |
| 100 | 011 |
| 101 | 010 |
| 110 | 000 |
| 111 | 000 |
不过这样的加密受手段需要加密者维持一个输入值为2的k次方!阶乘,要想实现加密效果的话k值往往很大,这就使得维持这个加密表几乎难以实现
取而代之的是,块密码常常用函数模拟随机排列表,使得较大的密码表,被拆分为一些小的密码表,方便管理
2.2非对称加密(公开密钥加密)
相当经典的加密方式,我们仍用设备A、B举例,A通过算法P生成一个公钥k1和和私钥k2,A向全世界公布自己的公钥k1,别的设备比如B想要对A发送数据,就会先用公钥k1对原始报文m进行加密,得到加密密文c,然后将密文发送给A,该密文只能使用A自身的私钥进行解密,也就是说原始报文m = P(c, K2),c为加密密文,这样黑客就很难获取私钥用于解密数据,因为私钥至始至终都不用于传输,也就很难被获取
那是不是非对称加密就如此完美呢?
非对称加密当然有自己的问题
加密效率慢、加密解密成本高、仍然存在被暴力破解的风险,并且未来可能会出现的高算力量子计算机,可能会对这种加密方式构成威胁
或许我们能从一种经典的非对称加密算法RSA的研究,来得知非对称加密为什么会出现这些问题
RSA算法
我们要做一些知识前置铺垫:模n算术的算术运算
首先看符号用于取余数的符号mod,示例:19 mod 5 = 4
设整数a、b、n,在模n算术中的加法与乘法满足以下等式:
[(a mod n) + (b mod n)] mod n = (a + b) mod n
[(a mod n) - (b mod n)] mod n = (a - b) mod n
[(a mod n) * (b mod n)] mod n = (a * b) mod n
由第三个式子不难得出,(a mod n)^d mod n= a^d mod n (a^d代表a的d次方)
好了,现在正式生成我们的RSA公钥与私钥
1.选择任意两个数值比较大的素数p和q
2.计算n = pq 和 z = (p - 1)(q - 1)
3.选择一个小于n的一个数e,且使e和z没有(非1的)公因数(也就是令e与z互素)
4.设一个数d,使得ed - 1可以被z整除,也就是说给定值e,使得ed mod z = 1
5.此时A在使用RSA加密方法时,对数(n, e)就作为公钥k1,对数(n, d)就作为私钥k2
设备A、设备B的加密、解密过程如下:
A通过公开手段,到处发布自己的公钥k1。
B在得知A的公钥k1后,想要对A发送一个由整数m表示的比特组合m(原始报文),使用公钥 k1对原始报文m加密处理(m < n),B对m进行指数运算m^e,然后计算m^e被n整除的余数,得到加密密文c,也就是: c = m^e mod n (c为加密密文)
B向A发送密文c,此时A就可以通过私钥解开这个报文,既:m = c^d mod n,获取B的原始报文m
我们一定对RSA中的加密解密原理仍存疑虑
上面提到加密是报文m使用模n算术做e的次冥运算,即
c = m^e mod n
解密则先对该值执行d次冥运算,再做模n运算,即
(m^e mod n)^d mod n
我们可以由这个式子(a mod n)^d mod n= a^d mod n (a^d代表a的d次方)推出
(m^e mod n)^d mod n = m^(e * d) mod n
此时我们补充数论当中的一个结论:
如果p和q是素数,且有n = pq以及z = (p - 1)(q - 1),则x^y mod n = x^(y mod z) mod n 此时我们x = m和y = ed,可得
m^(e * d) mod n = m^(ed mod z) mod n
之前我们说过ed mod z = 1
那么m^(ed mod z) mod n = m^1 mod n = m
神奇的是,如果我们先进行解密,再进行加密操作,得到的结果仍然是m
((m^d) mod n)^e mod n = m^(d * e) mod n = (m^e mod n)^d mod n
RSA的安全性来源于,已知目前没有任何一种算法,可以对一个公开值进行快速的因式分解
当然,随着时间的变迁,或许使用RSA算法加密的数据也会饱受安全威胁
2.3混合加密(会话密钥)
我们能推测出,RSA所要求的指数运算会消耗大量时间。所以在实际HTTPS协议的传输数据过程中,RSA通常与对称密钥密码结合使用。譬如A现在要向B发送大量数据,首先A会选择一个用于加密数据本身的密钥(这个密钥的生成并不像RSA密钥生成那么复杂,AES或者DES)我们称之为会话密钥,然后A使用B的公钥对会话密钥进行加密,之后将就加密的会话密钥发送给A,B使用私钥进行解密,得到会话密钥,之后双方就可以通过会话密钥来进行加密传输。
- 本质:先进行非对称加密,传递对称加密密钥,之后再使用对称加密(传输过程中不带密钥),这样不仅拥有优良的安全性,同时对称加密的高效率传输数据的特点也得以发挥
2.4报文完整性验证与数字认证
在上一环节中,我们已经有了比较好的对数据加密方式,然而数据在传输过程中,是否被篡改,也是我们所关心的问题
仍然是我们的老嘉宾设备A和设备B,假设B接收到一个报文,并且B认为该报文是由A发出,那么为了鉴别这个报文,B需要证实: 1.该报文的确来自于A 2.该报文中途是否被篡改
密码散列函数
我们仍需要一些前置知识铺垫:密码散列函数
我们将原始报文m作为散列函数的输入,并计算得到一个称为散列的固定长度的字符串H(m),密码散列函数,确保了H(m)值有以下属性:
- 找到任意两个报文x和y,都无法使得H(x) = H(y),也就是说,每个文件都可以通过散列函数计算出一个唯一的值,来证明其身份
目前使用较为广泛的散列算法有MD5和SHA-1等
补充:
在实际开发中,我们的文件快传功能(客户端传输文件给服务端,会比较双方文件中的MD5或者Hash值,如果有一致的文件,则取消传输,直接使用服务端中的文件),正是散列函数应用的一个扩展
报文鉴别码
那么我们的报文完整性验证如何来做呢?
1.A生成报文m,并且计算散列H(m)
2.A向B发送的报文中,带有H(m),生成一个扩展报文(m, H(m))
3.B接到一个扩展报文(m, H(m)),通过散列函数来计算H(m)的值,如果得到的值,和扩展报文中的H(m)一致,就能说明该报文未被篡改吗?
显然,这种做法存在极大缺陷,只要有一个设备C,向B声明自己是A,并且发送一个以自己报文得出的扩展报文(m^, H(m^)),这样当B成功核对以后,就会认为C就是A
为了确认报文完整性,除了散列函数之外,我们还需要A、B间互相知晓一个鉴别密钥s(非公开),报文完整性能够如以下执行:
A将s级联m以生成m+s,放入散列函数计算,得到H(m + s),然后A将扩展报文(m, H(m + s))发往B,B接到扩展报文之后,只有将接收到的m与自身已知的密钥s结合,通过散列函数计算出值,与H(m + s)相比较,如果值等于H(m + s),就能认为报文未被篡改
数字签名
我们在前面得知,在RSA算法中,先对数据进行解密,再进行加密操作,得到的结果仍然是m,这为我们的数字验证提供了很好的思路,换句话说,B使用私钥对数据进行加密,其它设备,只有使用B公开的密钥,解开这个数据,这无疑验证了B的身份,其次如果初始文档被修改过,比如m变为了文档m^,但是B为m生成的签名对m^无效,因为K公钥加密(K私钥解密(m)),即((m^d) mod n)^e mod n = m^(d * e) mod n = (m^e mod n)^d mod n的结果不会为m^,这无疑验证了报文的完整性
在实际应用中,由于直接对数据进行数字签名,效率低下,实用性并不强,所以现代的浏览器厂商一般采取私钥加密报文m的散列函数值H(m)的方式,直接发送一个用于验证身份的原始明文报文,以及私钥加密过后的散列函数值H(m),接收方通过公钥解密之后,通过m计算出散列值,与接收的散列函数值H(m)比较,如果相当,则可以确信报文完整性以及发送方身份真实性
公钥认证
上面提到的数字签名方式并非没有破绽
中间人攻击
设备A、B间要进行数据传输,采取混合加密方式,B首先要向A发送公钥,此时,中间人C就有了可乘之机,C向A声明自己就是B,为发送自己公钥,A认为这是B的公钥,之后C就可以假装自己为B,与A进行通信,给A下达一些带有特殊目的的指令
预防方式
在日常的通信中,我们通常求助于一些权威的认证中心(CA),它们会帮我们验证我们具有的公钥就是与我们要通信的那个实体