掘金 后端 ( ) • 2021-07-09 15:42
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body .contains-task-list{padding-left:0}.markdown-body .task-list-item{list-style:none}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}

为什么需要加密

通过互联网交换数据时,数据要经过各种各样的网络和设备才能传到对方那里。数据在传输过程中有可能会经过某些恶意用户的设备,从而导致内容被盗取。因此,要想安全地使用互联网,安全技术是不可或缺的。

传输数据时的四个问题

互联网传输数据时可能会发生的四个主要问题:

  • 窃听:A向B发送的消息可能会在传输途中被X偷看,这就是窃听
  • 假冒:A以为向B发送了消息,然而B接受的消息有可能是X冒充的
  • 篡改:B确实收到了A发送的消息,但是该消息的内容在途中就被X更改了,除了被第三方篡改,通信故障导致的数据损坏也可能会使消息内容发生变化。
  • 事后否认:B从A那里收到了消息,但作为消息发送者的A可能对B抱有恶意,并在事后声称"这不是我发送的消息啊"
image-20210709142112187

为了解决这些问题,我们需要使用哪些安全技术呢

  • 应对窃听,我们会使用加密技术
  • 应对假冒、篡改,我们会使用消息验证码或数字签名技术
  • 应对事后否认,我们使用数字签名

一些基本的概念

  • 加密就是用密钥对数据进行数值运算,把数据变成第三者无法理解的形式的过程
  • 解密就是通过密钥进行数值计算,把密文恢复成原本数据的过程。

哈希函数

哈希函数可以把给定的数据转换成固定长度的无规律数值。转换后的无规律数值可以作为数据摘要应用于各种各样的场景。

  • 第一个特征是输出的哈希值数据长度不变,即使输入了相当大的数据,输出的哈希值的长度也保持不变。
  • 第二个特征是如果输入的数据相同,那么输出的哈希值也必定相同。
  • 第三个特征是即使输入的数据相似,但哪怕它们只有一比特的差别,那么输出的哈希值也会有很大的差异。输入相似的数据并不会导致输出的哈希值也相似
  • 第四个特征是即使输入的两个数据完全不同,输出的哈希值也有可能是相同的,虽然出现这种情况的概率比较低。这种情况叫作哈希冲突
  • 第五个特征是不可能从哈希值反向推算出原本的数据。输入和输出不可逆这一点和加密有很大不同。
  • 第六个特征是哈希值的计算相对容易,就是说执行效率很高

哈希函数的算法中具有代表性的是MD5、SHA-1和SHA-2等。其中SHA-2是现在应用较为广泛的一个,而MD5和SHA-1存在安全隐患,不推荐使用。

加密方法

加密数据的方法可以分为两种:

  • 加密和解密都使用相同密钥的共享密钥加密
  • 加密和解密都使用不同密钥的公开密钥加密

1.对称加密

共享密钥加密是加密和解密都使用相同密钥的一种加密方式。由于使用的密钥相同,所以这种算法也被称为对称加密

先来了解下共享密钥加密的处理流程:

  1. A使用密钥加密数据,然后将密文发送给B。
  2. B收到密文后,使用相同的密钥对其进行解密。这样B就取得了原本的数据。只要是加密好的数据,就算被第三者恶意窃听也无须担心

image-20210709142224341

实现共享密钥加密的算法有凯撒密码、AES[插图]、DES[插图]、动态口令等,其中AES的应用最为广泛

接下来想一想共享密钥加密中的问题

  • 密文可能已经被X窃听了。这里假设A和B无法直接沟通,B不知道加密时使用的是什么密钥。A需要通过某种手段将密钥交给B。和密文一样,A又在互联网上向B发送了密钥。B使用收到的密钥对密文进行解密。但是,该密钥也有可能会被X窃听。这样一来,X也可以使用密钥对密文进行解密了。 - 如何将蜜月安全的发送给B,这其实是密钥分配问题

2.非对称加密

公开密钥加密是加密和解密使用不同密钥的一种加密方法。由于使用的密钥不同,所以这种算法也被称为非对称加密。加密用的密钥叫作公开密钥,解密用的叫作私有密钥

公开密钥加密的处理流程:

  1. 由接收方B来生成公开密钥Public Key和私有密钥Secret Key
  2. 然后接收方B把公开密钥发送给数据发送方A
  3. A使用B发来的公开密钥加密数据
  4. A将密文发送给B, B再使用私有密钥对密文进行解密。这样,B就得到了原本的数据

image-20210709142247446

了解下就行:

  • 实现公开密钥加密的算法有RAS算法、椭圆曲线加密算法等,其中使用最为广泛的是RSA算法。RSA算法由其开发者Rivest、Shamir、Adleman的首字母命名而来,三人在2002年获得了图灵奖。

  • 公开密钥和密文都是通过互联网传输的,因此可能会被X窃听。但是,使用公开密钥无法解密密文,因此X也无法得到原本的数据。因此公开密钥是不怕被人知道的,所以B可以把公开密钥发布在网上。与此相反,私有密钥不能被人知道,必须严密保管。

  • 如果使用共享密钥加密,密钥的需求数量会随着发送人数的增多而急剧增多。具体公式为需要的密钥数=n(n-1)/2,其中N为人数,那么2人就需要2个密钥,5人就需要10个,100个人就需要4950个

  • B用私有密钥对收到的密文进行解密,取得原本的数据。这种情况就不需要为每个发送对象都准备相对应的密钥了。需要保密的私有密钥仅由接收方保管,所以安全性也更高。

不过,公开密钥加密存在公开密钥可靠性的问题:

  1. 让我们回到B生成公开密钥和私有密钥的时候。在接下来的说明中,B生成的公开密钥用PB来表示、私有密钥用SB来表示。
  2. X想要窃听A发给B的数据,于是他也准备了公开密钥PX和私有密钥SX
  3. 在B把公开密钥PB发给A的时候,X把公开密钥PB替换成自己的公开密钥PX
  4. 于是公开密钥PX传到了A那里。由于公开密钥无法显示自己是由谁生成的,所以A不会发现自己收到的公开密钥已经被人替换。于是A使用公开密钥PX对数据加密。
  5. 当A把想要给B的密文发送出去后,X接收了这个密文。这个密文由X生成的公开密钥PX加密而成,所以X可以用自己的私有密钥SX对密文进行解密。
  6. 接下来,X用B生成的公开密钥PB加密数据。
  7. X把密文发送给B,这个密文由B发出的公开密钥PB加密而成,所以B可以用自己的私有密钥SB来解密。从收到密文到解密密文都没发生任何问题,因此B也意识不到数据已经被窃听。这种通过中途替换公开密钥来窃听数据的攻击方法叫作“中间人攻击”(man-in-the-middle attack)

image-20210709142331519

公开密钥存在的问题

  1. 公开密钥的可靠性会出现问题,就是因为A无法判断收到的公开密钥是否来自B。要想解决这个问题,就要用到之后会讲到的“数字证书”。
  2. 公开密钥加密还有一个问题,那就是加密和解密都比较耗时,所以这种方法不适用于持续发送零碎数据的情况。要想解决这个问题,就要用到“混合加密”。

3.混合加密

共享密钥加密存在无法安全传输密钥的密钥分配问题,公开密钥加密又存在加密解密速度较慢的问题。结合这两种方法以实现互补的一种加密方法就是混合加密。在混合加密中,要用处理速度较快的共享密钥加密对数据进行加密。不过,加密时使用的密钥,则需要使用公开密钥加密进行处理。

混合加密的处理流程如下:

  1. 假设A准备通过互联网向B发送数据。使用处理速度较快的共享密钥加密对数据进行加密。加密时所用的密钥在解密时也要用到,因此A需要把共享密钥发送给B
  2. 为了将共享密钥PA安全的发送给接收方B,我们需要传输共享密钥PA时需要使用公开密钥加密,因此,接收方B需要事先生产公开密钥PB和私有密钥SB
  3. 公开密钥传输:B将公开密钥发送给A,A使用收到的公开密钥,对共享密钥加密中需要使用的密钥进行加密,B使用私有密钥对密钥进行解密
  4. 数据传输:A就把共享密钥加密中使用的密钥安全地发送给了B。接下来,A只要将使用这个密钥加密好的数据发送给B即可。加密数据时使用的是处理速度较快的共享密钥加密。

image-20210709142357900

像这样,混合加密在安全性和处理速度上都有优势。能够为网络提供通信安全的SSL协议也应用了混合加密方法。SSL是Secure Sockets Layer(安全套接层)的简写,该协议经过版本升级后,现在已正式命名为TLS(TransportLayer Security,传输层安全)。但是,SSL这个名字在人们心中已经根深蒂固,因此该协议现在也常被称为SSL协议或者SSL / TLS协议。

4.迪菲-赫尔曼密钥交换z

混合加密虽然解决了公开加密耗时的问题,但是密钥传输时公开密钥可靠性的问题并没有解决,依然存在中间人攻击的风险。那么如何安全的进行密钥传输呢?

迪菲-赫尔曼(Diffie-Hellman)密钥交换是一种可以在通信双方之间安全交换密钥的方法。这种方法通过将==双方共有的秘密数值==隐藏在公开数值相关的运算中,来实现双方之间密钥的安全交换。

我们先来理解一下这个算法的概念

假设有一种方法可以合成两个密钥。使用这种方法来合成密钥P和密钥S,就会得到由这两个密钥的成分所构成的密钥P-S,这种合成方法有三个特征:

  1. 即使持有密钥P和合成的密钥P-S,也无法把密钥S单独取出来。即密钥之间可以合成,但不能分解
  2. 合成的密钥,可以作为新的元素,继续与别的密钥进行合成。比如使用密钥P和密钥P-S,还能合成出新的密钥P-P-S。即合成后的密钥可以继续合成
  3. 密钥的合成结果与合成顺序无关,只与用了哪些密钥有关。即ABC和BAC是一样的

我们来看下密钥交换的过程

  1. 首先由A生成密钥P,然后将密钥P发送给B。然后A和B各自准备自己的私有密钥SA和SB
  2. A利用密钥P和私有密钥SA合成新的密钥P-SA,B也利用密钥P和私有密钥SB合成新的密钥P-SB
  3. 双方交换合成密钥,即A将密钥P-SA发送给B, B也将密钥P-SB发送给A
  4. 将私有密钥SA和收到的P-SB合成为新的密钥SA-P-SB,B也将私有密钥SB和收到的P-SA合成为新的密钥P-SA-SB。根据之前的假设,A和B都得到了密钥P-SA-SB,这个密钥将作为双方的共享密钥进行数据加密

image-20210709142435895

下面我们来验证该密钥交换的安全性。因为密钥P、密钥P-SA和密钥P-SB需要在互联网上进行传输,所以有可能会被X窃听。但是,X无法用自己窃听到的密钥合成出P-SA-SB,因此这种交换方式是安全的。

image-20210709142449586

使用迪菲-赫尔曼密钥交换,通信双方仅通过交换一些公开信息就可以实现密钥交换。但实际上,双方并没有交换密钥,而是生成了密钥。因此,该方法又被叫作“迪菲-赫尔曼密钥协议”。

5.消息认证码

前面我们可以使用迪菲赫尔曼方法安全的交换共享密钥了,但是密文的内容在传输过程中可能会被篡改,这会导致解密后的内容发生变化,从而产生误会。消息认证码就是可以预防这种情况发生的机制,消息认证码可以实现认证和检测篡改这两个功能

消息验证码的处理流程如下:

  1. A生成了一个用于制作消息认证码的密钥,然后使用安全的方法将密钥发送给了B。
  2. 接下来,A使用密文和密钥生成一个值。此处生成的是7f05。这个由密钥和密文生成的值就是消息认证码,以下简称为MAC(Message Authentication Code)。
  3. A将MAC(7f05)和密文发送给B。B也需要使用密文和密钥来生成MAC。经过对比,B可以确认自己计算出来的7f05和A发来的7f05一致。

我们可以把MAC想象成是由密钥和密文组成的字符串的“哈希值”。计算MAC的算法有HMAC[插图]、OMAC[插图]、CMAC[插图]等。目前,HMAC的应用最为广泛。

消息验证码存在的不足

​然而消息验证码也有缺点。在使用消息认证码的过程中,AB双方都可以对消息进行加密并且算出MAC。也就是说,我们无法证明原本的消息是A生成的还是B生成的[事后否认]。因此,假如A是坏人,他就可以在自己发出消息后声称“这条消息是B捏造的”,而否认自己的行为。如果B是坏人,他也可以自己准备一条消息,然后声称“这是A发给我的消息”。使用MAC时,生成的一方和检测的一方持有同样的密钥,所以不能确定MAC由哪方生成

6.数字签名

​数字签名不仅可以实现消息认证码的认证和检测篡改功能,还可以预防事后否认问题的发生。==由于在消息认证码中使用的是共享密钥加密,所以持有密钥的收信人也有可能是消息的发送者,这样是无法预防事后否认行为的==。而==数字签名是只有发信人才能生成的==,因此使用它就可以确定谁是消息的发送者了。

数字签名的处理流程

  1. 假设A要向B发送消息。在发送前A给消息加上自己的数字签名,只要发送的消息上有A的数字签名,就能确定消息的发送者就是A。
  2. B可以验证数字签名的正确性,但无法生成数字签名。

接下来看一看数字签名具体是怎样生成的吧

数字签名的生成使用的是公开密钥加密,我们先来回顾下前面的知识。公开密钥加密中,加密使用的是公开密钥P,解密使用的是私有密钥。任何人都可以使用公开密钥对数据进行加密,但只有持有私有密钥的人才能解密数据。然而,数字签名却是恰恰相反的。

  1. 首先由A准备好需要发送的消息、私有密钥和公开密钥。由消息的发送者来准备这两个密钥,这一点与公开密钥加密有所不同。
  2. A将公开密钥发送给B,然后A使用私有密钥加密消息。加密后的消息就是数字签名
  3. A将消息和签名都发送给了B。B使用公开密钥对密文(签名)进行解密。B对解密后的消息进行确认,看它是否和收到的消息一致。流程到此结束

image-20210709142509531

补充说明

  1. 公开密钥加密的加密和解密都比较耗时。为了节约运算时间,实际上不会对消息直接进行加密,而是先求得消息的哈希值,再对哈希值进行加密,然后将其作为签名来使用
  2. 虽然==数字签名可以实现“认证”“检测篡改”“预防事后否认”三个功能==,但它也有一个缺陷。那就是,虽然使用数字签名后B会相信消息的发送者就是A,但实际上也有可能是X冒充了A。其根本原因在于使用公开密钥加密无法确定公开密钥的制作者是谁。收到的公开密钥上也没有任何制作者的信息。因此,公开密钥有可能是由某个冒充A的人生成的。这个理解起来还是挺难的,但是可以简单理解成如果黑客X足够厉害,那么他完成可以把自己伪装成A和B进行通信,从而发一些非法指令。

7.数字证书

公开密钥加密和数字签名无法保证公开密钥确实来自信息的发送者。因此,就算公开密钥被第三者恶意替换,接收方也不会注意到。不过,如果使用数字证书,就能保证公开密钥的正确性。

  1. A持有公开密钥PA和私有密钥SA,现在想要将公开密钥PA发送给B
  2. A首先需要向认证中心(Certification Authority, CA)申请发行证书,证明公开密钥PA确实由自己生成。
  3. 认证中心里保管着他们自己准备的公开密钥PC和私有密钥SC
  4. A将公开密钥PA和包含邮箱信息的个人资料发送给认证中心。
  5. 认证中心对收到的资料进行确认,判断其是否为A本人的资料。确认完毕后,认证中心使用自己的私有密钥SC,根据A的资料生成数字签名。
  6. 认证中心将生成的数字签名和资料放进同一个文件中,然后,把这个文件发送给A。这个文件就是A的数字证书
  7. A将作为公开密钥的数字证书发送给了B。
  8. B收到数字证书后,确认证书里的邮件地址确实是A的地址。接着,B获取了认证中心的公开密钥。
  9. B对证书内的签名进行验证,判断它是否为认证中心给出的签名。证书中的签名只能用认证中心的公开密钥PC进行验证。如果验证结果没有异常,就能说明这份证书的确由认证中心发行。
  10. 确认了证书是由认证中心发行的,且邮件地址就是A的之后,B从证书中取出A的公开密钥PA。这样,公开密钥便从A传到了B。

再来看看公开密钥的交付过程有没有什么问题

  1. 假设X冒充A,准备向B发送公开密钥PX,但是B会用验证来判断是否为认证中心颁发的数字证书
  2. 假设X为了假冒A,准备在认证中心登记自己的公开密钥。然而X无法使用A的邮箱地址,因此无法获得A的证书。

参考

《我的第一本算法书》