一. 基础概念
1. 计算机网络体系结构分层
计算机网络体系结构分层2.TCP/IP
TCP/IP协议并不是单纯的指TCP协议/IP协议. TCP/IP是传输层和网络层两个代表性的协议. 在很多情况下, 它是指利用IP协议进行通信是所必须用到的协议群(协议族)的统称. 具体来说, HTTP/TELNET/FTP(应用层)、TCP/UDP(传输层协议)、IP/ICMP(网络层协议)等, 都统称TCP/IP协议. 他们都是互联网的必要组成部分.所以TCP/IP也称为网际协议群.
互联网进行通信是, 需要响应的网络协议. TCP/IP原本就是未使用互联网而开发、定义的协议族.因此, 互联网协议就是TCP/IP. TCP/IP就是互联网协议.
网际协议群
3.数据包
包、帧、数据包、段、消息. 这五个术语都可以用来标书网络中传输的数据的单位:
包: 可以说是全能术语, 在各个分层中都能用
消息: 是指应用层协议(HTTP)数据流中的单位.
段: 是指TCP数据流中的信息
数据包:是指IP/ICMP等网络层以上的分层中数据流的单位.
帧: 用于表示链路层中数据包的单位
在每个分层中, 都会对所发送的数据附加一个该层的首部. 这个首部中包含了该层中必要的信息. 例如:目标MAC地址, 目标IP地址以及协议相关信息等. 通常, 为下层协议提供的信息为包首部, 所要发送的内容为数据.
4.TCP/IP通信传输流
发送端发送的数据会从应用层从上往下传输, 每经过一层就会在数据包头部附加该层的首部.接收端(Sever)则从链路层从下往上传输. 每经过一层就验证、去掉该层的首部. 如图所示:
TCP/IP协议通信流程
- 应用程序处理: 首先应用层会进行编码处理. 产生HTTP报文,
- TCP层的处理: TCP根据应用的指示, 负责建立链接、发送数据以及断开链接(三次握手及四次挥手).TCP提供将应用层发来的数据顺利发送至对端的可靠传输. 为了实现这一功能, 需要在应用层数据(HTTP报文)的前端附加一个TCP首部.
- IP层的处理: IP层将'TCP首部+HTTP报文'合起来当做自己的数据, 并在TCP首部的前端加上自己的IP首部. IP包生成后, 参照'路由控制表'决定接受此IP包的路由或者主机.
- 网络接口(以太网驱动)的处理: 从IP传过来的IP包对以太网来说就是数据, 在这些数据的前端加上'以太网首部'并进行发送处理. 生成的以太网数据包将通过物理层传输给接收端.
- 接收端处理: 主机接收到以太网包后, 首先从'以太网包首部'找到MAC地址, 判断是否是发送给自己的包. 若不是, 则丢弃数据.
5.1 如果是发送给自己的包, 则从以太网包首部中确定数据类型, 再传给相应的上层模块(网络层 IP), 此时数据包首部为IP包首部- IP模块的处理: IP层接收到数据后, 从IP包首部中判断目标IP是否是与自己的IP地址相匹配. 如果匹配则根据首部的协议类型发送给响应的上层模块(TCP/UDP)
TCP模块的处理: 在TCP模块中, 首先会计算下校验和, 判断数据是否被破坏. 然后检查是否在按照序号接收数据. 接下来检查端口号, 确定目标应用程序. 然后传输给端口号识别的应用程序.
8: 应用程序的处理: 应用程序接收到数据后, 通过解析数据, 展示相应的内容.
数据处理流程
5. TCP建立连接/断开连接的过程
TCP协议的职责: 负责建立连接, 传输数据, 断开链接. 将应用层数据(HTTP报文)按照序号切割成多个报文段, 并提供将报文段传输到对方的可靠链接.
5.1 TCP报文首部的格式
首先我们一起学习下TCP报文首部的格式
引申: 一个TCP报文段的最大载荷为多少? 一个TCP报文段的最大数据载荷为多少?
一个IP数据包的最大长度为2^16 -1 = 65535Bytes. IP首部20B, TCP首部20B. 所以一个TCP报文段的最大载荷为65535-20=65515B(字节). 最大数据载荷为65535-20-20= 65495字节.
TCP报文首部格式
- 如图所示, 目标端口号字段和源端口号字段各占16比特, 也就是2个字节.
- 序号字段和确认号字段各占32比特, 4个字节. 确认号是接收方期望从对方收到的下一字节的序号.
- ACK标志位: 用于指示确认号字段中的值是有效的. ACK = 1有效. ACK=0无效.
- SYN标志位: 用于建立连接, SYN = 1时. 标明这是一个用于请求建立连接的报文.
- FIN标志位: 用于断开连接. FIN=1是, 标明发送方数据已经发送完成, 请求断开连接.
5.2 建立连接(三次握手)
- 客户端发送一个不包含应用层数据的TCP报文. SYN标志位置为1. 随机选择一个初始序号(一般为0)放在TCP首部的序号字段中. (SYN=1, seq=M. SYN=1时, 不能携带数据, 但是要消耗一个掉序号.). 同时, 客户端进入SYN_SEND状态
- TCP报文发送到主机后, 服务器提取报文, 并为该TCP连接分配变量和缓存. 然后向客户端发送允许连接的ACK报文. 该报文中, ACK=1. SYN=1. 确认号字段=TCP报文中随机序号+1(ack=M+1), 生成自己的随机序号(seq=N). 服务器进入SYN_RCVD状态.
客户端接收到ACK报文后, 检查ACK是否为1, ack==M+1. 如果正确, 发送给服务端一个ACK报文, ACK=1, SYN=0. ack=N+1. 服务端接收到后, 检查ACK=1, ack=N+1. 确认后, 建立连接成功. 双端进入ESTABLISHED状态, 后续再发送的报文SYN=0. 可以携带应用层数据.
三次握手
5.3 断开链接(四次挥手)
- 客户端发送一个FIN报文段, FIN = M. 表示客户端的数据已经发送完成. 请求断开链接. 客户端进入FIN_WAIT_1状态.
- 服务端接收到报文段后. 通过FIN=1知道了客户端请求断开链接. 但是这时候服务端数据可能尚未传输成功. 所以服务端先向客户端发送一个针对断开链接的确认应答. 该报文段中ACK=1. 确认号ack=M+1. 表示接收到客户端断开链接的请求. 服务端进入CLOSE_WAIT状态. 客户端进入FIN_WAIT_2状态.
- 当服务端数据传输完成后, 会向客户端发送一个请求断开链接的报文段. FIN=N.
客户端接收到后, 向服务端发送一个确认应答. ACK=1, ack=N+1. 双方断开链接
四次挥手
值得注意的是, 中断链接端可以是客户端, 也可以是服务端.
5.4 同时发起主动断开链接
在5.3中, 是一段主动发起断开链接, 另一端被动断开链接. 实际上, 也会存在双端同时断开链接的情况.
同时挥手
二、应用层的HTTP协议
HTTP协议(超文本传输协议, 位于OSI模型中的应用层).它是万维网的基础.
当我们通过HTTP发送请求时. 通常会通过URL(统一资源定位符)来定位服务器并获取资源.
URL的基本格式为:
<协议名>://<域名>:<端口>/<资源路径>/<参数>?[query]
HTTP协议的端口号默认为80. 通常会省略掉. 当我们通过URL去访问一个资源的时候. 首先需要进行DNS解析, 将域名通过运营商的LocalDNS转换成对应的IP地址. (这里引出一个网络优化点---HTTPDNS, 其原理是通过NSURLProtocol来拦截所有网络请求, 在- startLoading方法中绕过运营商的DNS服务. 用HTTPDNS通过HTTP直接进行DNS解析. 然后进行字符串替换, 将域名替换成IP. 但是这里有一个坑点.运营商是根据域名来确定一个URL的, 如果直接用替换后的URL进行访问, 运营商会无法正常响应, 需要我们将域名拼入header中去. setValue:@"www.baidu.com" forHTTPHeaderField:@"Host");
HTTP/1.1
HTTP/1.1是目前使用最广的版本, 一般没有特别标明的版本都是指HTTP/1.1.
HTTP连接建立的过程:
- 先通过DNS解析将域名替换为IP地址.
- 通过TCP三次握手建立连接.TCP会在HTTP报文前端加上TCP首部. 包含目标端口号和源端口号.
- IP模块接收到TCP数据包后, 在TCP首部前端加上IP首部, 包含协议类型(TCP)、源IP地址和目标IP地址. IP包生成后, 会通过路由控制表决定目标路由或主机
- 链路层接收到IP包后会在IP首部前端附加上以太网首部. 包含目标主机的MAC地址. 然后通过物理层传输到目标主机.
- 服务器接受到数据后, 首先根据以太网首部中的MAC地址确认是否是发送给自己的数据, 如果不是则丢弃数据. 然后通过协议类型(IP/IMCP)传输到上层(网络层).
- IP模块接收数据后, 首先判断目标IP地址是否和自己的IP地址相匹配. 然后根据协议类型(TCP)传输到传输层
- TCP模块接收到数据后, 首先会计算一下检验和, 判断数据是否被破坏. 然后判断请求是否按顺序发送. 最后根据目标端口号找到对应的应用程序. 将数据传输给应用程序.
- 应用程序接收到数据后进行解析、展示.
HTTP报文格式
请求报文格式
请求报文格式请求报文分为三部分, 分别是: 请求行, 请求头部(header), 请求实体(body)
- 请求行: 固定格式为 Method path version. 请求方法(GET/POST/HEADER/PUT/DELETE等) www.baidu.com HTTP/1.1
- 请求头部: 以key: value的形式存在. 每一个键值对后跟接一个换行. 包含了我们常见的header键值对. 例如User-Agent、Connection: keep-alive、Cookie: 、Host(一般情况下不需要设置, 但是如果我们有通过HTTPDNS等方式替换域名为IP, 那么这个时候就需要通过HOST来告知运营商我们请求的具体域名)、Range(Range: bytes=100-200, 常用来做断点续传)等信息
- 请求实体. 具体的请求书.在GET方法中 没有body部分, 所有的请求数据都放在URL中. POST中由body部分
响应报文格式
响应报文格式HTTP响应报文也对应的分为三部分:
- 状态行: 固定格式为 Version 状态码 状态码原因短语 (exp: HTTP/1.1 200 OK)
- 响应头部: 对请求报文中的请求头部进行响应
- 响应数据: 我们所需要的数据 {"data":{}}
HTTP协议相关特性
- HTTP是无连接、无状态的简单协议. 为什么是无连接的? 因为在HTTP早期版本中, HTTP每一次发送请求并得到响应后都会断开链接. 无状态: 指在HTTP这一层, 不会对请求和响应之间的链接状态做持久化处理. 这样做的目的是为了快速处理大量事务.确保协议的可伸缩性. 所以才把HTTP设计成一个简单的协议.
- Cookie. 为了解决HTTP协议无状态的特性. 但是很多web又需要知道客户端的链接状态.所以引入了Cookie技术. 比如我们在浏览淘宝或者京东的时候, 未登录的时候再购物车中添加了3个商品. 登录后仍然能够在购物车中找到这三件商品.这就是利用了Cookie技术实现的. Cookie就是保存在客户端的一个简单文本. 对于一些链接, 服务器在发送响应报文时, 会在响应报文的header部分添加上Cookie. 并通过Set-Cookie:Cookie的方式通知客户端去存储Cookie. Cookie是和域名一一对应的. 想要的Cookie进行修改, 有三个充要条件(name, domain, path要跟客户端的一致). 如果要删除Cookie, 需要name,domain,path一致, 并且设置maxAge=0 或者 express等于过去的某一个时间.
- Session. 由于Cookie是保存在客户端的, 所以会存在一定的安全隐患. 为了解决这个问题, Session应运而生. Session是基于Cookie技术才能实现的. 与Cookie不同的是, Session是保存在服务端的. 通常服务端的响应报文中会存放用户对应的SessionId在Cookie中. 这样就不会泄漏用户的隐私数据. 然后服务端通过请求报文Cookie中的SessionId来查找对应的用户.
- 持久链接. 在HTTP早期版本中, 每请求一次就要建立一次链接. 而每次建立连接都需要进行TCP三次握手, 断开链接也需要TCP四次挥手. 消耗无畏资源. 为了解决这个问题, 在HTTP1.1之后, 引入了持久链接. 就是指任何一方没有主动断开链接, 就保持TCP的链接状态. 这样一来就节省了每次请求都建立连接的过程. 也为HTTP的管线化提供了基础.
- 管线化. 在持久链接未引入的版本中. 多次HTTP请求只能等待上一次的请求接收到响应后才会进行下一次的建立连接, 发送报文等步骤. 持久链接为管线化提供了基础. 管线化后, 多个请求可以并行触发. 不用等待上一次的响应.
- 在TCP层, 为了请求数据能够正常发送(一个IP数据包的最大载荷是2^16-1=65535字节, 为了适配IP数据包, 一个TCP报文段最大载荷是65535-20(IP首部)=65515字节. 而一个TCP报文段的最大数据载荷为65515-20(TCP首部)=65495字节), 会将TCP报文按序号切割成多个报文段.然后在服务端的TCP层, 又会将这些报文段按照序号组合起来, 交付给应用层.
HTTPS
HTTPS是什么? 它存在的意义是什么?
HTTPS是什么?
在一个HTTP请求中, 通常由HTTP协议与TCP直接进行交互. 不过由于HTTP协议天生明文传输的特性, 任何人都能够从一个HTTP请求中截获/修改/伪造请求, 所以对我们来说, HTTP是不安全的. 在HTTP的传输过程中, 并不会验证通信方的身份,因此HTTP信息交换双方可能会遭到劫持、伪装.就是说没有用户验证
. 接收方和发送方也并不会验证报文的完整性
, 这样就导致报文即使被篡改也无法发现.
HTTPS是完全基于HTTP协议的.(不过HTTP默认端口号80 HTTPS默认端口号443)它本身不保证传输的安全应. 不过它在应用层和传输层中间新增了一层SSL/TLS协议. 在数据传输的过程中, 不再邮HTTP和TCP进行交互, 而是在建立连接后, 通过SSL/TLS和TCP进行交互. 可以概括的说, HTTP + SSL = HTTPS
HTTPS协议解决了什么问题
信息安全中有三个需要解决的问题:
- 保密性: 信息在传输时不被泄漏
- 完整性: 信息在传输是不被窃听/篡改
- 有效性: 信息的使用者/发送者是合法的
SSL/TLS协议主要解决就是为了解决这三个问题. - 保密性. 由于HTTP协议明文传输的特性, 所有基于HTTP协议的请求数据都是明文传输的. HTTPS协议通过SSL/TLS协议对传输的数据进行加密, 防止窃听甚至篡改.
- 数据完整性的问题. 保证数据在传输的过程中不会被窃听/篡改.
- 身份有效性的问题. 能够确认对方的真实身份, 防止被DNS劫持等
SSL/TLS
SSL(Secure Socket Layer) 安全套接字层
, TLS(Transport Layer Security)传输层安全协议
. TLS是SSL的后续版本. SSL在1999年被标准化后, 改名为TLS, 意为传输层安全协议. 他们是互联网两台计算机之间用于身份验证和加密
的一种协议. SSL/TLS是一种单独的协议. 不光HTTP可以使用, 其他应用层协议也可以使用.比如SMTP、Telent
等
目前为止, TLS共有三个版本, 1.1、1.2、和1.3. 目前使用最广泛的是TLS1.2版本
TLS为互联网的两台计算机之间的通信提供加密功能和保证数据完整性. TLS由记录协议
、握手协议
、警告协议
等多个子协议组成. 综合使用了对称加密、非对称加密、身份验证
等许多密码学技术.
TLS的命名规范为
秘钥交换算法-签名算法-对称加密算法-分组模式-摘要算法
下面举一个例子:
/// 使用ECDHE进行秘钥交换
/// 使用ECDSA进行签名和认证
/// 使用AES作为对称加密算法, 秘钥的长度为256位, 分组模式是GCM
/// 使用SHA384作为摘要算法, 进行加密
ECDHE-ECDSA-AES256-GCM-SHA384
对称加密.
顾名思义, 对称加密就是加密和解密时使用的秘钥都是同一个. 只要保证了秘钥的安全性, 嘛呢通信就是安全的. 常用的对称加密为AES
对称加密
但是对称加密的双方用到的秘钥是同一个, 发送方先对原始数据进行加密, 然后把秘钥发送给接收方, 对方才能进行解密. 也就是说, 秘钥需要随着数据进行传输, 这就有了风险, 不法分子可以截获到这个秘钥, 然后对加密后的数据进行解密、篡改. 所以对称加密是存在风险的.
非对称加密
最常用的非对称加密算法是RSA算法.
非对称加密也被称作公钥加密
, 是对称加密的一种改良加密方法. 非对称加密中的密钥有两个. 一个是私钥, 一个是公钥. 在RSA加密算法中, 用公钥对数据进行加密, 私钥进行解密. 在RSA签名算法中, 用私钥对数据进行签名, 公钥用来进行验证.
RSA加密算法.
在RSA加密算法中. 公钥对数据进行加密. 只有私钥能够对加密后的数据进行解密. 私钥只有自己能够知道,公钥能够提供给任何人使用. 也就是说, 公钥会随着数据进行传输. 可以这样理解: 公钥就是公开的密钥, 它公开了以后, 大家才能用它来进行加密. 但是解密时有不希望所有人都能解密, 所以用私钥来进行解密
RSA签名算法
在RSA签名算法中. 私钥对数据进行签名. 公钥对数据进行验证. 可以这样理解: 在签名算法中, 对数据进行签名, 当然希望这个签名只是我自己. 但是验证时, 需要所有人都能够用公钥执行, 对我的签名进行验证.
混合加密
TLS使用了对称加密和非对称加密的混合加密的方式来实现机密性
非对称加密(RSA)运算非常慢, 而对称加密(AES)运算比较快. TLS运用了混合加密的方式. 在通信刚开始的时候, 先通过非对称加密算法, 比如RSA, 来解决秘钥交换的问题, 然后用随机数产生对称加密算法使用的会话密钥(session key)
, 对这个密钥用公钥进行加密. 对方拿到密文后, 用私钥进行解密. 取出对称加密用到的会话密钥(session key)
. 后续通讯就用对称加密的密钥进行.
通过TLS的混合加密, HTTPS解决了通信私密性的问题. 还需要在私密性的基础上, 加上身份验证、完整性校验,才能实现真正的安全通信.
摘要算法
在TLS中, 解决数据完整性问题的手段主要是摘要算法
. 摘要算法能用任意长度的数据生成一种固定长度的字符串. 可以将摘要算法理解为一种特殊的压缩方式, 将任意长度的数据压缩成固定长度的字符串.
比如我们熟知的MD5(Message Digest Algorithm 5, 消息摘要算法), 它可以用任意长度的字符串生成一串128位(16字节)的字符串. MD5最常用来验证文件的完整性
SHA系列(Secure Hash Algorithm, 安全哈希算法) 也是一种常用的算法. SHA-1由于不是安全的加密算法, 被TLS禁用. 目前TLS推荐的是SHA-2. SHA-2系列包含6个哈希函数, 分别是SHA-224, SHA-256, SHA-384, SHA-512. 其摘要分别是224、256、384、512位. 能够生成28、32、48、64个字节的摘要.
有了摘要算法的保护, 就能对数据完整性进行校验. 原始数据中任何一个标点的改动都会导致生成的摘要算法生成的摘要不一致.
数字签名
我们在上边的非对称加密算法中, 提到了RSA的签名算法. 用私钥进行签名. 用公钥进行验, 就能保证自己的唯一性和合法性. 用私钥在加上摘要算法, 就能实现数字签名
,从而实现认证:
生成签名:
- 对消息进行摘要加密, 得到加密密文
- 用私钥对加密密文进行加密, 生成数字签名
- 将数字签名附加在消息后边发送出去.
验证签名:
- 拿到消息后, 提去消息中的数字签名. 用公钥对数字签名进行解密. 得到加密密文1
- 对消息进行摘要加密, 得到加密密文2
- 比对两个加密密文. 验证唯一性.
证书
上文说到用公钥来验证数字签名的合法性, 那么公钥的合法性又怎么验证呢?
这就引入了证书技术. 证书其实就是用来验证公钥的合法性, 验证成功后, 标识该公钥是合法的,可信的
证书一般包含:
- 公钥
- 公钥的数字签名
- 公钥拥有者的信息
那么问题又来了, 验证证书中的数字签名, 需要另一个公钥, 那么怎么判断这个公钥的合法性? 这时就需要一个权威的机构来颁发证书、提供公钥
. 只要是这个权威机构提供的公钥, 我们就认为这个公钥是合法的.
这个机构就是我们熟知的CA(Certification Authority), 证书颁发机构. CA就是能够认定该公钥确实属于此人
并且能够对公钥生成数字签名
的机构. CA有国际性组织和政府组织, 也有盈利性机构
如何生成一个证书?
- 服务器将公钥A发送给CA(公钥是服务器的)
- CA用自己的私钥B, 对公钥A进行加密, 生成数字签名A
- CA把公钥A, 数字签名A, 和一些公钥拥有者信息整合在一起, 生成证书, 发回给服务器.
- 这里注意, 私钥B是CA机构的用来生成公钥A的数字签名的. 私钥B和公钥A并不配对
客户端如何验证一个证书?
- 客户端得到CA办法给服务器的证书
- 客户端得到证书的公钥B(通过CA活着其他途径)
- 客户端通过得到的公钥B对证书中的数字签名A进行解密, 得到哈希值(CA中的私钥B和客户端得到的公钥B配对)
- 客户端对证书中的公钥A进行摘要加密, 得到哈希值
- 通过比对两个哈希值, 验证证书的合法性
到这里未知. 网络信息安全的三个问题: 私密性(对称加密+非对称机密的混合加密), 完整性(摘要加密 + 数字签名验证), 有效性(通过验证数字签名和证书)就全部解决了, 双方就能进行安全的通信了
网友评论