第6章——HTTP 首部
6.1 HTTP 报文首部
-
HTTP 请求报文
在请求中,HTTP 报文由方法、URI、HTTP 版本、HTTP 首部字段等部分构成。
GET / HTTP/1.1 Host: hackr.jp User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/2010010 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive If-Modified-Since: Fri, 31 Aug 2007 02:02:20 GMT If-None-Match: "45bae1-16a-46d776ac" Cache-Control: max-age=0 -
HTTP 响应报文
在响应中,HTTP 报文由 HTTP 版本、状态码(数字和原因短语)、HTTP 首部字段 3 部分构成。
HTTP/1.1 304 Not Modified Date: Thu, 07 Jun 2012 07:21:36 GMT Server: Apache Connection: close Etag: "45bae1-16a-46d776ac"
6.2 HTTP 首部字段
HTTP 首部字段是构成 HTTP 报文的要素之一,使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。首部字段由字段名和字段值构成,中间用冒号分割,另外,字段值对应单个 HTTP 首部字段可以有多个值,如下所示:
Keep-Alive: timeout=15, max=100
若 HTTP 首部字段重复了会如何? 当 HTTP 报文首部中出现了两个或两个以上具有相同首部字段名时会怎么样?这种情况在规范内尚未明确,根据浏览器内部处理逻辑 的不同,结果可能并不一致。有些浏览器会优先处理第一次出现的首部字段,而有些则会优先处理最后出现的首部字段。
HTTP 首部字段根据实际用途被分为以下 4 种类型:
-
通用首部字段(General Header Fields)
请求报文和响应报文两方都会使用的首部。
-
请求首部字段(Request Header Fields)
从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
-
响应首部字段(Response Header Fields)
从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
-
实体首部字段(Entity Header Fields)
针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。
HTTP/1.1 规范定义了 47 种首部字段--》HTTP/1.1 首部字段一览表
非 HTTP/1.1 首部字段:
在 HTTP 协议通信交互中使用到的首部字段,不限于 RFC2616 中定义的 47 种首部字段。还有 Cookie、Set-Cookie 和 Content-Disposition等在其他 RFC 中定义的首部字段,它们的使用频率也很高。
HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分成 2 种类型。
-
端到端首部(End-to-end Header)
首部会转发给请求 / 响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。
-
逐跳首部(Hop-by-hop Header)
首部只对单次转发有效,会因通过缓存或代理而不再转发。HTTP/1.1 和之后版本中,如果要使用 hop-by-hop 首部,需提 供 Connection 首部字段。
6.3 HTTP/1.1 通用首部字段
-
Cache-Control
通过指定首部字段 Cache-Control 的指令,就能操作缓存的工作机制。指令的参数是可选的,多个指令之间通过“,”分隔。例如:
Cache-Control: private, max-age=0, no-cache-
缓存请求指令:
指令 参数 说明 no-cache 无 强制向源服务器再次验证,防止从缓存中返回过期的资源
| no-store | 无 | 不缓存请求或响应的任何内容 | | max-age = [ 秒] | 必需 | 响应的最大Age值,当指定 max-age 值为 0,那么缓存服务器通常需要将请求转发给源服务器 | | max-stale = [ 秒] | 可省略 | 接收已过期的响应,如果指令未指定参数值,那么无论经过多久,客户端都会接收响应;如果指令中指定了具体数值,那么即使过期,只要仍处于 max-stale指定的时间内,仍旧会被客户端接收。 | | min-fresh = [ 秒] | 必需 | 期望在指定时间内的响应仍有效,例如 Cache-Control:min-fresh=60,这就要求缓存服务器发送60秒内的数据。 | | no-transform | 无 | 代理不可更改媒体类型 | | only-if-cached | 无 | 仅从缓存获取资源,若发生请求缓存服务器的本地缓存无响应,则返回状态码 504 Gateway Timeout。 | | cache-extension | - | 新指令标记(token) |
-
缓存响应指令:
指令 参数 说明 public 无 可向任意方提供响应的缓存,其他用户也可以利用缓存 private 可省略 仅向特定用户返回响应,其他用户发送的请求不会返回缓存 no-cache 可省略 如果服务器返回的响应中包含 no-cache 指令,那么缓存服务器不能对资源进行缓存;若报文首部字段 Cache-Control 中对 no-cache字段名具体指定参数值,那么客户端在接收到这个被指定参数值的首部字段对应的响应报文后,就不能使用缓存。 no-store 无 不缓存请求或响应的任何内容 no-transform 无 代理不可更改媒体类型,这样做可防止缓存或代理压缩图片等类似操作 must-revalidate 无 可缓存但必须再向源服务器进行确认,使用 must-revalidate 指令会忽略请求的 max-stale 指令 proxy-revalidate 无 要求中间缓存服务器对缓存的响应有效性再进行确认 max-age = [ 秒] 必需 响应的最大Age值 s-maxage = [ 秒] 必需 公共缓存服务器响应的最大Age值,使用后直接忽略对 Expires 首部字段(实体主体过期的日期时间)及max-age 指令的处理 cache-extension - 新指令标记(token)
-
-
Connection
作用有如下两种:
-
控制不再转发给代理的首部字段
-
管理持久连接
HTTP/1.1 版本的默认连接都是持久连接,若想断开持久连接则指定Connection 首部字段的值为 Close。而HTTP/1.1 之前的 HTTP 版本的默认连接都是非持久连接。想要维持持续连接则需要指定Connection 首部字段的值为 Keep-Alive。
-
-
Date
首部字段 Date 表明创建 HTTP 报文的日期和时间。
//HTTP/1.1 协议使用在 RFC1123 中规定的日期时间的格式 Date: Tue, 03 Jul 2012 04:40:59 GMT //之前的 HTTP 协议版本中使用在 RFC850 中定义的格式 Date: Tue, 03-Jul-12 04:40:59 GMT //C 标准库内的 asctime() 函数的输出格式 Date: Tue Jul 03 04:40:59 2012 -
Pragma
Pragma 是 HTTP/1.1 之前版本的历史遗留字段,仅作为与 HTTP/1.0的向后兼容而定义。规范定义的形式唯一,如下所示。
Pragma: no-cache -
Trailer
首部字段 Trailer 会事先说明在报文主体后记录了哪些首部字段。该首部字段可应用在 HTTP/1.1 版本分块传输编码时。
-
Transfer-Encoding
首部字段 Transfer-Encoding 规定了传输报文主体时采用的编码方式。HTTP/1.1 的传输编码方式仅对分块传输编码有效。
-
Upgrade
首部字段 Upgrade 用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。
-
Via
使用首部字段 Via 是为了追踪客户端与服务器之间的请求和响应报文的传输路径。首部字段 Via 不仅用于追踪报文的转发,还可避免请求回环的发生。所以必须在经过代理时附加该首部字段内容。
-
Warning
该首部通常会告知用户一些与缓存相关的问题的警告。格式如下。最后的日期时间部分可省略。
Warning: [警告码][警告的主机:端口号]“[警告内容]”([日期时间])
6.4 请求首部字段
-
Accept
Accept 首部字段可通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级。可使用 type/subtype 这种形式,一次指定多种媒体类型。q代表权重值,用分号(;)进行分隔,1最大,0最小,进度小数点后三位。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0 -
Accept-Charset
Accept-Charset 首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。q同上
Accept-Charset: iso-8859-5, unicode-1-1;q=0.8 -
Accept-Encoding
用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。q同上
Accept-Encoding: gzip, deflate -
Accept-Language
首部字段 Accept-Language 用来告知服务器用户代理能够处理的自然语言集(指中文或英文等),以及自然语言集的相对优先级(同上)。
Accept-Language: zh-cn,zh;q=0.7,en-us,en;q=0.3 -
Authorization
用来告知服务器,用户代理的认证信息(证书值)
-
Expect
客户端使用首部字段 Expect 来告知服务器,期望出现的某种特定行为。
-
From
用来告知服务器使用用户代理的用户的电子邮件地址。
-
Host
用来告知服务器自己请求资源所处的互联网主机名和端口号。Host 首部字段在 HTTP/1.1 规范内是唯一一个必须被包含在请求内的首部字段,因为他和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联。若服务器未设定主机名,那直接发送一个空值即可。
-
If-Match
形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。
-
Max-Forwards
通过 TRACE 方法或 OPTIONS 方法,发送包含首部字段 Max-Forwards 的请求时,该字段以十进制整数形式指定可经过的服务器最 大数目。每转发一次就减一,为0时直接返回响应。
-
Proxy-Authorization
接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段Proxy-Authorization 的请求,以告知服务器认证所需要的信息。
-
Range
对于只需获取部分资源的范围请求,包含首部字段 Range 即可告知服务器资源的指定范围。如:请求获取从第 5001 字节至第 10000 字节的资源。
Range: bytes=5001-10000 -
Referer
首部字段 Referer 会告知服务器请求的原始资源的 URI。
-
TE
首部字段 TE 会告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段 Accept-Encoding 的功能很相像,但是用于传输编码。
-
User-Agent
User-Agent 会将创建请求的浏览器和用户代理名称等信息传达给服务器。
6.5 响应首部字段
-
Accept-Ranges
首部字段 Accept-Ranges 是用来告知客户端服务器是否能处理范围请求,可处理范围请求时指定其字段值为 bytes,反之则指定其为 none。
-
Age
表示源服务器在多久前创建了响应。字段值的单位为秒。
-
ETag
告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag值。有强弱之分,强ETag值只要实体发生改变就会改变;弱的只有资源发生了根本改变才会改变,会在字段值最开始加“W/”。
-
Location
可以将响应接收方引导至某个与请求 URI 位置不同的资源。基本上,该字段会配合 3xx :Redirection 的响应,提供重定向的URI。
-
Proxy-Authenticate
会把由代理服务器所要求的认证信息发送给客户端。
-
Retry-After
告知客户端应该在多久之后再次发送请求,主要配合状态码 503 Service Unavailable 响应,或 3xx Redirect 响应一起使用。
-
Server
知客户端当前服务器上安装的 HTTP 服务器应用程序的信息
Server: Apache/2.2.6 (Unix) PHP/5.2.5 -
Vary
可对缓存进行控制。它决定了对于未来的一个请求头,应该用一个缓存的回复(response)还是向源服务器请求一个新的回复。
扩展阅读:轻松理解HTTP缓存策略
-
WWW-Authenticate
用于 HTTP 访问认证,它会告知客户端适用于访问请求 URI 所指定资源的认证方案(Basic 或是 Digest)和带参数提示的质询(challenge)
6.6 实体首部字段
实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息。
-
Allow
用于通知客户端能够支持 Request-URI 指定资源的所有 HTTP 方法。
-
Content-Encoding
告知客户端服务器对实体的主体部分选用的内容编码方式。
-
Content-Language
首部字段 Content-Language 会告知客户端,实体主体使用的自然语言
-
Content-Length
表明了实体主体部分的大小(单位是字节)。
-
Content-Location
给出与报文主体部分相对应的 URI。
-
Content-MD5
是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达。
-
Content-Range
针对范围请求,返回响应时使用的首部字段 Content-Range,能告知客户端作为响应返回的实体的哪个部分符合范围请求。
-
Content-Type
说明了实体主体内对象的媒体类型。
-
Expires
将资源失效的日期告知客户端。
-
Last-Modified
指明资源最终修改的时间。
6.7 为 Cookie 服务的首部字段
管理服务器与客户端之间状态的 Cookie,虽然没有被编入标准化HTTP/1.1 的 RFC2616 中,但在 Web 网站方面得到了广泛的应用。
-
Set-Cookie(响应首部字段)
属性 说明 NAME=VALUE 赋予 Cookie 的名称和其值(必需项) expires=DATE Cookie 的有效期(若不明确指定则默认为浏览器关闭前为止) path=PATH 将服务器上的文件目录作为Cookie的适用对象(若不指定则默认为文档所在的文件目录) domain=域名 作为 Cookie 适用对象的域名 (若不指定则默认为创建 Cookie的服务器的域名) Secure 仅在 HTTPS 安全通信时才会发送 Cookie HttpOnly 加以限制,使 Cookie 不能被 JavaScript 脚本访问, -
Cookie(请求首部字段)
首部字段 Cookie 会告知服务器,当客户端想获得 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个Cookie 时,同样可以以多个 Cookie 形式发送。
6.8 其他首部字段
HTTP 首部字段是可以自行扩展的。所以在 Web 服务器和浏览器的应用上,会出现各种非标准的首部字段。
-
X-Frame-Options (响应首部)
用于控制网站内容在其他 Web 网站的 Frame 标签内的显示问题。其主要目的是为了防止点击劫持(clickjacking)攻击。首部字段 X-Frame-Options 有以下两个可指定的字段值:
- DENY :拒绝
- SAMEORIGIN :仅同源域名下的页面(Top-level-browsing-context)匹配时许可。
-
X-XSS-Protection (响应首部)
针对跨站脚本攻击(XSS)的一种对策,用于控制浏览器 XSS 防护机制的开关。首部字段 X-XSS-Protection 可指定的字段值如下:
- 0 :将 XSS 过滤设置成无效状态
- 1 :将 XSS 过滤设置成有效状态
-
DNT (请求首部)
Do Not Track的简称,拒绝个人信息被收集,是表示拒绝被精准广告追踪的一种方法。首部字段 DNT 可指定的字段值如下:
- 0 :同意被追踪
- 0 :同意被追踪
-
P3P (响应首部)
通过利用 P3P(The Platform for Privacy Preferences,在线隐私偏好平台)技术,可以让 Web 网站上的个人隐私变成一种仅供程序可理解的形式,以达到保护用户隐私的目的。
第 7 章 确保 Web 安全的 HTTPS
7.1 HTTP 的缺点
-
通信使用明文可能会被窃听
由于 HTTP 本身不具备加密的功能,所以也无法做到对通信整体进行加密。
TCP/IP 是可能被窃听的网络
按TCP/IP 协议族的工作机制,通信内容在所有的通信线路上都有可能遭到窥视,互联网上的任何角落都存在通信内容被窃听的风险,即使经过加密也可以窥视到加密处理后的信息,但是这可能会让人无法破解这些信息。
-
加密处理防止被窃听
目前防止窃听保护信息的对策中,有对通信的加密,通过和 SSL(Secure Socket Layer,安全套接层)或TLS(Transport Layer Security,安全层传输协议)的组合使用,加密 HTTP 的通信内容。与 SSL 组合使用的 HTTP 被称为 HTTPS(HTTPSecure,超文本传输安全协议)或 HTTP over SSL。
另一种是对内容的加密,客户端需要对 HTTP 报文进行加密处理后再发送请求。需要注意的是报文首部是不进行加密的,同事要求客户端和服务端都需要具备加密和解密机制,但任然有内容被篡改的风险。
-
-
不验证通信方的身份就可能遭遇伪装
-
任何人都可以发起请求
HTTP 协议的实现本身非常简单,不论是谁发送过来的请求都会返回响应,因此不确认通信方,会存在以下各种隐患:
- 无法确定请求发送至目标的 Web 服务器是否是按真实意图返回响应的那台服务器,有可能是伪装的服务器。
- 无法确定响应返回到的客户端是否是按真实意图接收响应的那个客户端,有可能是伪装的客户端。
- 无法确定正在通信的对方是否具备访问权限。
- 无法判定请求是来自何方、出自谁手。
- 即使是无意义的请求也会照单全收。无法阻止海量请求下的 DoS 攻击(Denial of Service,拒绝服务攻击)。
-
无法查明对方的证书
使用HTTP无法确定通信方,但是可以使用SSL提供的证书手段确定通信方,证书由值得信任的第三方机构颁发,用以证明服务器和客户端是实际存在的。通过使用证书可以减少个人信息泄露的危险,也可以用于对web网站的认证。
-
-
无法证明报文完整性,可能已遭篡改
所谓完整性是指信息的准确度。若无法证明其完整性,通常也就意味着无法判断信息是否准确。
-
接收到的内容可能有误
没有任何办法确认,发出的请求 / 响应和接收到的请求 / 响应是前后相同的。
-
如何防止篡改
常用的是 MD5 和 SHA-1 等散列值校验的方法,以及用来确认文件的数字签名方法。但这些方法无法百分百确保结果正确,而且被篡改的情况下用户也无法察觉。更好的办法使用过https。
-
7.2 HTTP+ 加密 + 认证 + 完整性保护=HTTPS
-
HTTP 加上加密处理和认证以及完整性保护后即是HTTPS
-
HTTPS 是身披 SSL 外壳的 HTTP
HTTPS 并非是应用层的一种新协议。只是 HTTP 通信接口部分用SSL(Secure Socket Layer)和 TLS(Transport Layer Security)协议代替而已。
在采用 SSL 后,HTTP 就拥有了 HTTPS 的加密、证书和完整性保护这些功能。可以说 SSL 是当今世界上应用最为广泛的网络安全技术。
-
相互交换密钥的公开密钥加密技术
SSL 采用一种叫做公开密钥加密(Public-key cryptography)的加密处理方式。近代加密算法中一般加密算法是公开的,秘钥是保密的,通过这种方式确保加密的安全性,一般来说只要拿到秘钥就可以进行解密了。
-
共享密钥加密的困境
加密和解密同用一个密钥的方式称为共享密钥加密(Common keycrypto system),也被叫做对称密钥加密。共享秘钥的方式需要将秘钥也发给对方依旧意味着秘钥的暴露,所以需要解决秘钥安全转交的问题。
-
使用两把密钥的公开密钥加密
需要使用一对密钥来分别完成加密和解密操作,一个公开发布,即公开密钥,另一个由用户自己秘密保存,即私用密钥。信息发送者用公开密钥去加密,而信息接收者则用私用密钥去解密。
-
HTTPS 采用混合加密机制
HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密机制,因为公开密钥加密虽然安全但是速度很慢,所以一般会在交换秘钥环节用公开密钥加密,然后建立通信交换报文阶段用共享秘钥加密。
-
-
证明公开密钥正确性的证书
公开密钥加密方式还是存在一些问题的。那就是无法证明公开密钥本身就是货真价实的公开密钥。公开密钥也有可能在传输途中被篡改。所以为了解决上述问题,可以使用由数字证书认证机构(CA,CertificateAuthority)和其相关机关颁发的公开密钥证书。
-
HTTPS 的安全通信机制
- 客户端通过发送 Client Hello 报文开始 SSL 通信。报文中包含客户端支持的 SSL 的指定版本、加密组件(Cipher Suite)列表(所使用的加密算法及密钥长度等)
- 服务器可进行 SSL 通信时,会以 Server Hello 报文作为应154答。和客户端一样,在报文中包含 SSL 版本以及加密组件。服务器的加密组件内容是从接收到的客户端加密组件内筛选出来的。
- 之后服务器发送 Certificate 报文。报文中包含公开密钥证书。
- 最后服务器发送 Server Hello Done 报文通知客户端,最初阶段的 SSL 握手协商部分结束。
- SSL 第一次握手结束之后,客户端以 Client Key Exchange 报文作为回应。报文中包含通信加密中使用的一种被称为 Pre-mastersecret 的随机密码串。该报文已用步骤 3 中的公开密钥进行加密。
- 接着客户端继续发送 Change Cipher Spec 报文。该报文会提示服务器,在此报文之后的通信会采用 Pre-master secret 密钥加密。
- 客户端发送 Finished 报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确解密该报文作为判定标准。
- 服务器同样发送 Change Cipher Spec 报文。
- 服务器同样发送 Finished 报文。
- 服务器和客户端的 Finished 报文交换完毕之后,SSL 连接就算建立完成。当然,通信会受到 SSL 的保护。从此处开始进行应用层协议的通信,即发送 HTTP 请求。
- 应用层协议通信,即发送 HTTP 响应。
- 最后由客户端断开连接。断开连接时,发送 close_notify 报文。上图做了一些省略,这步之后再发送 TCP FIN 报文来关闭与 TCP的通信。
-
HTTPS的一些缺点
首先就是https一般比http慢2~100倍,因为一是通信慢,二是加密耗时导致慢。而且要使用https就必须要购买证书,这也是一项不菲的开销,所以一般在敏感信息等数据是采用https,其他的采用http即可。
第8章——确认访问用户身份的认证
8.1 何为认证
认证就是确保此刻坐在这个电脑面前的人就是浏览器上显示的用户,而不是伪造的或者是假扮的,为了确认用户需要核对一下信息:
密码,动态令牌,数字证书,生物认证,身份证等等。HTTP/1.1 使用的认证方式如下所示:
- BASIC 认证(基本认证)
- DIGEST 认证(摘要认证)
- SSL 客户端认证
- FormBase 认证(基于表单认证)
8.2 BASIC 认证
BASIC 认证(基本认证)是从 HTTP/1.0 就定义的认证方式。即便是现在仍有一部分的网站会使用这种认证方式。是 Web 服务器与通信 客户端之间进行的认证方式。
BASIC 认证使用上不够便捷灵活,且达不到多数 Web 网站期望的安全性等级,因此它并不常用。
8.3 DIGEST 认证
为弥补 BASIC 认证存在的弱点,从 HTTP/1.1 起就有了 DIGEST 认证。 DIGEST 认证同样使用质询 / 响应的方式 (challenge/response),但不会像 BASIC 认证那样直接发送明文密码。
DIGEST 认证和 BASIC 认证一样,使用上不那么便捷灵活,且仍达不到多数 Web 网站对高度安全等级的追求标准。因此它的适用范围也 有所受限。
8.4 SSL 客户端认证
SSL 客户端认证是借由 HTTPS 的客户端证书完成认证的方式。凭借客户端证书认证,服务器可确认访问是否来自已登录的客户端。认证的步骤如下:
- 接收到需要认证资源的请求,服务器会发送 CertificateRequest 报文,要求客户端提供客户端证书。
- 用户选择将发送的客户端证书后,客户端会把客户端证书信息以 Client Certificate 报文方式发送给服务器。
- 服务器验证客户端证书验证通过后方可领取证书内客户端的公开密钥,然后开始 HTTPS 加密通信。
多数情况下,SSL客户端认证会和表单认证结合形成一种双因素认证,通过双因素认证后,就可以确认是用户本人正在使用匹配正确的计算机访问服务器。
8.5 基于表单认证
基于表单的认证方法并不是在 HTTP 协议中定义的。客户端会向服务器上的 Web 应用程序发送登录信息(Credential),按登录信息的验证结果认证。对于 Web 网站的认证功能,能够满足其安全使用级别的标准规范并不存在,所以只好使用由 Web 应用程序各自实现基于表单的认证方式。每个网站一般都有各自的认证实现方式,基于表单认证的标准规范尚未有定论,一般会使用 Cookie 来管理Session(会话)。