重要的 HTTP 协议,很重要。《图解 HTTP》读书笔记,作者:上野 宣,译者:于均良。

与 HTTP 协作的 Web 服务器

多域名虚拟主机

HTTP/1.1 规范允许一台 HTTP 服务器搭建多个 Web 站点。客户端使用 HTTP 协议访问服务器时,经常采用类似 www.abc.com 这样的主机域名。域名通过 DNS 服务映射到 IP 地址之后访问目标网站。在相同的 IP 地址下,由于虚拟主机可以寄存多个不同的主机域名,因此发送 HTTP 请求时,必须在 Host 首部内指定主机域名的 URI。

通信数据转发程序:代理、网关、隧道

1、 代理 是一种有转发功能的应用程序,扮演了位于服务器和客户端“中间人”的角色,使用代理服务器的理由有:利用缓存技术减少网络带宽流量;对特定网站的访问控制;获取访问日志。

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

透明代理:转发请求或响应时,不对报文做任何加工被称为透明代理。

2、 网关 是转发其他服务器通信数据的服务器。

3、 隧道 在相隔甚远的客户端和服务器之间进行中转,并保持双方通信连接的应用程序。目的是确保客户端和服务器进行安全的通信。

缓存

缓存是指代理服务器或客户端本地磁盘内保存资源副本。利用缓存可减少对源服务器的访问,节省通信流量和通信时间。

  1. 缓存服务器: 是代理服务器的一种
  2. 客户端缓存(浏览器)
  3. 有效期: 缓存失效, 会再次请求新资源。

确保 Web 安全的 HTTPS

HTTP 的缺点

1、 通信使用明文(不加密),内容可能会被窃听

加密处理防止被窃听:

  1. 通信加密: HTTP 协议没有加密机制,但可以通过和 SSL(Secure Socket Layer,安全套接层)或 TLS(Transport Layer Security,安全层传输协议)的组合使用,加密 HTTP 的通信内容。与 SSL 组合使用的 HTTP 被称为 HTTPS。

  2. 内容加密: 为了做到有效的内容加密,前提是要求客户端和服务器同事具备加密和解密机制。

2、 不验证通信方的身份,因此有可能能遭遇伪装

任何人都可以发起请求:即使是无意义的请求也会照单全收,无法阻止海量请求下的 Dos 攻击(Denial of Service, 拒绝服务攻击)。

查明对手的证书:

虽然使用 HTTP 协议无法确定通信方,但如果使用 SSL 则可以。SSL 提供了一种证书方法可用于确定对方身份。

证书由值得信任的第三方机构颁发,用以证明服务器和客户端是实际存在的。

3、 无法证明报文的完整性,所以有可能已遭篡改

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

1、 HTTPS 是身批 SSL 外壳的 HTTP

通常,HTTP 直接和 TCP 通信。当使用 SSL 时,先和 SSL 通信,再由 SSL 和 TCP 通信。SSL 独立于 HTTP 协议,不仅 HTTP 协议,其他运行在应用层的 SMTP 和 Telent 等协议均可配合 SSL 协议使用。

2、 对称密钥和非对称密钥加密

  1. 对称密钥加密(共享密钥)技术: 加密和解密使用的是同一个密钥
  2. 非对称加密(公开密钥)技术: 两个密钥,私有密钥和公开密钥。发送密文一方使用对方的公开密钥加密,对方收到密文后,使用自己的私有密钥解密。

3、 HTTPS 采用混合加密机制

非对称密钥安全性高,但是速度比对称秘钥慢。所以,在交换密钥环节使用公开密钥方法,之后建立通信交换报文阶段使用共享密钥,既保证安全又提升效率。

4、 证明公开密钥正确性的证书

为了确保公开密钥在传输图中没有被掉包,可以使用数字认证机构(CA, Certificate Authority)颁发的公开密钥证书。服务器将证书发送给客户端,客户端使用 CA 的公开密钥校验证书。浏览器开发商会事先在内部植入常用认证机关的公开密钥,保证认证机关的密钥是安全可靠的。

5、 HTTPS 的安全通信机制

  1. 客户端向服务器发出加密通信请求(ClientHello),并向服务器提供:支持的协议版本;一个随机数(Client random);支持加密的方法;支持压缩的方法。
  2. 服务器回应(ServerHello):确认使用的加密通信协议版本;一个随机数(Server random);确认使用的加密方法;服务器证书。
  3. 客户端收到服务器回应后,首先验证证书,通过后取出公钥,向服务器发送:一个用公钥加密的随机数(Premaster secret);编码改变通知(表示随后的信息将用双方商定的加密方式和密钥发送);客户端握手结束(这一项同时也是前面发送的所有内容的 hash 值,供服务器校验)。
  4. 服务器的最后回应,服务器使用私钥获取 Premaster secret 之后,计算生产本次会话所有的“会话密钥(对称秘钥)”,向客户端发送:编码改变通知;服务器握手结束通知。

接下来,客户端和服务器使用“会话秘钥”进入加密通信。

6、 SSL 和 TLS

SSL 技术最初是由浏览器开发商网景通信公司率先倡导的, 开发过 SSL3.0 之前的版本。 目前主导权已转移到 IETF(Internet Engineering Task Force, Internet 工程任务组) 的手中。

IETF 以 SSL3.0 为基准, 后又制定了 TLS1.0、 TLS1.1 和 TLS1.2。 TSL 是以 SSL 为原型开发的协议, 有时会统一称该协议为 SSL。 当前主流的版本是 SSL3.0 和 TLS1.0。

证书有很多类型,首先分为三种认证级别:

  1. 域名认证(Domain Validation):最低级别认证,可以确认申请人拥有这个域名。
  2. 公司认证(Company Validation):确认域名所有人是哪一家公司,证书里面会包含公司信息。
  3. 扩展认证(Extended Validation):最高级别的认证,浏览器地址栏会显示公司名。

还分三种覆盖范围:

  1. 单域名证书:只能用于单一域名,foo.com的证书不能用于www.foo.com
  2. 通配符证书:可以用于某个域名及其所有一级子域名,比如*.foo.com的证书可以用于foo.com,也可以用于www.foo.com
  3. 多域名证书:可以用于多个域名,比如foo.com和bar.com

7、 SSL 速度慢吗

  1. 通信慢。和 HTTP 相比,除去 TCP 连接、发送 HTTP 请求、响应之外,还要进行 SSL 通信
  2. 必须进行加密解密处理。比起 HTTP 会更多的消耗服务器和客户端的硬件资源。

基于 HTTP 的功能追加协议

HTTP 的瓶颈

  1. 请求只能从客户端开始,客户端不可以接收出响应以外的指令
  2. 请求/响应首部未经压缩就发送。首部信息越多延迟越大
  3. 每次互相发送相同的首部造成浪费

消除 HTTP 瓶颈的 SPDY

在介绍 SPDY 之前,先来了解一下 Ajax 和 Comet 对 HTTP 瓶颈的优化。

  1. Ajax 的核心技术是 XMLHttpRequest 的 API,通过 JS 脚本调用和服务器进行 HTTP 通信,从已加载完毕的 Web 页面上发起请求,实现局部更新,响应传输的数据量会因此减少。
  2. Comet 技术通过延迟应答,模拟实现服务器端想客户端推送(Server Push)的功能。通常,服务器端接收到请求,在处理完毕后会立即返回响应,但是为了实现推动功能,Comet 会先将响应置于挂起状态,当服务器有内容更新是,在返回改响应。
  3. SPDY 在 TCP/IP 的应用层与传输层自己新加一层会话层,同时基于安全考虑,SPDY 规定通信中使用 SSL

使用 SPDY 后,HTTP 协议会获得以下功能:

  1. 多路复用流:一个 TCP 连接,可以无限制处理多个 HTTP 请求
  2. 赋予请求优先级
  3. 压缩 HTTP 首部
  4. 推送功能,支持服务端主动向客户端推送数据
  5. 服务器提示功能:服务器可以主动提示客户端请求所需的资源

期盼已久的 HTTP/2

2015 年,HTTP/2 发布,它不叫 HTTP/2.0,因为标准委员会不打算发布子版本了,下一个新版本将是 HTTP/3。下面介绍 HTTP/2 的新特性:

1、 二进制协议:HTTP/1.1 版的头信息是文本,数据体可以是文本也可以是二进制。HTTP/2 头信息和数据体都是二进制,并且统称为“帧”:头信息帧和数据帧

2、 多工: HTTP/2 复用 TCP 连接,在一个连接里,客户端和服务端可以同时发送多个请求或响应,而且不用按照顺序一一对应,避免了“队头堵塞”,这样双向、实时的通信叫多工(Multiplexing)。每个来源一个连接,HTTP/2 不再依赖多个 TCP 并行。

3、 数据流:HTTP/2 的数据包不是按顺序发送的,同一个连接里连续的数据包可能属于不同的响应。因此必须对数据包做标记,指出它属于哪一个回应。HTTP/2 将每个请求或响应的所有数据包称为一个数据流,每个数据流有一个独一无二的编码,数据包发送的时候必须标记数据流 ID。另外还规定,客户端发出的数据流 ID 为奇数,服务端为偶数。数据流发送到一半时,客户端和服务端都可以发送 RST_STREAM 帧,取消这个数据流。HTTP/1.1 取消数据流的唯一方式是关闭 TCP 连接,HTTP/2 可以取消某次请求,同时保证 TCP 连接还打开着。客户端可以指定数据流的优先级。

4、 头信息压缩:HTTP 协议不记录状态,每次请求都必须带上所有信息,其中很多字段都是重复的。HTTP/2 对这一点做了优化,一方面头信息使用 gzip 或 compress 压缩后再发送,另一方面,客户端和服务端同时维护一张头信息表,所以字段都会存入这个表,生成一个索引号,以后就不发送同样的字段了,已发送索引号。

5、 服务器推送:HTTP/2 允许服务器未经请求,主动向客户端发送资源。比如,客户端请求一个网页,包含很多静态资源。正常情况下,客户端必须收到网页后,解析 HTML 源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。

注:在 HTTP/2 中,请求和响应标头字段的定义保持不变,仅有一些微小的差异:所有标头字段名称均为小写,请求行现在拆分成各个 :method、:scheme、:authority 和 :path 伪标头字段。

扩展阅读

  1. SSL 延迟有多大?
  2. HTTPS 的七个误解(译文)

使用浏览器进行全双工通信的 WebSocket

WebSocket,Web 浏览器与 Web 服务器之间全双工通信标准。其特点包括:

  1. 支持由服务器向客户端推送数据的功能
  2. 建立在 TCP 协议之上,服务器端的实现比较容易
  3. 与 HTTP 协议有良好的兼容性。默认端口也是 80 和 443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器
  4. 数据格式轻量,性能开销小,通信高效
  5. 可以发送文本或二进制数据
  6. 没有同源限制,客户端可以与任意服务器通信
  7. 协议标识是ws,如果加密则为wss

为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一次握手的步骤:

  1. 握手——请求

为了实现 WebSocket 通信,需要用到 HTTP 的 Upgrade 首部字段,告知服务器通信协议发生改变,以达到握手的目的。Sec-WebSocket-Key 字段内记录着握手过程中必不可少的键值。

  1. 握手——响应

对于之前的请求,返回状态码 101 Switching Protocols 的响应,Sec-WebSocket-Accept 的字段值是由握手请求中的 SecWebSocket-Key 的字段值生成的。

成功握手确立 WebSocket 连接,采用 WebSocket 独立数据帧:

来看一下 Chrome 下的报文信息:

Javascript 可以调用“WebSocket API”实现 WebSocket 协议下全双工通信,点击看效果

  1. WebSocket 对象作为一个构造函数,用于新建 WebSocket 实例
1
var ws = new WebSocket('ws://example.com')
  1. readyState属性返回实例对象的当前状态,共四种。
1
2
3
4
5
6
// 1. CONNECTING: 值0,正在连接
// 2. OPEN:值1,连接成功,可以通信了
// 3. CLOSING:值2,连接正在关闭
// 4. CLOSED:值3,连接已关闭
switch (ws.readyState) {
}
  1. 实例对象的onopen属性,用于指定连接成功后的回调函数
1
2
3
4
5
6
7
8
ws.onopen = function() {
ws.send('Hello Server!')
}

// 使用addEventListern,指定多个回调
ws.addEventListener('open', function(event) {
ws.send('Hello Server!')
})
  1. 实例对象的onclose属性,用于指定连接关闭后的回调函数
1
2
3
4
5
6
7
8
9
10
11
ws.onclose = function(event) {
var code = event.code
var reason = event.reason
var wasClean = event.wasClean
}

ws.addEventListener('close', function(event) {
var code = event.code
var reason = event.reason
var wasClean = event.wasClean
})
  1. 实例对象的onmessage属性,用于指定接收到服务器数据后的回调函数
1
2
3
4
5
6
7
ws.onmessage = function(event) {
var data = event.data
}

ws.addEventListener('message', function(event) {
var data = event.data
})

注意,服务端数据可能是文本,也可能是二进制数据(blob对象或者ArrayBuffer对象)。

1
2
3
4
5
6
7
ws.onmessage = function(event) {
var data = event.data
if (typeof data === 'string') {
}
if (data instanceof ArrayBuffer) {
}
}

除了动态判断收到的数据类型,还可以使用binaryType属性,显示指定收到的二进制数据类型。

1
2
3
4
5
6
7
8
9
10
11
// blob数据
ws.binaryType = 'blob'
ws.onmessage = function(event) {
console.log(event.data.size)
}

// ArrayBuffer数据
ws.binaryType = 'arraybuffer'
ws.onmessage = function(event) {
console.log(event.data.byteLength)
}
  1. 实例对象的send()方法用于向服务器发送数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//发送文本
ws.send('your message')

//发送Blob对象
var file = document.querySelector('input[type="file"]').files[0]
ws.send(file)

//发送ArrayBuffer对象
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320)
var binary = new Uint8Array(img.data.length)
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i]
}
ws.send(binary.buffer)
  1. 实例对象的bufferedAmount属性,表示还有多少字节的二进制数据没有发送出去。
1
2
3
4
5
6
7
8
var data = new ArrayBuffer(10000000)
ws.send(data)

if (ws.bufferedAmount === 0) {
// 发送完毕
} else {
// 发送还没结束
}
  1. 实例对象的onerror属性,用于指定报错事的回调函数。
1
2
3
4
5
6
7
ws.onerror = function(event) {
// handle error event
}

ws.addEventListener('error', function(event) {
// handle error event
})

Web 的攻击技术

来自互联网的攻击大多是冲着 Web 站点来的,它们大多把 Web 应用作为攻击目标。

  1. 在客户端即可篡改请求

在 HTTP 请求报文内加载攻击代码, 就能发起对 Web 应用的攻击。通过 URL 查询字段或表单、 HTTP 首部、 Cookie 等途径把攻击代码传入, 若这时 Web 应用存在安全漏洞, 那内部信息就会遭到窃取, 或被攻击者拿到管理权限。

  1. 针对 Web 应用的攻击模式

有两种方式:主动攻击和被动攻击。

主动攻击:指攻击者通过直接访问 Web 应用,把攻击代码传入的攻击模式。 由于该模式是直接针对服务器上的资源进行攻击, 因此攻击者需要能够访问到那些资源。

被动攻击:指利用圈套策略执行攻击代码的攻击模式。 在被动攻击过程中, 攻击者不直接对目标 Web 应用访问发起攻击。具有代表性的攻击是跨站脚本攻击和跨站点请求伪造。

因输出值转义不完全引发的安全漏洞

  1. 跨站脚本攻击(Cross-Site Scription, XSS)

通过存在安全漏洞的 Web 网站注册用户的浏览器内运行非法的 HTML 标签或 JavaScript 进行的一种攻击。 动态创建的 HTML 部分有可能隐藏着安全漏洞。 就这样, 攻击者编写脚本设下陷阱, 用户在自己的浏览器上运行时, 一不小心就会受到被动攻击。

跨站脚本攻击有可能造成以下影响:

1、 利用虚假输入表单骗用户个人信息
2、 利用脚本窃取用户 Cookie,被害者在不知情的情况下,帮助攻击者发送恶意请求
3、 显示伪造的文章或图片

  1. SQL 注入攻击

针对 Web 应用使用的数据库, 通过运行非法的 SQL 而产生的攻击。 该安全隐患有可能引发极大的威胁, 有时会直接导致个人信息及机密信息的泄露。

Web 应用通常都会用到数据库, 当需要对数据库表内的数据进行检索或添加、 删除等操作时, 会使用 SQL 语句连接数据库进行特定的操作。 如果在调用 SQL 语句的方式上存在疏漏, 就有可能执行被恶意注入(Injection) 非法 SQL 语句。

SQL 注入攻击有可能会造成以下等影响:

1、 非法查看或篡改数据库内的数据
2、 规避认证
3、 执行和数据库服务业务关联的程序等

通过 URL 改写查询参数q上野宜'--,构成的 SQL 语句变成:

1
SELECT * FROM bookTbl WHERE author ='上野宣' --' and flag = 1

SQL 语句中的 -- 之后全视为注释。 即, and flag=1 这个条件被自动忽略了。

  1. OS 命令注入攻击

通过 Web 应用, 执行非法的操作系统命令达到攻击的目的。 只要在能调用 Shell 函数的地方就有存在被攻击的风险。

OS 命令注入攻击可以向 Shell 发送命令, 让 Windows 或 Linux 操作系统的命令行启动程序。 也就是说, 通过 OS 注入攻击可执行 OS 上安装着的各种程序。

  1. HTTP 首部注入攻击

攻击者通过在响应首部字段内插入换行, 添加任意响应首部或主体的一种攻击。

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

HTTP 首部注入攻击有可能会造成以下一些影响:

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

  1. 邮件首部注入攻击

Web 应用中的邮件发送功能, 攻击者通过向邮件首部 To 或 Subject 内任意添加非法内容发起的攻击。 利用存在安全漏洞的 Web 网站, 可对任意邮件地址发送广告邮件或病毒邮件。

  1. 目录遍历攻击

对本无意公开的文件目录,通过非法截断其目录路径后, 达成访问目的的一种攻击。 这种攻击有时也称为路径遍历(Path Traversal)攻击。

通过 Web 应用对文件处理操作时, 在由外部指定文件名的处理存在疏漏的情况下, 用户可使用 …/ 等相对路径定位到 /etc/passed 等绝对路径上, 因此服务器上任意的文件或文件目录皆有可能被访问到。 这样一来, 就有可能非法浏览、 篡改或删除 Web 服务器上的文件。

固然存在输出值转义的问题, 但更应该关闭指定对任意文件名的访问权限。

  1. 远程文件包含漏洞

当部分脚本内容需要从其他文件读入时, 攻击者利用指定外部服务器的 URL 充当依赖文件, 让脚本读取之后, 就可运行任意脚本的一种攻击。

因设置或设计上的缺陷引发的安全漏洞

  1. 强制浏览

从安置在 Web 服务器的公开目录下的文件中, 浏览那些原本非自愿公开的文件。

强制浏览有可能会造成以下一些影响:

1、 泄露顾客的个人信息等重要情报
2、 泄露原本需要具有访问权限的用户才可查阅的信息内容
3、 泄露未外连到外界的文件

2、 不正确的错误消息处理

Web 应用的错误信息内包含对攻击者有用的信息。Web 应用抛出的错误消息;数据库等系统抛出的错误消息。

3、 开发重定向

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

开发重定向就是向 URL 指定参数,使本来的 URL 发送重定向跳转:

http://example.com/?redirect=http://www.tricorder.jp

攻击者把重定向指定的参数改成已设好陷阱的 Web 网站对应的链接:

http://example.com/?redirect=http://www.hackr.jp

因会话管理疏忽引发的安全漏洞

会话管理是用来管理用户状态的必备功能, 但是如果在会话管理上有所疏忽, 就会导致用户的认证状态被窃取等后果。

  1. 会话劫持

攻击者通过某种手段拿到了用户的会话 ID, 并非法使用此会话 ID 伪装成用户, 达到攻击的目的。

下面列举几种攻击者可获得会话 ID 的途径:

1、 通过非正规的生成方法推测会话 ID
2、 通过窃听或 XSS 攻击盗取会话 ID
3、 通过会话固定攻击( Session Fixation) 强行获取会话 ID

  1. 会话固定攻击

对以窃取目标会话 ID 为主动攻击手段的会话劫持而言, 会话固定攻击(Session Fixation) 攻击会强制用户使用攻击者指定的会话 ID, 属于被动攻击。

  1. 跨站点请求伪造(Cross-Site Request Forgeries, CSRF)

攻击者通过设置好的陷阱, 强制对已完成认证的用户进行非预期的个人信息或设定信息等某些状态更新, 属于被动攻击。

跨站点请求伪造有可能会造成以下等影响:

1、 利用已通过认证的用户权限更新设定信息等
2、 利用已通过认证的用户权限购买商品
3、 利用已通过认证的用户权限在留言板上发表言论

其他安全漏洞

  1. 密码破解

密码破解有以下两种手段:
1、 通过网络的密码试错
2、 对已加密密码的破解( 指攻击者入侵系统, 已获得加密或散列处理的密码数据的情况)

  1. 点击劫持

利用透明的按钮或链接做成陷阱, 覆盖在 Web 页面之上。 然后诱使用户在不知情的情况下, 点击那个链接访问内容的一种攻击手段。 这种行为又称为界面伪装(UIRedressing)。

已设置陷阱的 Web 页面, 表面上内容并无不妥, 但早已埋入想让用户点击的链接。 当用户点击到透明的按钮时, 实际上是点击了已指定透明属性元素的 iframe 页面。

  1. Dos 攻击

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

主要有以下两种 DoS 攻击方式:
1、 集中利用访问请求造成资源过载, 资源用尽的同时, 实际上服务也就呈停止状态。
2、 通过攻击安全漏洞使服务停。

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

  1. 后门程序

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

通常的后门程序分为以下 3 种类型:
1、 开发阶段作为 Debug 调用的后门程序
2、 开发者为了自身利益植入的后门程序
3、 攻击者通过某种方法设置的后门程序

参考文献

  1. 阮一峰 HTTP 协议入门
  2. Google Developer HTTP/2 简介
  3. 阮一峰 WebSocket 教程
  4. 阮一峰 SSL/TLS 协议运行机制的概述
  5. MDN WebSocket