你可以带着以下目的进行学习:
SSL:安全套接字层(Secure Socket Layer),是TLS的前身。
TLS:安全传输层协议的简称(Transport Layer Security)。
历史发展时间线如上图所示。
1995年由Netscape发布 SSL 2.0
1996年由Netscape发布 SSL 3.0
1999年由IETF在RFC 2246中首次定义 TLS 1.0,作为SSL 3.0的升级
2006年由IETF在RFC 4346发布 TLS 1.1
2008年由IETF在RFC 5246发布 TLS 1.2
2018年由IETF在RFC 8446发布 TLS 1.3
2011年弃用 SSL 2.0
2015年弃用 SSL 3.0
2020年弃用 TLS 1.0 与 TLS 1.1
截至2020年,只有TLS 1.2和TLS 1.3仍然有效。
举三个生活中常用的示例:
TLS 为我们解决了 3 件事:
如上图所示,TLS工作流程由2个阶段(或2个协议)组成:
1、握手协议(Handshake protocol),其主要目的是进行身份验证和密钥交换,该阶段主要涉及以下步骤:
- 协商 TLS 协议版本。
- 选择密码算法或密码套件。
- 通过非对称密钥相互认证。
- 建立一个将用于下一阶段的共享密钥(对称加密密钥)。
2、记录协议(Record protocol),其主要目的是确保消息传输的机密性和完整性,该阶段主要涉及以下步骤:
- 使用握手中建立的共享密钥对发出的消息进行加密。
- 将加密后的消息传输到另一侧。
- 验证消息是否在传输过程中进行了修改。
- 使用握手中建立的共享密钥对接收的消息进行解密。
由于客户端与服务器大量的数据加解密交换发生在记录协议阶段,故又因该阶段解密数据量很大,又称该阶段为批量加密。
可以看出,TLS在整个流程中同时使用了对称和非对称加密两种方式,那为什么不只使用一个?
在介绍SSL/TLS的完整握手流程之前,我们先了解下对称加密与非对称加密的相关内容,关于SSL/TLS的完整握手流程将在第四个大标题中讲解。
(如上图所示)首先,Alice有一条纯文本消息,她想发送给Bob,但不希望互联网中的任何人都可以阅读。因此她使用他们之前彼此共享过的共享密钥(Shared secret key)对消息进行加密,然后通过互联网将加密的消息发送给Bob,Bob收到加密的消息后,他可以轻松的使用相同的密钥对其进行解密。由于该密钥用于加密和解密,且加密和解密的过程是对称的,故称该过程为对称加密过程。
似乎加密的数据就很安全?黑客仍然可以采用翻转攻击的方式破坏加密后的数据。
(如上图所示)现在,有一个可以在互联网上捕获他们交流信息的黑客Harry。但是,该消息已被加密,而Harry没有密钥,因此他将无法对其解密。但是他仍然可以改变消息,通过一种称为翻转攻击的技术。假设这一次,Alice不是在跟Bob通信,而是在和她的网上银行通信,此时Alice想转账$100给某人,该消息通过密钥进行加密后通过互联网发送给银行。此时,Harry捕获到了加密的消息,虽然他无法解密,但是他可以将某些位从1翻转为0,从0翻转为1,然后将修改后的消息转发到银行,当银行解密后将获得不同的消息内容,在这种情况下,转账金额变成了$900而不是$100,因此非常危险。
那么,这就是需要我们在收到加密的数据后,有方法确保加密的消息在传输过程中未被更改。该如何确保呢?使用认证加密。
认证加密包括对消息的加密和验证过程。
(如上图所示)该指示的是加密的过程,该过程可分为两个步骤,其一是对消息的加密,其二是为加密信息生成消息认证码。
(如上图所示)在TLS 1.3中,除了加密的消息外,我们还想验证一些关联数据(Associated Data),例如地址(addresses)、端口(ports)、协议版本(protocol version)或序列号(sequence number),这些信息是未加密,且通信双方均知晓的 。在TLS 1.3中,将这些关联数据也作为MAC算法的输入,因此,整个过程又称为带有关联数据的认证加密(Authenticated Encryption with Associated Data,简称AEAD)
接下来我们将看到Bob如何验证加密的消息在传输过程中是否被更改。
(如上图所示)这是一个加密的反向过程。
从带有MAC的加密消息开始,我们将从加密的消息中经过提取(Untag)过程,获的MAC(ae6f21b)和不带有MAC的加密消息。然后,加密的消息、共享密钥、随机数(注意该随机数和加密过程中的随机数相同,在将消息发送给对方时,会将随机数填充到加密的消息中)以及关联数据作为MAC算法的输入,然后输出一个新的MAC值。现在,Bob可以简单地比较两个MAC值,如果它们不同,则表示加密的消息已被更改,否则,他可以安全地解密内容,并充分相信这与Alice发送的消息相同。
但是,Bob和Alice如何在不泄露给公众的情况下实现共享密钥的交换?
(如上图所示)为此,他们需要使用一种能够生成共享密钥的密钥建立协议,例如Diffie-Hellman Ephemeral(DHE)或Elliptic Curve Diffie-Hellman Ephemeral(ECDHE)。
接下来我们了解下Diffie-Hellman在密钥交换中的工作原理。
(如上图所示)首先基数 g 和模数 p,这两个数字是众所周知的,且Bob和Alice都知晓这两个数字。其次Bob和Alice都拥有一个私钥,Alice的私钥是 a,Bob的私钥是 b。准备就绪后,现在开始进行密钥交换:
因此,Alice和Bob具有了相同的密钥S,而没有将其泄露给公众。
但是请记住,不同加密算法输出的密钥长度是不相同的。因此,Alice和Bob必须使用相同的密钥派生函数制作密钥,输出相同长度的密钥S。在TLS 1.3中,使用的密钥派生函数是HMAC-based key derivation function,所以这是为什么命名HKDF的原因。
让接下来我们将进一步了解密钥派生函数工作原理。
密钥派生函数(Key Derivation Function),简称KDF。
(如上图所示)通常,KDF需要五个输入参数:
通过这些输入参数,KDF将输出指定长度的密钥(Key of required length)。
陷门函数(Trapdoor function),是一种进行正向计算很容易,反向计算极其困难的函数。
(如上图所示)现在,我们继续讨论Diffie-Hellman密钥交换问题。在Diffie-Hellman示例中,由于p、g、A、B都是众所周知的,这意味着黑客Harry也可以访问这些数字。我们可能会产生疑问:根据p、g、A、B和给定函数能否计算出a、b和S?这种密钥交换机制安全吗?
答案是安全的,因为这些用于计算的函数均是陷门函数。例如,如果我们为p、g、a、b选择好一个值,例如选择p作为2048位素数,选择g作为p的模,并选择a、b为256位随机整数,在这种情况下,给定p、g和a很容易计算出A,但是给定p、g和A,要计算出a很难。很容易看书,A可以用O(log(a)) 时间复杂度快速计算,这是一个模块化求幂问题。另一方面,计算a是一个离散对数问题,计算起来要困难得多,这需要我们当前的计算机花费很长的时间解决。所以我们目前的使用Diffie-Hellman至少是安全的,或者直到下一代强大的量子计算机出现后才会受到影响。
虽然Diffie-Hellman是一个需要很长时间解决的问题,但是并不意味着无法解决,是吗?
如果我们在会话过程中使用的都是固定的密钥S,又名静态密钥(Static Key),将会产生潜在的危险,具体分析如下。
(如上图所示)如果Alice和Bob在他们交流的每个环节中,都使用固定的私钥a和b,然后发生的是,Harry可以记录所有这些会话,然后从Session1开始解决a问题,尽管他要花很长时间才能解决,假设在SessionN之后,他得到了正确的a,然后他可以用a来计算出密钥S,从而他将能解密出所有记录的会话内容。
以上情况看起来很吓人!我们要如何预防呢?
答案是使用临时密钥(Ephemeral Key)。
(如上图所示)顾名思义,我们在每个会话中使用不同的密钥(S1、S2…),即使Harry可以解决一次会话的密钥,他也不能将该密钥用于其他会话。这在TLS中称为完全前向保密(Perfect Froward Secrecy)。
目前为止,我相信你已经完全了解了Deffie-Hellman Ephemeral DHE的含义,即使用临时密钥的Deffie-Hellman密钥建立协议。
非对称加密可用于以下三个方面:
在学习数字签名算法之前,先来学习下非对称加密系统是如何工作的?
在非对称加密体系中:公钥和私钥是成对出现的,若是公钥加密,则私钥解密,若是私钥加密,则公钥解密,即互相解密,在私钥加密的情形中,又常称为私钥签名,公钥验证。即使用场景为:
(如上图所示)同对称加密一样,Alice想发送一条消息给Bob,但是这一次,没有共享密钥,而是使用非对称加密的公私钥,Alice使用Bob的公钥(Bob’s public key)对消息加密,并将加密的消息发送给Bob,当Bob收到消息时,它使用自己的私钥(Bob’s private key)对其进行解密,尽管公钥和私钥不同,但是它们仍然可以通过一些陷门函数关联在一起,就像我们在Diffie-Hellman算法中看到的一样。
在非对称加密的情况下,即使黑客Harry可以访问Alice的加密消息和Bob的公钥,他也不能使用Bob的公钥来解密消息。
由非对称加密原理可知,分享公钥变得极其简单,Bob可以直接通过互联网将密钥发送给Alice,无用担心公钥可用于解密任何消息。公钥分享的关键是完全公开的,因此,任何人都可以使用它来加密只有Bob可以阅读的消息,其分享流程如下图所示。
你认为这个公钥分享方案真的安全吗?
若直接使用以上公钥分享方案,其现实情况并不那么简单。
(如上图所示)尽管我们知道Harry不能使用Bob的公钥解密邮件,但他仍然可以干扰公钥的分享,并用他自己的公钥替换Bob的公钥。现在,当Alice收到公钥时,她仍然认为这是Bob的公钥,但实际上是Harry的公钥。因此,如果Alice使用此公钥加密她的消息,Harry可以用他的私钥解密消息,然后再用Bob的公钥对解密后的消息加密,再发送给Bob,如此一来,Bob和Alice在通信过程中对Harry无感知。发生这种情况的原因是,因为公钥只是一串数字,而没有身份信息可以告诉我们其所有者是谁。
那么我们应该如何解决没有身份信息的问题呢?
显然,我们应该将密钥与一些身份消息放在一起,然后再共享出去,即所谓的数字证书。于是,Bob把他的公钥放在证书里,证书上有他的姓名和其他身份信息,该证书就像现实世界中的护照一样。
但是我们如何知道真正拥有证书的是Bob?是如何阻止了Harry用Bob的名字,但用Harry的公钥制作假证书?
(如上图所示)就像现实世界中一样,护照必须由护照颁发机构经过身份验证的过程后签发。在数字世界中,证书必须由证书颁发机构验证并签名,该证书颁发机构和护照颁发机构均是受信任的第三方。
获取数字证书,即证书颁发机构对数字证书的颁发过程。
(如上图所示)Bob已有一对公钥和私钥,现在他准备开始申请证书颁发机构对数字证书的签名:
现在,Bob与Alice可以共享此证书,证书中包含Bob的公钥和一些身份信息,而不是像以前那样仅发送公钥,Alice收到证书后,Alice可以使用证书颁发机构的公钥轻松验证证书的真实性。因此,Harry无法再用他的公钥替换Bob的公钥,因为他没有CA的私钥来签名假证书。数字证书的共享流程如下图所示:
请注意,以上的安全的前提是我们都信任CA。如果以某种方式CA不可信,例如,如果CA给Harry他们的私钥,那么我们将面临严重的危险!解决CA可信问题的方法是,使用CA链。
CA链是为了解决CA的可信任问题。
(如上图所示)CA链的顶层是根证书颁发机构(Root Certificate Authority),它可以签署自身证书与签署中间CA(Intermediate Certificate Authority)证书。而该中间CA又可以签署其子节点CA证书,或者他们可以直接签署最终实体证书(即叶子证书)。如此,确保每个证书都引用了其上一节点的证书,可以追溯到根节点的证书,例如我们使用叶子节点的公钥解密(验证)叶子节点证书签名后,可以获得上一节点的签名,直至根节点。
在我们使用的操作系统和浏览器中存储了受信任的根证书颁发机构的证书列表,这样,操作系统和浏览器就可以轻松地验证所有证书的真实性。
(如上图所示)数字证书的签名与验证流程:
CA对证书的签名:
用户验证证书:
至此,我们已经了解了对称加密与非对称加密,下面将探索如何在TLS 的握手协议中使用这两种加密方式。
TLS 1.3 完整的握手流程主要包括以下三个步骤。
1、首先是客户端到服务器的Client Hello,消息内容包括:
- 支持的协议版本:TLS 1.3 或 TLS 1.2。
- 支持的对称密钥套件:TLS_AES_256_GCM_SHA384 或 TLS_CHACHA20_POLY1305_SHA256。
- 支持的密钥协定(交换)算法:DHE(Diffie-Hellman Ephemeral) 或 ECDHE(Elliptic-Curve Diffie-Hellman Ephemeral)。
- 分享的密钥:客户端的DHE公钥,客户端的ECDHE公钥,用于计算临时的共享密钥,即前文示例中的S。
- 支持的签名算法:RSA-PSS 或 ECDSA,由服务器选择使用哪种算法对整个握手进行签名。
2、 收到客户端的Client Hello后,服务器将回复一个Server Hello,消息内容包括:
- 选择的协议版本:TLS 1.3.
- 选择的对称密钥套件:TLS_AES_256_GCM_SHA384。
- 选择的密钥协定算法:DHE。
- 分享的密钥:服务器的DHE公钥。
- 证书请求:对客户端证书的请求,可选值,通常在HTTPS中,只需要服务器将其证书发送给客户端即可。。
- 服务器证书:服务器的证书。
- 证书验证:对整个握手消息的签名。生成方式:从客户端的握手开始,直到证书请求为止,都称为握手上下文(Handshake context),然后将握手的上下文以及服务器的证书经过Hash运算,得到一个hash值,例如4ab31d2,然后使用服务器的私钥对hash值进行签名,使用的签名算法为客户端支持的算法之一,最后获得填写的签名值。
- 服务完成:为一个MAC值(消息认证码)。生成方式:对握手上上下文+服务器证书+证书验证进行Hash运算,再将hash值通过所选的密码套件计算出MAC值。
3、客户端收到Server Hello后,将通过根CA验证服务器证书,然后检查签名和MAC值,确保消息没有被篡改。若一切顺利,则客户端将发送一个握手结束消息,结束消息中包括:
- 由握手上下文计算的MAC值、以及可选的客户端证书和证书验证。
以上便是TLS 1.3中的完整握手流程。
预共享密钥(Pre-Shared Key),简称PSK。
(如上图所示)为了提高效率,客户端与服务器并不会每次都经过完整的握手流程,有时他们仅执行简短的握手流程,实现方法是通过预共享密钥恢复状态:经过前一次握手,客户端与服务器已经相互了解,因此他们不需要再次进行身份验证,因此,服务器可以向客户端发送一个或多个会话凭证(session ticket),可以在下一次握手中用预共享密钥(PSK)、凭证过期时间以及其他一些信息用作身份验证。
在使用PSK的简短握手流程中,客户端将发送一条简单的问候消息,其中包括上一次握手获得的PSK身份标识(凭证)和PSK密钥交换模式,如果使用具有Diffie-Hellman模式的PSK,客户端还需要共享其Diffie-Hellman公钥。如有需要,允许服务器回退到完整的握手流程。服务器收到此客户端的问候消息时,它将返回带有选定的预共享密钥标识消息,服务器可在返回消息中带有可选的Diffie-Hellman公钥。最后,客户端发送给服务器一个完成消息。
可以看出,在该简短的握手流程中,客户端与服务器之间没有证书身份验证。这为零个往返时间(0-RTT)提供了机会。
0-RTT(Zero Round-Trip Time)意味着,客户端无需等待握手完成,就可将第一个应用请求数据发送给服务器。
(如上图所示)在0-RTT中,客户端将应用程序数据(Application data)和客户端Client Hello消息一起发送,客户端使用Pre-shared key字段中的第一个PSK派生的密钥对数据进行加密,同时,该Client Hello增加了早期数据指示(Early data indication)字段,告诉服务器有早期的应用数据正在发送。如果服务器接收此0-RTT请求,它会像正常的PSK恢复一样发送一个回复消息,可能回复消息中带有一些可选的应用程序数据。最后,客户端发送一个带有早期数据的结束与MAC值得结束消息。
以上就是TLS 1.3中0-RTT的工作方式。它的优点时将延迟减少了 1 个往返时间,但是,其缺点是将会收到重放攻击的潜在威胁,意思是,黑客可以复制并发送相同加密的0-RTT请求多次访问服务器,为了避免这种情况,必须实现服务器应用程序对重复请求的方式限制,例如1s之内只能访问5次。
整理文件的过程中,找到了早先实现的代码,逻辑与上图所示一致,实现语言为Go,可前往资源中心下载。
希望你也有所收获!
参考文献:A complete overview of SSL/TLS and its cryptographic system
文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib
文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang
文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些
文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器
文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距
文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器
文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn
文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios
文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql
文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...
文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120
文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数