SSL 连接过程详解

1、SSL 简介

SSL(Secure Sockets Layer 安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层与应用层之间对网络连接进行加密。

在标准的 HTTP 协议下,客户端与服务端直接通过 TCP 链接,以 明文 的形式交换数据,这样做其实在传输一些普通网页数据时并没什么问题,但是如果用户在浏览网页中,需要向服务端发送用户名、密码、银行卡号之类的敏感信息的话,我们不希望这些信息被入侵者所获取,也不希望其遭到篡改或伪造,这时就需要用到 SSL 了。

一个安全的通信往往需要包含三个特性:机密性、数据完整性、端点鉴别,三者缺一不可。

  • 机密性:如果没有机密性,入侵者就可能截获客服端的报文,并获取其的敏感信息。
  • 数据完整性:如果没有数据完整性,入侵者就可以随意篡截获的客户端报文,并对其的信息进行随意的篡改。
  • 端点鉴别:如果没有端点鉴别,客服端所请求的服务器有可能是一个钓鱼网站,用来恶意收集用户的敏感信息。

SSL 就是通过提供机密性、数据完整性以及服务端和客户端鉴别,来强化一个普通的 TCP 链接。

因为 SSL 协议是运行在 TCP 之上的,因此,理论上来讲它能为包括 HTTP 协议在内的任何基于 TCP 连接的应用层协议提供安全性保障。下面来看一下 SSL 的工作原理。

2、SSL 工作原理

SSL 的工作主要可以分为三个阶段:握手、密钥导出、数据传输。

2.1、握手阶段:

在握手阶段需要完成的三个任务分别是:建立一条 TCP 连接、验证服务端身份、分发通信主密钥。大致过程描述如下:

客户端首先发起一条到服务端的 TCP 连接,随后的数据传输都是在这条 TCP 连接之上的,在 TCP 链接建立之后,客户端会向服务端发送 HELLO 报文,这个报文中包含了客户端所支持的密码算法列表,服务端在接收后会选用一种对称算法,一种非对称算法和一种 MAC 算法,连同其 证书 回应给客户端(这个证书就是经过权威机构认证的一个实体与其公钥的绑定)。

因为在各种的加密过程中,只要是涉及到使用公开密钥的,一般都会有公钥被入侵者盗用和伪造的风险,这时就需要权威机构颁发的数字证书来证明一个公要与实体的绑定。

客户端在收到服务端发来的证书之后,就可以明确的知道当前正在跟自己通信的服务端就是目标服务器,客户端随后会从证书中提取服务端发来的公钥,并在客户端生成一个随机的主密钥 MS,然后用服务端的公钥对其进行加密后发送给服务端,服务端会用自己的私钥解密得到主密钥 MS,这样就完成了主密钥的分发。

客户端和服务器都掌握了主密钥,有了这个其他人都不知道的主密钥,随后的数据加密和验证过程就好办了。

2.2、密钥导出:

密钥导出阶段,就是通信双方会以相同的方法,用主密钥生成四个密钥,这四个密钥的分别作用如下:

  • EB:用于从服务端到客户端发送数据的会话加密密钥
  • MB:用于从服务端到客户端发送数据的会话 MAC 密钥
  • EA:用于从客户端到服务端发送数据的会话加密密钥
  • MA:用于从客户端到服务端发送数据的会话 MAC 密钥

会话加密密钥就是实际用来加密传输数据的对称密钥,MAC 密钥在是标志传输数据完整性的密钥。

MAC:报文鉴别码,是一种用来监测报文完整性的技术。它的过程并不复杂,发送方将明文与一个鉴别密钥进行级联,这个鉴别密钥是通信双方所共有的,随后会计算这个级联后的数据散列值,这个散列值就叫做原始数据的报文鉴别码 MAC,将报文的鉴别码附加在原始明文后面,一同发送给接收方。接收方用收到的明文,级联相同的鉴别密钥,再以相同的方法计算散列值,与收到的散列值 MAC 进行对比,若两者相同,则说明数据未被篡改,上述的 MA 和 MB 就是 MAC 里的鉴别密钥。

2.3、数据传输:

SSL 将数据流分割成记录,对每个记录 EA 加密,并附加一个 MAC(用于完整性鉴别),然后对该记录与 MAC 进行加密,然后将这个被加密的包发送服务器,服务端收到这个数据包后,用相应的 EB 对称密钥进行解密,再用 MB 进行数据完整性检验。

3、报文重放攻击

上述操作看似是实现了对安全通信的三个基本需求,但是其对整个会话过程中报文流的数据完整性的保障并未达到天衣无缝,虽然单个记录的报文完整性可以由 MAC 保障,但是若是入侵者恶意调换两个 SSL 记录的顺序,或者故意多次重放同一个 SSL 记录多次,这样会导致接收方收到的最终报文不正确,这也就是 "报文重放攻击"

不过这个问题可以通过序号来解决,你可能会想,在每一个记录中增加一个序号不就行了么,但是实际上不必直接在 SSL 记录中额外包含一个序号,只需要由发送方自己维护一个计数器,每发送一次,就将自己的计数器 +1,并在计算记录 MAC 时,将这个需要括在 MAC 中的记录中,接收方也跟踪自己收到的所有记录的序号,同样在计算记录 MAC 进行校验时,让自己跟踪到的序号参与计算,若计算结果相同就说明记录即通过了完整性检验,也没有被篡改顺序。

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SSL(Secure Sockets Layer)是一种加密协议,用于在网络上安全地传输数据。Python中的ssl模块提供了一种简单的方式来使用SSL加密协议。在本文中,我们将介绍Python中的ssl模块,包括SSL/TLS协议的基础知识、如何在Python中使用SSL模块建立加密连接、如何验证SSL证书以及如何配置SSL加密连接。 ## SSL/TLS协议基础知识 SSL/TLS协议是一种加密协议,用于在网络上安全地传输数据。它是一种端到端的加密协议,可以保护数据在传输过程中不被窃听、篡改或伪造。SSL/TLS协议是建立在TCP协议之上的,因此它可以在任何支持TCP协议的网络上使用。 SSL/TLS协议使用公钥加密和私钥解密的方式来加密数据。在建立连接时,客户端和服务器之间会交换公钥,用于加密数据。数据在传输过程中,只有拥有私钥的一方才能解密数据。因此,SSL/TLS协议可以保证数据在传输过程中不被窃听。 SSL/TLS协议还提供了身份验证和完整性保护。使用SSL/TLS协议建立连接时,客户端和服务器可以交换数字证书,用于验证对方的身份。数字证书是由权威机构颁发的,可以保证对方的身份是真实可靠的。同时,SSL/TLS协议还提供了完整性保护,可以确保数据在传输过程中不被修改。 ## SSL模块的使用 Python的ssl模块提供了一种简单的方式来使用SSL加密协议。使用ssl模块建立加密连接的基本步骤如下: 1. 创建一个socket对象 2. 使用ssl.wrap_socket()函数对socket对象进行包装 3. 连接到服务器 4. 发送和接收数据 下面是一个简单的例子,使用ssl模块建立一个加密连接: ```python import socket import ssl # 创建一个socket对象 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 对socket对象进行包装 ssl_sock = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLS) # 连接到服务器 ssl_sock.connect(('www.example.com', 443)) # 发送数据 ssl_sock.send(b'Hello, world!') # 接收数据 data = ssl_sock.recv(1024) # 关闭连接 ssl_sock.close() ``` 在上面的例子中,我们首先创建了一个普通的socket对象s,然后使用ssl.wrap_socket()函数对其进行包装,生成了一个加密的socket对象ssl_sock。我们将ssl_version参数设置为ssl.PROTOCOL_TLS,表示使用TLS协议进行加密。 然后,我们使用ssl_sock.connect()函数连接到服务器,并使用ssl_sock.send()函数发送数据。使用ssl_sock.recv()函数接收服务器返回的数据。最后,我们使用ssl_sock.close()函数关闭连接。 ## SSL证书验证 在上面的例子中,我们没有对SSL证书进行验证。在使用SSL/TLS协议建立连接时,服务器会向客户端发送一个数字证书,用于验证服务器的身份。Python的ssl模块提供了一种简单的方式来验证SSL证书。 使用ssl模块验证SSL证书的基本步骤如下: 1. 创建一个SSLContext对象 2. 设置验证选项 3. 创建一个socket对象 4. 使用SSLContext.wrap_socket()函数对socket对象进行包装 5. 连接到服务器 6. 发送和接收数据 下面是一个简单的例子,使用ssl模块验证SSL证书: ```python import socket import ssl # 创建一个SSLContext对象 context = ssl.create_default_context() # 设置验证选项 context.check_hostname = True context.verify_mode = ssl.CERT_REQUIRED # 创建一个socket对象 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 对socket对象进行包装 ssl_sock = context.wrap_socket(s, server_hostname='www.example.com') # 连接到服务器 ssl_sock.connect(('www.example.com', 443)) # 发送数据 ssl_sock.send(b'Hello, world!') # 接收数据 data = ssl_sock.recv(1024) # 关闭连接 ssl_sock.close() ``` 在上面的例子中,我们首先创建一个SSLContext对象,然后设置验证选项。我们将check_hostname选项设置为True,表示验证服务器的主机名,将verify_mode选项设置为ssl.CERT_REQUIRED,表示验证SSL证书。当服务器的证书无效或不可信时,会抛出异常。 然后,我们创建一个socket对象s,并使用context.wrap_socket()函数对其进行包装,生成了一个加密的socket对象ssl_sock。我们将server_hostname参数设置为服务器的主机名,表示验证服务器的主机名。 然后,我们使用ssl_sock.connect()函数连接到服务器,并使用ssl_sock.send()函数发送数据。使用ssl_sock.recv()函数接收服务器返回的数据。最后,我们使用ssl_sock.close()函数关闭连接。 ## SSL加密连接配置 Python的ssl模块提供了一些选项,可以配置SSL加密连接。下面是一些常用的选项: - ssl_version:指定使用的SSL/TLS协议版本,默认为PROTOCOL_TLS。 - ciphers:指定加密算法的列表,默认为None。 - certfile:指定客户端证书文件的路径。 - keyfile:指定客户端私钥文件的路径。 - ca_certs:指定服务器证书颁发机构的证书文件的路径。 - check_hostname:指定是否验证服务器的主机名,默认为False。 - verify_mode:指定SSL证书验证的级别,默认为CERT_NONE。 下面是一个简单的例子,使用ssl模块配置SSL加密连接: ```python import socket import ssl # 创建一个SSLContext对象 context = ssl.create_default_context() # 设置加密算法和证书文件 context.set_ciphers('AES256-SHA') context.load_cert_chain(certfile='client.crt', keyfile='client.key') # 设置SSL证书验证选项 context.check_hostname = True context.verify_mode = ssl.CERT_REQUIRED context.load_verify_locations(cafile='ca.crt') # 创建一个socket对象 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 对socket对象进行包装 ssl_sock = context.wrap_socket(s, server_hostname='www.example.com') # 连接到服务器 ssl_sock.connect(('www.example.com', 443)) # 发送数据 ssl_sock.send(b'Hello, world!') # 接收数据 data = ssl_sock.recv(1024) # 关闭连接 ssl_sock.close() ``` 在上面的例子中,我们首先创建一个SSLContext对象,并设置加密算法和证书文件。我们将ciphers选项设置为'AES256-SHA',表示使用AES256-SHA加密算法进行加密。我们使用load_cert_chain()函数加载客户端证书和私钥文件。我们将certfile选项设置为'client.crt',表示客户端证书文件的路径,将keyfile选项设置为'client.key',表示客户端私钥文件的路径。 然后,我们设置SSL证书验证选项。我们将check_hostname选项设置为True,表示验证服务器的主机名。我们将verify_mode选项设置为ssl.CERT_REQUIRED,表示验证SSL证书。我们使用load_verify_locations()函数加载服务器证书颁发机构的证书文件。我们将cafile选项设置为'ca.crt',表示服务器证书颁发机构的证书文件的路径。 然后,我们创建一个socket对象s,并使用context.wrap_socket()函数对其进行包装,生成了一个加密的socket对象ssl_sock。我们将server_hostname参数设置为服务器的主机名,表示验证服务器的主机名。 然后,我们使用ssl_sock.connect()函数连接到服务器,并使用ssl_sock.send()函数发送数据。使用ssl_sock.recv()函数接收服务器返回的数据。最后,我们使用ssl_sock.close()函数关闭连接。 ## 总结 Python的ssl模块提供了一种简单的方式来使用SSL加密协议。在使用SSL/TLS协议建立连接时,可以保护数据在传输过程中不被窃听、篡改或伪造。在使用ssl模块建立加密连接时,可以验证SSL证书,并配置SSL加密连接

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值