应用层协议
超文本传输协议(HTTP、HTTPS)
文件传输协议(FTP)
简单文件传输协议(TFTP)
简单邮件传输协议(SMTP)
邮局协议第三版(POP3)
动态主机配置协议(DHCP)
简单网络管理协议(SNMP)
域名服务协议(DNS)
远程登录协议(TELNET)
安全外壳协议(SSH)
传输层协议
传输控制协议(TCP)
用户数据报文协议(UDP)
网络层协议
网际协议(IP)
地址转换协议(ARP)
反向地址转换协议(RARP)
互联网控制报文协议(ICMP)
互联网组管理协议(IGMP)
路由信息协议(RIP)
边界网关协议(BGP)
分布式链路状态协议(OSPF)
数据链路层协议
点对点协议(PPP)
停止等待协议(CSMA/CD)
自动重传请求协议(ARQ)
物理层协议
传输线相关标准
中继器相关标准
集线器相关标准
交换机相关标准
A类地址
网络号占前8位,以0开头,可分配范围:1~126
主机号占后24位,最大主机数:16777214
B类地址
网络号占前16位,以10开头,可分配范围:128.1~191.255
主机号占后16位,最大主机数:65534
C类地址
网络号占前24为,以110开头,可分配范围:192.0.1~223.255.255
主机号占后8位,最大主机数:254
D类地址
以1110开头
保留为多播地址
E类地址
以1111开头
保留为以后使用
210.27.48.21表示网络中一台主机的IP地址,斜杠后面的30表示其中前30位是网络号,后2位是主机号
xxxxxxxxxx
181210.27.48.21
2|______
3| |
4210.27.48.00010101
5|______________|_|
6网络号 主机号
7_____网络地址____
8| |
9210.27.48.00010100
10|______|
11|
12210.27.48.20
13_____主机地址____
14| |
15210.27.48.00010100 - 多播地址
16210.27.48.00010101 - 主机地址
17210.27.48.00010110 - 主机地址
18210.27.48.00010111 - 广播地址
在子网210.27.48.21/30中,有两可用主机地址:
210.27.48.21
210.27.48.22
路由表是用来指导如何将一个数据包从一个子网传送到另一个子网的
路由表中的每一个条目至少包含目标网络号、子网掩码和为到达目标网络应使用的网卡等信息
当路由器从它的一块网卡接收到一个数据包时,它会扫描路由表中的每一个条目,用其中的子网掩码和数据包的目的IP地址做位与运算,得到目标网络号
若所得到的目标网络号与该条目的目标网络号匹配,则将该条目作为一个备选路由
在所有备选路由中选择目标网络号最长的,作为命中路由
将数据包通过命中路由的网卡发送出去
若一个匹配的条目都没有,则通过默认路由的网卡将数据包发送出去
在Linux系统中配置默认路由的命令:
xxxxxxxxxx
11route add default gw <默认路由IP地址>
检测两台主机是否连通可以使用ping命令
如果ping不通,可以使用traceroute命令,找出具体是哪个路由器不能连通
然后再定位发生故障的传输线、中继器、集线器或者交换机
TTL是Time To Live的缩写,即生存时间,是指允许一个数据包在到达其目的地之前最多经过多少个路由器
数据包每经过一个路由器,其生存时间就会被路由器减一
当一个数据包的生存时间被减到零时,就会被路由器丢弃
TTL主要是为了防止数据包在网络回路上无限循环
ping和traceroute工具都会用到TTL
工作在网络层的ARP协议主要负责IP地址到物理地址的转换
每台主机都维护一张ARP列表,其中包含一系列IP地址和物理地址的对应关系
当源主机要将一个数据包发送到目的主机时,会先在ARP列表中搜索与该目的主机的IP地址相对应的物理地址
如果找到了,则直接将数据包发送到这个物理地址
如果没找到,则向本网段广播一个ARP请求包,其中包含源主机的IP地址和物理地址,以及目的主机的IP地址。网段中每台收到该ARP请求包的主机,都会检查请求包中的目的主机IP地址
若请求包中的目的主机IP地址与自己的IP地址不一致,则忽略该请求包
若请求包中的目的主机IP地址与自己的IP地址一致,则将源主机的IP地址和物理地址保存到自己的ARP列表中,同时向源主机返回一个ARP响应包,其中包含自己的物理地址
收到ARP响应包的源主机一方面将目的主机的IP地址和物理地址保存到自己的ARP列表中,另一方面将数据包发送到目的主机的物理地址
若源主机一直没有收到ARP响应包,则宣告ARP查询失败
TCP是一种面向连接的通信协议
通信之前必须先建立连接,即所谓虚电路
凭借已有的连接,通信双方相互交换数据
通信结束后双方终止连接,释放连接资源
TCP只支持点对点的通信,不支持广播通信
一个连接只有两个端点,实现点对点的通信
不能在一个连接上实现,一多或者多多通信
TCP保证数据传输的可靠性
不丢失、不重复、无差错、保证顺序
TCP是一种面向字节流的通信协议
传输层看到的是无结构的字节序列
应用层需自己实现记录边界的划分
TCP协议提供全双工通信
通信双发可以同时收发报文
UDP是一种面向无连接的通信协议
通信双方不存在长期关系
UDP不仅支持点对点的通信,还支持广播通信
一对一、一对多、多对一、多对多
UDP不保证数据传输的可靠性
可能丢失、可能重复、可能有差错、不保证顺序
UDP是一种面向记录的通信协议
传输层看到的是有结构的记录
应用层无需自己划分记录边界
UDP协议提供全双工通信
通信双发可以同时收发报文
TCP协议面向连接;UDP协议面向无连接
TCP协议仅支持点对点通信;UDP协议除了支持点对点通信,还支持广播通信
TCP协议保证数据传输的可靠性;UDP协议不保证数据传输的可靠性
TCP协议面向字节流;UDP协议面向记录
TCP协议是重量级协议,速度慢,数据量大;UDP协议是轻量级协议,速度快,数据量小
应答确认:每发送一个分组,必须等待对方确认收到,否则不算发送成功
超时重传:如果超过一定时间还没有收到对方确认,则认为发送失败,重新发送该分组
分组校验:每接收一个分组,校验其正确性,如有差错,直接丢弃且不发确认,迫使对方重发
乱序重排:对接收到的分组按序号重排,保证跟发送的顺序一致
丢弃重复:重排过程中,如发现序号相同的重复分组,只留一个
流量控制:动态调整发送方的发送速度,以与接收方的接收能力相适应
拥塞控制:动态调整发送方的发送速度,以与网络的承载能力相适应
参与TCP通信的一方向另一方发送数据时,传输层会在每发送完一个分组后,等待对方返回应答确认
分组无误,收到确认
分组有误,收不到确认,重传该分组
分组丢失,收不到确认,重传该分组
分组无误,确认迟到,重传该分组,对方丢弃重复分组
参与TCP通信的一方向另一方发送数据时,传输层会在每发送完一个分组后,启动一个超时计时器
如果在超时计时器到期前,仍未收到对方返回的应答确认,则认定分组丢失或有误,重传分组并等待更长时间
TCP协议包含用于动态估算数据平均往返时间(Round-Trip Time,RTT)的算法,因此它知道等待一个确认至少需要多长时间
滑动窗口是TCP协议实现流量控制的基础
通常所说的滑动窗口是指接收方滑动窗口
滑动窗口的大小反映了接收方用于接收数据的缓冲区可用空间的大小
当滑动窗口比较大时,意味着接收方具有较强的接收能力,发送方可以加快发送速度
当滑动窗口比较小时,意味着接收方接收数据的能力不足,发送方必须降低发送速度
当滑动窗口降为零时,意味着接收方暂时不能再接收数据,发送方应停止数据的发送,除非是特别紧急的数据
参与TCP通信的接收方在接收数据的同时,会不断告知对方它最多还能够接收多少字节数据,即所谓滑动窗口
任何时候,滑动窗口都反映了接收缓冲区可用空间的大小,以确保不会因发送数据的速度过快而导致溢出丢失
在某段时间内,如果网络中对某个资源的需求超过了该资源所能提供的极限,网络性能就会变差,这就叫拥塞
拥塞控制的目的就是为了防止过多的数据在短时间内注入网络,导致网络中的路由器、交换机等设备出现过载
参与TCP通信的发送方会维护一个拥塞窗口,该窗口的大小反映了网络当前的承载能力,随时可能发生变化
发送方滑动窗口其实是由拥塞窗口和接收方滑动窗口中较小的那个决定的,既要网络送得出,又要对方接得住
与拥塞控制有关的算法主要有三个:
慢开始:发送伊始,对网络的承载能力尚不明确,先低速慢传,逐渐增大拥塞窗口
拥塞避免:拥塞窗口的增大速度不宜过快,每经历一个RTT,只增大一个字节
快重传和快恢复:接收方根据分组序号发现缺失了某个分组,直接告诉发送方重传,不必等待超时再重传
基于TCP的常见应用层协议
超文本传输协议(HTTP、HTTPS):从Web服务器上下载超文本内容在浏览器中显示,默认使用80端口
文件传输协议(FTP):上传和下载文件,默认使用21端口
简单邮件传输协议(SMTP):发送电子邮件到邮件服务器,默认使用25端口
邮局协议第三版(POP3):从邮件服务器接收电子邮件,默认使用110端口
远程登录协议(TELNET):远程登录到服务器,默认使用23端口
安全外壳协议(SSH):以加密方式远程登录到服务器,默认使用22端口
基于UDP的常见应用层协议
简单文件传输协议(TFTP):上传和下载文件,默认使用69端口
动态主机配置协议(DHCP):分配和管理局域网内计算机的IP地址,服务器默认使用67端口,客户机默认使用68端口
简单网络管理协议(SNMP):管理网路中的各种设备,默认使用161端口
域名服务协议(DNS):将主机域名解析为IP地址,默认使用53端口
第一路握手:客户机向服务器发送一个SYN分组,序号为J,而后进入SYN_SENT状态
第二路握手:服务器收到来自客户机的SYN分组,向客户机发送一个ACK+SYN分组,确认号为J+1,序号为K,而后进入SYN_RCVD状态
第三路握手:客户机收到来自服务器的ACK+SYN分组,向服务器发送一个ACK分组,确认号为K+1,而后进入ESTABLISHED状态;服务器收到来自客户机的ACK分组,也进入ESTABLISHED状态,连接建立完成
TCP连接的三路握手是为了让参与通信的双方能够确认自己和对方的发送和接收能力
第一路握手是为了让服务器确认:客户机能发送、服务器能接收
第二路握手是为了让客户机确认:客户机能发送、服务器能接收、服务器能发送、客户机能接收
第三路握手是为了让服务器确认:服务器能发送、客户机能接收
如果没有第三路握手,服务器就无法确认自己是否可以发送,而对方是否可以接收
第一路挥手:客户机向服务器发送一个FIN分组,序号为M,而后进入FIN_WAIT_1状态
第二路挥手:服务器向客户机发送一个ACK分组,确认号为M+1,而后进入CLOSE_WAIT状态;客户机收到该分组后进入FIN_WAIT_2状态
第三路挥手:服务器向客户机发送一个FIN分组,序号为N,而后进入LAST_ACK状态
第四路挥手:客户机向服务器发送一个ACK分组,确认号为N+1,而后进入TIME_WAIT状态,并在该状态停留一个报文往返时间,即2MSL后,进入CLOSED状态;服务器收到该分组后进入CLOSED状态,连接断开完成
假设在TCP四路挥手的第四路,客户机向服务器发送了ACK分组,并进入TIME_WAIT状态后,由于某种原因,服务器并没有收到该分组,这时服务器会向客户机重发第三路的FIN分组
客户机的ACK分组到达服务器需要1MSL,服务器重发的FIN分组到达客户机也需要1MSL,二者之和是2MSL
这是客户机判断服务器是否收到ACK分组的最大时长,超过2MSL仍没有收到服务器重发的FIN分组,则可以确信对方已收到ACK分组并进入CLOSED状态,这时客户机再进入CLOSED状态是最为合理的
TCP是一种面向字节流的通信协议,应用层交给传输层的可能是一系列大小不等的数据块,即所谓记录,但在传输层看来,它们只是一段连绵不绝字节序列,即所谓流,其中既没有记录的边界,也没有记录的大小
当应用层从传输层获取接收到的数据时,一次得到的可能一条完整的记录,也可能是部分记录或多条记录,甚至可能是一或多条记录连带着部分记录,这种记录与记录间的粘连现象,称为TCP粘包
如果在一个TCP连接中只发送和接收一条记录,则不可能发生粘包现象
发送方产生的粘包:当所发送的记录比较小时,TCP的传输层会将多条记录合并为一个分组,放到发送缓冲区中,这些记录在发送时就已经是粘包状态了
接收方发生的粘包:传输层不断将接收到的数据写入接收缓冲区,应用层不断从接收缓冲区读取数据。如果应用层读取的速度赶不上传输层写入的速度,接收缓冲区中的数据将发生粘连
一次一连法
通信双方先建立连接,一方发送一条记录,如有需要可再接收对方返回的一条记录
另一方接收一条记录,如有需要可再向对方返回一条记录,之后通信双方断开连接
定长记录法
人为规定每条记录都采用固定的长度
按该长度从接收缓冲区中读取的数据都是完整的记录
特殊分隔符法
在每条记录与下一条记录中间插入一个特殊的分隔符
接收时以该分隔符作为划分记录的依据
定长包头法
在每条记录的前面增加一个固定长度的包头,其中包含该记录的实际长度
接收时先接收固定长度的包头,再根据包头中的记录长度,接收记录内容
基于TCP协议的网络编程模型
服务器
创建套接字(create)
绑定地址和端口(bind)
启动监听(listen)
等待并接受客户机连接(accept)并获得用于后续通信的套接字
和客户机收发报文(recv、send)
关闭套接字(close)
客户机
创建套接字(create)
连接服务器(connect)
和服务器收发报文(recv、send)
关闭套接字(close)
基于UDP协议的网络编程模型
创建套接字(create)
绑定地址和端口(bind)
接收和发送报文(recvfrom、sendto)
关闭套接字(close)
在TCP三路握手的第三路,客户机收到来自服务器的ACK+SYN分组,并向服务器发送一个ACK分组,随即进入ESTABLISHED状态,这时connect函数即返回
服务器在收到来自客户机的ACK分组后,将处于SYN_RCVD状态的套接字从未完成连接队列移入已完成连接对象,并将其状态更新为ESTABLISHED状态
accept函数从已完成队列中获取并返回处于ESTABLISHED状态套接字,该套接字可用于后续通信
客户机侧的connect函数可能会早于服务器侧的accept函数返回,这种情况下客户机发送的数据,会被服务器侧的传输层排队缓存在接受缓冲区中,待accept函数返回后,再被应用层读取
退出或重启的一方会向另一方发送FIN分组并得到ACK应答
如果此时正在接收数据,执行接收操作的函数会返回0
如何此时正在发送数据,执行发送操作的函数不会返回失败,但会导致对方响应RST分组,该分组将超前于FIN分组,导致后续执行接收操作的函数返回失败,错误号为ECONNRESET
任何通过已收到RST分组的套接字发送数据的操作,都会触发SIGPIPE信号
主机断电,传输层不可能再有任何数据分组的交换
如果此时正在接收数据,执行接收操作的函数会返回0
如何此时正在发送数据,执行发送操作的函数不会返回失败,但会因传输层的多次超时重传,导致后续执行接收操作的函数返回失败,错误号为ETIMEOUT、EHOSTUNREACH或者ENETUNREACH
如果在对方恢复供电并启动后发送数据,对方的传输层一律响应RST分组
调用connect函数前,先通过alarm函数设置定时器,利用SIGALRM信号,打断可能发生阻塞的connect调用
借助ioctlsocket函数将套接字设置为非阻塞模式(FIONBIO)
基于多进程的并发服务器:启动和切换速度慢,需要额外的进程间通信机制,无需同步机制解决并发冲突
基于多线程的并发服务器:启动和切换速度快,无需额外的线程间通信机制,需要同步机制解决并发冲突
基于TCP协议的客户机和服务器在建立连接后,服务器每收到一个来自客户机的数据分组,即开启一个保活计时器,为期2小时
若在保活计时器到期时,仍没有收到来自客户机的任何数据分组,服务器就会每隔75秒向客户机发送一个探测分组
如果一连发送了10个探测分组,仍没有收到来自客户机的任何回应,则认定客户机故障,关闭此连接
当需要处理可能在多个文件描述符上同时发生的I/O事件时:
创建多个进程或线程,在每个进程或线程中监听一个文件描述符的I/O事件,并对所发生的事件进行处理
通过I/O多路复用,在一个进程或线程中同时监听多个文件描述符的I/O事件
在一个进程或线程中依次处理多个文件描述符的I/O事件
在多个进程或线程中同时处理多个文件描述符的I/O事件
与I/O多路复用有关的系统调用包括:select、poll和epoll
I/O多路复用的优点
用单进程或单线程模型,取代多进程或多线程模型
规避了进程间通信和线程同步的复杂性
规避了在进程或线程间切换任务的开销
在一个或尽可能少的进程或线程中处理I/O事件,比在大量进程或线程中等待I/O事件的资源开销小
I/O多路复用的缺点
单进程或单线程模型,不利于充分发挥多核处理器的性能优势
处理逻辑相对复杂,不符合人类自然的思维习惯
调用select函数时,需要将文件描述符集从用户空间复制到内核空间,平均时间复杂度为线性级
从select函数返回,需要遍历文件描述符集中的文件描述符,平均时间复杂度为线性级
系统内核对被监听文件描述符集的大小有所限制,默认为1024
在TCP通信中,select发现某个套接字可读,但实际读到的字节数却是0,说明对方关闭了与之相连的套接字的写端,本方关闭套接字的读端即可
监听套接字在TCP连接成功建立时可读
通信套机字在接收缓冲区有数据时可读
通信套机字在对方套接字被关闭时可读
任何套接字在有错误发生且未决时可读
epoll解决了select和poll在复制和遍历文件描述符集过程中的时间复杂度问题,效率更高
在注册需要监听的I/O事件时,需要将数据从用户空间复制到内核空间
当监听到有I/O事件发生并返回时,需要将数据从内核空间复制到用户空间
epoll在内核中以红黑树的形式组织被监听事件,查询操作的平均时间复杂度为对数级
epoll采用回调函数的方式处理被监听到的事件,平均时间复杂度为常数级
事件触发条件不同
LT:电平触发,专注于缓冲区的状态
ET:边沿触发,专注于缓冲区的变化
以读就绪事件为例
LT:只要缓冲区中还有可读数据就会触发读就绪事件
ET:只有当缓冲区被填入新数据时才触发读就绪事件
如果一次读操作没有读完缓冲区中的数据
LT:缓冲区中还有可读数据,持续触发读就绪事件,继续读取剩余数据
ET:缓冲区中没有新增数据,不再触发读就绪事件,在新数据到达前剩余数据不会被读取
编程模式
LT:读写就绪事件触发,不一定要读写完全部数据,随时触发随时读写
ET:读写就绪事件触发,尽可能地读写完全部数据,可能失去读写机会
ET比LT的效率更高,更适合在高并发大流量的场合中使用,但对编程者的要求更高,必须仔细处理好每次事件触发,否则容易导致读写数据不完整的问题
HTTP/1.0
浏览器和服务器之间只保持短连接,一个连接只能传输一个请求和一个响应,再发请求需要重新建立连接
通过“Connection: keep-alive”字段虽可开启长连接,但其并非标准字段,不同实现的具体处理不尽相同
HTTP/1.1
浏览器和服务器之间保持长连接,在同一个连接上传输多个请求和响应,直到一方长期失活或主动断开
引入流水线机制(Pipelining),浏览器可以连续发送多个请求,进一步提高传输效率
HTTP/2.0
采用多路复用,在同一个连接上不但可以传输多个请求和响应,而且它们的先后顺序不必安全一致
通过头部压缩和服务端推送,进一步提高传输效率
目前主流的HTTP协议依然是HTTP/1.1,HTTP/2.0的使用率正在逐年增加
GET方法:获取资源
POST方法:上传资源
PUT方法:更新资源
DELETE方法:删除资源
PATCH:修改资源
HEAD方法:获取包头
TRACE方法:追踪路径
CONNECT方法:建立隧道
OPTIONS方法:查询被支持的方法
应用场景不同
GET方法主要用于获取资源
POST方法主要用于上传资源
携带参数的方式不同
GET方法所携带的参数通常位于URL字符串中,其中包含汉字在内的特殊字符需要编码为ASCII字符
POST方法所携带的参数通常位于包体中,且支持标准字符集,如UTF-8等
安全性不同
GET方法不会改变服务器状态,因此是安全的
POST方法可能改变服务器状态,因此不是安全的
幂等性不同
相同的GET方法只执行一次,和连续执行多次,在效果上是一样的,因此具有幂等性
相同的POST方法执行的次数不同,其效果往往也不同,因此不具幂等性
可缓存性不同
缓存针对GET方法的响应,通常是可行的
缓存针对POST方法的响应,通常没有意义
对XMLHttpRequest的支持不同
在使用XMLHttpRequest的GET方法时,包头和包体必须合在一起发送
在使用XMLHttpRequest的POST方法时,可以先发送包头,再发送包体
GET方法所携带的参数通常位于URL字符串中,其中包含汉字在内的特殊字符需要编码为ASCII字符,例如:
“汉字”被编码为“%E4%B8%AD%E6%96%87”
空格被编码为“%20”
GET方法所携带的参数以键值对表示,键和值以“=”分隔,键值对之间以“&”分隔,但如果键或值内部也包含这两个分隔符字符,则需对其编码,以防被误解为分隔符,例如:
“student=tom&jerry&work=2+3=5”被编码为“student=tom%26jerry&work=2+3%3D5”
基于HTTP/1.0的浏览器和服务器之间默认为短连接,发完请求,收完响应,连接即断开
如果希望连接继续保持,可以在请求包头中增加“Connection: keep-alive”字段,显式指明使用长连接
HTTP/1.1及更高版本,默认为长连接,如果希望短连接,可以在请求包头中增加“Connection: close”字段
使用长连接的浏览器和服务器之间,可以一个连接上完成多个请求响应交互。适用于需要频繁交互的场景,比如观看在线视频、玩网页游戏、参与在线交易,等等
使用短连接的浏览器和服务器之间,一个连接上只能发送和接收一个请求和响应,再发请求必须重新建立连接。适用于只需要偶尔交互的场景,比如浏览静态网页、上传下载文件、查收电子邮件,等等
HTTP实现长连接包括两个方面
一方面是在浏览器提交给服务器的请求包头中,加上“Connection: keep-alive”字段。当然这是在使用HTTP/1.0的情况下,因为在HTTP/1.1以后,长连接已经成为默认的选项,无需再显式指明
另一方面是服务器要支持长连接。如果服务器不支持,浏览器的长连接请求会被忽略
长连接并非无限期的连接,除了浏览器或服务器中的一方或双方,在业务处理完毕后主动断开连接以外,闲置时间过长的连接也会被服务器强行关闭
一方面在浏览器提交给服务器的请求包头中可以设置闲置超时
另一方面在服务器的配置文件里也可以设置默认的闲置超时
1xx:中间状态,还需后续请求
101:切换协议
2xx:成功
200:成功且有响应包体
3xx:重定向状态,还需后续请求
301:永久重定向,会缓存
302:临时重定向,不会缓存
304:协商缓存命中
4xx:浏览器错误
400:请求错误
403:服务器禁止访问
404:资源未找到
5xx:服务器错误
500:服务器内部错误
504:服务器繁忙
在网站的日常维护中,经常需要调整页面的目录结构和存储位置,这些调整必然会导致页面地址的改变
当用户通过浏览器收藏夹或搜索引擎数据库中的旧地址请求页面时,会得到404错误,进而损失用户流量
状态码301、302旨在告诉浏览器,所访问页面已被重定向到另一个页面,浏览器进而发起对新页面的请求
301表示永久重定向,搜索引擎会用该定向的目标地址替换源地址,源地址不复存在
302表示临时重定向,搜索引擎认为该定向的目标地址是临时性的,源地址会被保留
Forward和Redirect是两种不同的请求转发方式
Forward转发,即直接转发,客户机只提交一个请求,由服务器将其转发给对第二个请求的处理
Redirect转发,即间接转发,客户机先提交第一个请求,根据服务器的响应,再提交第二个请求
传统意义上的HTTP协议是一个无状态的短连接协议。浏览器向服务器每次发送请求之前都要重新建立TCP连接,并在收到响应后关闭此连接。连接的生命周期仅在一次HTTP请求和一次HTTP响应之间。每一次连接续存期间所产生的内存数据,无论是在服务器侧还是浏览器侧都是不保留的。因此每一次连接都是全新的,独立的,不会带有之前任何一次连接遗留下来的状态信息
Cookie和Session都是为了解决HTTP协议无状态问题的技术手段,即设法将某次连接过程中产生的数据,延续到后续连接中继续使用
Cookie为HTTP协议自带,不需要第三方支持,以键值对的形式,将用户名、登录时间等非敏感信息,在浏览器侧保存一段时间。在Cookie到期前,其中的信息可被用于所有与服务器之间的连接交互。但是一般来讲,浏览器都缺乏完善的保护机制,保存在浏览器侧的Cookie很容易被窃取或篡改,安全性很低
浏览器和服务器之间的多次请求、响应交互通常带有明显的业务相关性。比如在电商场景中,登录、搜索、添加购物车、下单购买、查看订单,其中的每个动作都是独立的请求、响应交互,合在一起构成一个完整的业务流程。在这样的业务流程中,通常会有很多需要在多次交互中共享的信息。这种存在业务相关性的多次交互称为一个会话,在一个会话中被多次交互共享的数据则称为Session。与Cookie不同,Session的生命期仅限于当前会话,会话结束,比如关闭浏览器,Session即被删除。Session保存在服务器侧,服务器通常具有完善的保护机制,窃取和篡改服务器上的数据会非常困难,因此Session具有更高的安全性。浏览器和HTTP协议本身并没有提供对Session的支持,需要服务器侧应用的开发者自己实现
在服务器侧实现Session的难点在于,服务器所服务的对象通常不止一个,多个浏览器同时和服务器交互,服务器侧随时会有多个会话及与之关联的Session同时并存,那么服务器如何判定哪个Session属于哪个会话,对应哪个浏览器呢?应对这种问题,有很多方法。其中之一就是让Session和Cookie配合工作。当浏览器向服务器发送会话中的第一个请求时,服务器即为此会话生成一个键值对,保存在类似Redis这样的容器中,其中的值包含了需要在会话中被共享的数据,键经加密后作为值被放到一个Cookie中,该Cookie与响应一起返回给浏览器。浏览器从响应中提取该Cookie,保存在本地,并在后续发送请求时携带该Cookie。服务器从请求中提取该Cookie,解密其值即得到Session的键,在容器中找到与之对应的值
默认端口不同
HTTP协议默认使用80端口
HTTPS协议默认使用443端口
费用不同
HTTP协议本身是免费的,使用基于HTTP协议的应用,不需要为协议本身支付费用
HTTPS协议虽然也是免费的,但该协议会用到CA证书,申请证书通常需要支付费用
开销不同
HTTP是超文本传输协议,信息采用明文传输,系统开销较小
HTTPS是基于SSL的密文传输协议,信息加解密需要消耗更多资源
安全性不同
HTTP协议本身毫无安全性可言,信息在传输过程中易被窃取和篡改
HTTPS协议借助加密通信、身份认证等机制,确保信息在传输过程中的安全性
客户机
服务器
客户机:验证服务器证书合法性,随机生成预密钥
客户机
服务器:用服务器证书中的私钥解密预密钥密文得到预密钥
客户机
服务器:将密文经主密钥解密后得到明文,验证其是否与所有接收自客户机的信息的哈希值一致
服务器
客户机:将密文经主密钥解密后得到明文,验证其是否与所有接收自服务器的信息的哈希值一致
客户机和服务器:握手完成,使用主密钥加解密后续通信内容
HTTPS的优点
支持对客户机和服务器的双向认证,确保数据总是被可信任的接收者接收
对通信数据采用加密传输,防止数据被窃取和篡改,确保数据的完整性
虽然无法做到绝对安全,但会大幅提高攻击者的攻击成本
HTTPS的缺点
握手阶段比较费时,页面加载时间增加50%,耗电量增加10%~20%
对通信内容的加解密会增加运行开销和功耗,已有的安全措施也会因此受到影响
SSL证书通常都不是免费的,功能越强的证书费用往往也越高
SSL证书通常都是与IP绑定的,因此无法在同一个IP上使用多个域名,进一步增加对IPv4的资源消耗
SSL证书的信用链并不完整,在某些国家可以控制根证书的情况下,中间人攻击一样可行
基于加密的信息安全作用有限,对拒绝服务、服务器劫持等攻击手段,起不到任何作用
数字签名的作用有两个
让接收方能够确认所收到的信息来自可信任的发送方
让接收方能够确认所收到的信息没有在传递过程中被篡改
发送方做签名:先计算信息的数字摘要,然后用私钥对数字摘要做加密,得到数字签名与信息一起发送
接收方做验签:先计算信息的数字摘要,然后用公钥对数字签名做解密,检验解密所得与摘要是否一致
合法性理由
假设信息并非来自可信发送方,用可信发送方的公钥不可能解密出数字摘要
假设信息在传输过程中被篡改,计算出的数字摘要不可能与解密所得相一致
数字证书是用于保存公私密钥对的电子文件
加密时接收方将自己的数字证书交给发送方
发送方先用对称密钥加密数字内容,得到内容密文,再用数字证书中的公钥加密对称密钥,得到密钥密文
接收方先用数字证书中的私钥解密密钥密文,得到对称密钥,再用对称密钥解密内容密文,得到数字内容
签名时发送方将自己的数字证书交给接收方
发送方先计算信息的数字摘要,然后用数字证书中的私钥对数字摘要做加密,得到数字签名
接收方先计算信息的数字摘要,然后用数字证书中的公钥对数字签名做解密,比对数字摘要
除公私密钥对外,数字证书中还包含证书指纹、证书有效期、证书持有者和颁发机构信息等内容
域名解析:依次查询浏览器自身的域名缓存、操作系统的域名缓存、本地Host文件、本地域名服务器等,获得目的主机的IP地址
建立连接:根据目的主机的IP地址,结合默认或指定的端口号,建立与目的主机的TCP连接
发送请求:通过已建立的连接,向目的主机发送HTTP请求
接收响应:通过已建立的连接,从目的主机接收HTTP响应
解析渲染:解析收到的HTTP响应,渲染页面内容
断开连接:若采用短连接模式,则断开与目的主机的连接,否则保持该连接
本地域名服务器先查询存储在本地的域名资源
要么返回查询到的IP地址
要么向根域名服务器发出查询请求
根域名服务器先查询存储在本地的域名资源
要么返回查询到的IP地址
要么返回某个顶级域名服务器的IP地址
顶级域名服务器先查询存储在本地的域名资源
要么返回查询到的IP地址
要么返回某个权限域名服务器的IP地址
以此类推,最后本地域名服务器,向浏览器返回目的主机的IP地址,或报告错误
无论是本地域名服务器还是主机,都会将最近查询过的域名保存在高速缓存中,以缩短响应时间,减轻域名服务器的负荷,降低互联网上域名查询报文的数量
域名缓存中的每条域名信息都有一个生存时间,超过生存时间的域名信息会从缓存中被删除。生存时间越长,网络开销越小,生存时间越短,域名解析的正确率越高
主机甚至可以在启动时,将本地域名服务器的域名数据库直接下载到域名缓存中,并对缓存中的域名信息定期维护,添加新增的域名信息,删除失效的域名信息
域名的变动并不频繁,域名缓存中的域名信息,在多数时间内都是有效的
SQL注入是一种常见的Web攻击方式,其主要形式是借由用户的输入,将一段恶意代码串联到SQL语句中,以达到执行非预期命令或访问未授权数据的目的
例如,有这样一条SQL语句:
xxxxxxxxxx
11SELECT * FROM users WHERE user_id = $user_id;
其中,user_id来自用户的输入,如果输入“1234; DELETE FROM users”,则最终的SQL语句变为:
xxxxxxxxxx
11SELECT * FROM users WHERE user_id = 1234; DELETE FROM users;
执行以上语句,会删除users表中的所有数据
又如,有这样一条SQL语句:
xxxxxxxxxx
11SELECT * FROM users WHERE user_id = $user_id AND password = $password;
其中,user_id和password来自用户的输入,如果输入“'' OR 1 = 1 --”和“''”,则最终的SQL语句变为:
xxxxxxxxxx
11SELECT * FROM users WHERE user_id = '' OR 1 = 1 -- AND password = '';
“user_id = '' OR 1 = 1”恒为真,后面的“--”表示注释,该语句总能查询到结果,轻易地骗过系统,取得合法身份
针对SQL注入攻击的最有效的防范手段,就是使用SQL预编译和参数绑定技术。攻击者的恶意代码,只会被当做SQL语句的参数,而非SQL命令的一部分,这样的代码是不会被执行的
XSS是除SQL注入以外,另一种主流的Web攻击方式,其原理是通过用户提交的数据,将恶意代码嵌入到Web页面中,当这些代码被执行时,将可能盗取用户资料,假借用户身份执行某种操作,或令用户系统感染病毒等
例如,有这样一行URL字符串:
xxxxxxxxxx
11http://www.test.com/message.php?send=Hello,World!
访问该URL将得到一段HTML文本,浏览器渲染该文本的结果是显示“Hello,World!”字符串。攻击者将这行URL字符串篡改成下面这样:
xxxxxxxxxx
11http://www.test.com/message.php?send=<script>alert('You are foolish!')</script>
访问该URL将得到一段HTML文本,其中包含一段JavaScript脚本,浏览器在渲染页面时会执行这段脚本
又如,页面中的表单域:
xxxxxxxxxx
11<input type="text" name="content" value="填写内容" />
将表单提交到服务器后,用户填写的内容将被保存到数据库中,而如果用户填写的是一段脚本代码:
xxxxxxxxxx
11<script>alert('You are foolish!')</script>
这段代码将也被保存到数据库中,并在显示查询结果的页面中被执行
XSS攻击的根本原因,就是过于相信客户端提交的数据,不做任何检查和过滤
防范XSS攻击的核心就是永远不要轻信客户端提交的数据
将重要的Cookie标记为HttpOnly,这样JavaScript中的document.cookie语句就无法获取Cookie了
显式规定表单中各字段的数据类型,比如用户名必须是字母或数字的组合,不能是其它
从客户端提交的数据中过滤掉“<script>”之类的特殊标签