HTTPS,HTTP追加协议 - 重学计算机网络系列(4)

626 阅读22分钟

前言

  • 本篇文章主要讲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)。
  • 步骤二: 接收到状态码401的客户端为了通过BASIC认证,需要将用户ID及密码发送给服务器。发送的字符串内容是由用户ID和密码构成,两者中间以冒号(:)连接后,再经过Base64编码处理。当用户代理为浏览器时,用户仅需输入用户ID和密码即可,之后,浏览器会自动完成到Base64编码的转换工作。
  • 步骤3:步骤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客户端认证虽然具有高度的安全等级,但因为导入及维持费用等问题,还尚未普及。

Session(会话)管理及Cookie应用

基于表单认证本身是通过服务器端的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页面上发起请求,只更新局部页面。

引用廖雪峰老师的例子(利用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请求,格式如下:
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: websocket和Connection: Upgrade表示这个连接将要被转换为WebSocket连接;
    • Sec-WebSocket-Key是用于标识这个连接,并非用于加密数据;
    • Sec-WebSocket-Version指定了WebSocket的协议版本。
  • 随后,服务器如果接受该请求,就会返回如下响应:
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/2.0

HTTP/2.0在2014年11月实现标准化。

HTTP/2.0的目标是改善用户在使用Web时的速度体验。

有以下几个目标:

  • 异步连接多路复用
  • 头部压缩;
  • 请求/响应管线化