本文使用青花瓷软件和Wireshark进行抓包分析
Wireshark的使用:
本次主要通过 RVI 抓取 iPhone 数据包
使用 Mac 抓取 iPhone 数据包可通过共享和代理两种方式:
使用 Mac 的网络共享功能将 Mac 的网络通过 WiFi 共享给 iPhone 连接;
使用代理软件(例如 Charles、Flidder for Mono、Andiparos)在Mac上 建立HTTP代理服务器。
这两种方式都是将 iPhone 的网络流量导入到 Mac 电脑中,通过 Mac 连接互联网。这就要求 Mac 本身是联网的,对于网络共享的方式还要求 Mac 本身的网络不能使用 WiFi,而且在 iPhone 上只能使用 WiFi 连接,无法抓取到 xG(2G/3G/4G) 网络包。
苹果在 iOS 5 中新引入了“远程虚拟接口(Remote Virtual Interface,RVI)”的特性,可以在 Mac 中建立一个虚拟网络接口来作为 iOS 设备的网络栈,这样所有经过 iOS 设备的流量都会经过此虚拟接口。此虚拟接口只是监听 iOS 设备本身的协议栈(但并没有将网络流量中转到 Mac 本身的网络连接上),所有网络连接都是 iOS 设备本身的,与 Mac 电脑本身联不联网或者联网类型无关。iOS设备本身可以为任意网络类型(WiFi/xG),这样在 Mac 电脑上使用任意抓包工具(tcpdump、Wireshark、CPA)抓取 RVI 接口上的数据包就实现了对 iPhone 的抓包。
Mac OS X 对 RVI 的支持是通过终端命令 rvictl 提供的,在终端(Terminal)中输入“ rvictl ? ”命令可查看帮助:
rvictl Options:
-l, -L List currently active devices
-s, -S Start a device or set of devices
-x, -X Stop a device or set of devices
使用 “ rvictl -s ”命令创建虚拟接口
首先,通过 MFI USB 数据线将 iPhone 连接到安装了 Mac OS+Xcode 4.2(or later) 的 Mac 机上。iOS 7 以上需要搭配 Xcode 5.0(or later),抓包过程中必须保持连接。
然后,通过 Xcode->Organizer->Devices 获取 iPhone 的 UDID(identifier)。
接着,使用“rvictl -s”命令创建 RVI 接口,使用 iPhone 的 UDID 作为参数。
$rvictl -s <UDID>
Http报文首部
HTTP协议的请求和响应报文必定包含HTTP首部。首部内容为客户端和服务端分别处理请求和响应提供所需的信息。
HTTP请求报文
响应报文
在响应中,HTTP报文是有HTTP版本、状态码、HTTP首部字段3部分构成。
HTTP首部字段会根据实际用途分为4种类型
1. 通用首部字段 请求报文和响应报文两方都会使用首部。
2. 请求首部字段 从客户端向服务端发送请求报文的时候使用首部字段。补充了请求的附加内容,也会要求客户端附加额外的内容信息。
3. 响应首部字段 从服务端向客户端返回响应报文时使用的首部。
4. 实体首部字段 针对请求报文和响应报文的实体部分使用的首部。
通用首部字段
首部字段名 | 说明 |
---|---|
Cache-Control | 控制缓存的行为 |
Connection | 逐跳首部、连接的管理 |
Date | 创建报文的日期时间 |
Pragma | 报文指令 |
Trailer | 报文末端的首部一览 |
Transfer-Encoding | 指定报文主体的传输编码方式 |
请求首部字段
首部字段名称 | 说明 | 举例 |
---|---|---|
Accept | 用户代理可处理的媒体类型 | Accept: text/html,application/xhtml+xml,application/xml |
Accept-Charset | 优先的字符集 | Accept-Charset: iso-8859-5, unicode-1-1;q=0.8 |
Accept-Encoding | 优先的内容编码 | Accept-Encoding: gzip, deflate Accept-Encoding 首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。可一次性指定多种内容编码 |
Accept-Language | 优先的语言(自然语言) | ccept-Language: zh-cn,zh;q=0.7,en-us,en;用来告知服务器用户代理能够处理的自然 |
Authorization | Web认证信息 | Authorization: Basic dWVub3NlbjpwYXNzd29yZA==.首部字段 Authorization 是用来告知服务器,用户代理的认证信息(证书值)。通常,想要通过服务器认证的用户代理会在接收到返回的401 状态码响应后,把首部字段 Authorization 加入请求中。共用缓存在接收到含有 Authorization 首部字段的请求时的操作处理会略有差 |
Expect | 期待服务器的特定行为 | expect: 100-continue.客户端使用首部字段 Expect 来告知服务器,期望出现的某种特定行为。因服务器无法理解客户端的期望作出回应而发生错误时,会返回状态码 417 Expectation Failed。客户端可以利用该首部字段,写明所期望的扩展。虽然 HTTP/1.1 规范只定义了 100-continue(状码 100 Continue 之意)。等待状态码 100 响应的客户端在发生请求时,需要指定 Expect:100-continue。 |
From | 用户的电子邮箱地址 | 邮箱地址 |
Host | 请求资源所在服务器 | Host 会告知服务器,请求的资源所处的互联网主机名和端口号。Host 首部字段在 HTTP/1.1 规范内是唯一一个必须被包含在请求内的首部字段。首部字段 Host 和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联,这是首部字段 Host 必须存在的意义。请求被发送至服务器时,请求中的主机名会用 IP 地址直接替换解决。但如果这时,相同的 IP 地址下部署运行着多个域名,那么服务器就会无法理解究竟是哪个域名对应的请求。因此,就需要使用首部字段 Host 来明确指出请求的主机名。若服务器未设定主机名,那直接发送一个空值即可 |
If-Match | 比较实体标记(ETag) | If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求 |
If-Modified-Since | 比较资源的更新时间 | If-Modified-Since,属附带条件之一,它会告知服务器若 If-Modified-Since 字段值早于资源的更新时间,则希望能处理该请求。而在指定 If-Modified-Since 字段值的日期时间之后,如果请求的资源都没有过更新,则返回状304 Not Modified 的响应。If-Modified-Since 用于确认代理或客户端拥有的本地资源的有效性。获取资源的更新日期时间,可通过确认首部字段 Last-Modified 来确定。 |
If-None-Match | 比较实体标记(与 If-Match 相反) | If-None-Match 属于附带条件之一。它和首部字段 If-Match作用相反。用于指定 If-None-Match 字段值的实体标记(ETag)值与请求资源的 ETag 不一致时,它就告知服务器处理该请求。在 GET 或 HEAD 方法中使用首部字段 If-None-Match 可获取最新的资源。因此,这与使用首部字段 If-Modified-Since 时有些类似 |
If-Range | 资源未更新时发送实体 Byte 的范围请求 | If-Range 属于附带条件之一。它告知服务器若指定的 If-Range 字段值(ETag 值或者时间)和请求资源的 ETag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源 |
If-Unmodified-Since | 比较资源的更新时间(与If-Modified-Since相反) | If-Unmodified-Since 和首部字段 If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码 412 Precondition Failed 作为响应返回 |
Max-Forwards | 最大传输逐跳数 | 通过 TRACE 方法或 OPTIONS 方法,发送包含首部字段 Max-Forwards 的请求时,该字段以十进制整数形式指定可经过的服务器最大数目。服务器在往下一个服务器转发请求之前,Max-Forwards 的值减 1 后重新赋值。当服务器接收到 Max-Forwards 值为 0 的请求时,则不再进行转发,而是直接返回响应 |
Proxy-Authorization | 代理服务器要求客户端的认证信息 | 接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段Proxy-Authorization 的请求,以告知服务器认证所需要的信息。这个行为是与客户端和服务器之间的 HTTP 访问认证相类似的,不同之处在于,认证行为发生在客户端与代理之间。客户端与服务器之间的认证,使用首部字段 Authorization 可起到相同作用 |
Range | 实体的字节范围请求 | Range: bytes=5001-10000。对于只需获取部分资源的范围请求,包含首部字段 Range 即可告知服务器资源的指定范围。上面的示例表示请求获取从第 5001 字节至第10000 字节的资源。接收到附带 Range 首部字段请求的服务器,会在处理请求之后返回状态码为 206 Partial Content 的响应。无法处理该范围请求时,则会返回状态码 200 OK 的响应及全部资源 |
Referer | 对请求中 URI 的原始获取方 | 客户端一般都会发送 Referer 首部字段给服务器。但当直接在浏览器的地址栏输入 URI,或出于安全性的考虑时,也可以不发送该首部字段。因为原始资源的 URI 中的查询字符串可能含有 ID 和密码等保密信息,要是写进 Referer 转发给其他服务器,则有可能导致保密信息的泄露 |
User-Agent | HTTP 客户端程序的信息 | User-Agent 会将创建请求的浏览器和用户代理名称等信息传达给服务器。由网络爬虫发起请求时,有可能会在字段内添加爬虫作者的电子邮件地址。此外,如果请求经过代理,那么中间也很可能被添加上代理服务器的名称 |
响应首部字段
响应首部字段是由服务器端向客户端返回响应报文中所使用的字段,用于补充响应的附加信息、服务器信息,以及对客户端的附加要求等信息。
| 首部字段名 | 说明 | 举例 |
| ------------- |:-------------:| |
|Accept-Ranges| 是否接受字节范围请求 |首部字段 Accept-Ranges 是用来告知客户端服务器是否能处理范围请求,以指定获取服务器端某个部分的资源。可指定的字段值有两种,可处理范围请求时指定其为 bytes,反之则指定其为 none。 |
| Age | 推算资源创建经过时间 | Age: 600;首部字段 Age 能告知客端,源服务器在多久前创建了响应。字段值的单位为秒。若创建该响应的服务器是缓存服务器,Age 值是指缓存后的响应再次发起认证到认证完成的时间值。代理创建响应时必须加上首部字段=Age。 |
| ETag | 资源的匹配信息|ETag: "82e22293907ce725faf67773957acd12”。首部字段 ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag值。 另外,当资源更新时,ETag 值也需要更新。生成 ETag 值时,并没有统一的算法规则,而仅仅是由服务器来分配。资源被缓存时,就会被分配唯一性标识。例如,当使用中文版的浏览器访问 http://www.google.com/ 时,就会返回中文版对应的资源,而使用英文版的浏览器访问时,则会返回英文版对应的资源。两者的URI 是相同的,所以仅凭 URI 指定缓存的资源是相当困难的。若在下载过程中出现连接中断、再连接的情况,都会依照 ETag 值来指定资源。强 ETag 值和弱 Tag 值。ETag 中有强 ETag 值和弱 ETag 值之分强 ETag 值。强 ETag 值,不论实体发生多么细微的变化都会改变其值。ETag: "usagi-1234"弱 ETag 值弱 ETag 值只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时,会在字段值最开始处附加 W/ETag: W/"usagi-1234" |
| Location | 令客户端重定向至指定URI| Location: http://www.usagidesign.jp/sample.html。使用首部字段 Location 可以将响应接收方引导至某个与请求 URI 位置不同的资源。基本上,该字段会配合 3xx :Redirection 的响应,提供重定向的URI。几乎所有的浏览器在接收到包含首部字段 Location 的响应后,都会强制性地尝试对已提示的重定向资源的访问。 |
| Proxy-Authenticate| 代理服务器对客户端的认证信息| 首部字段 Proxy-Authenticate 会把由代理服务器所要求的认证信息发送给客户端。它与客户端和服务器之间的 HTTP 访问认证的行为相似,不同之处在于其认证行为是在客户端与代理之间进行的。而客户端与服务器之间进行认证时,首部字段 WWW-Authorization 有着相同的作用。有关HTTP 访问认证,后面的章节会再进行详尽阐述。 |
| Retry-After |对再次发起请求的时机要求| Retry-After 告知客户端应该在多久之后再次发送请求。主要配合状码 503 Service Unavailable 响应,或 3xx Redirect 响应一起使用。字段值可以指定为具体的日期时间(Wed, 04 Jul 2012 06:34:24GMT 等格式),也可以是创建响应后的秒数。 |
| Server|HTTP服务器的安装信息 | Server: Apache/2.2.17 (Unix)。首部字段 Server 告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息。不单单会标出服务器上的软件应用名称,还有可能包括版本号和安装时启用的可选项。Server: Apache/2.2.6 (Unix) PHP/5.2.5|
| Vary|代理服务器缓存的管理信息| 当代理服务器接收到带有 Vary 首部字段指定获取资源的请求时,如果使用的 Accept-Language 字段的值相同,那么就直接从缓存返回响应。反之,则需要先从源服务器端获取资源后才能作为响应返回。首部字段 Vary 可对缓存进行控制。源服务器会向代理服务器传达关于本地缓存使用方法的命令。从代理服务器接收到源服务器返回包含 Vary 指定项的响应之后,若再要进行缓存,仅对请求中含有相同 Vary 指定首部字段的请求返回缓存。即使对相同资源发起请求,但由于 Vary 指定的首部字段不相同,因此必须要从源服务器重新获取资源。|
| WWW-Authenticate| 服务器对客户端的认证信息 | WWWAuthenticate: Basic realm="Usagidesign Auth"首部字段 WWW-Authenticate 用于 HTTP 访问认证。它会告知客户端适用于访问请求 URI 所指定资源的认证方案(Basic 或是 Digest)和带参数提示的质询(challenge)。状态码 401 Unauthorized 响应中,肯定带有首部字段 WWW-Authenticate。|
实体首部字段
实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息。
首部字段名 | 说明 | 举例 |
---|---|---|
Allow | 资源可支持的HTTP方法 | Allow: GET, HEAD。首部字段 Allow 用于通知客户端能够支持 Request-URI 指定资源的所有 HTTP 方法。当服务器接收到不支持的 HTTP 方法时,会以状态码405 Method Not Allowed 作为响应返回。与此同时,还会把所有能支持的 HTTP 方法写入首部字段 Allow 后返回。 |
Content-Encoding | 实体主体适用的编码方式 | Content-Encoding: gzip。首部字段 Content-Encoding 会告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩。 |
Content-Language | 实体主体的自然语言 | 首部字段 Content-Language 会告知客户端,实体主体使用的自然语言(指中文或英文等语言) |
Content-Length | 实体主体的大小(单位:字节) | 首部字段 Content-Length 表明了实体主体部分的大小(单位是字节)。对实体主体进行内容编码传输时,不能再使用 Content-Length首部字段 |
Content-Location | 替代对应资源的URI | Content-Location: http://www.hackr.jp/index-ja.html。首部字段 Content-Location 给出与报文主体部分相对应的 URI。和首部字段 Location 不同,Content-Location 表示的是报文主体返回资源对应的 URI。比如,对于使用首部字段 Accept-Language 的服务器驱动型请求,当返回的页面内容与实际请求的对象不同时,首部字段 Content-Location内会写明 URI。(访问 http://www.hackr.jp/ 返回的对象却是http://www.hackr.jp/index-ja.html 等类似情况) |
Content-MD5 | 实体主体的报文摘要 | 客户端会对接收的报文主体执行相同的 MD5 算法,然后与首部字段 Content-MD5 的字段值比较Content-MD5: OGFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达。对报文主体执行 MD5 算法获得的 128 位二进制数,再通过 Base64 编码后将结果写入 Content-MD5 字段值。由于 HTTP 首部无法记录二进制值,所以要通过 Base64 编码处理。为确保报文的有效性,作为接收方的客户端会对报文主体再执行一次相同的 MD5 算法。计算出的值与字段值作比较后,即可判断出报文主体的准确性。采用这种方法,对内容上的偶发性改变是无从查证的,也无法检测出恶意篡改。其中一个原因在于,内容如果能够被篡改,那么同时意味着 Content-MD5 也可重新计算然后被篡改。所以处在接收阶段的客户端是无法意识到报文主体以及首部字段 Content-MD5 是已经被篡改过的。 |
Content-Range | 实体主体的位置范围 | Content-Range: bytes 5001-10000/10000。针对范围请求,返回响应时使用的首部字段 Content-Range,能告知客户端作为响应返回的实体的哪个部分符合范围请求。字段值以字节为单位,表示当前发送部分及整个实体大小。 |
Content-Type | 实体主体的媒体类型 | Content-Type: text/html; charset=UTF-8。首部字段 Content-Type 说明了实体主体内对象的媒体类型。和首部字段 Accept 一样,字段值用 type/subtype 形式赋值。参数 charset 使用 iso-8859-1 或 euc-jp 等字符集进行赋值。 |
Expires | 实体主体过期的日期时间 | 首部字段 Expires 会将资源失效的日期告知客户端。缓存服务器在接收到含有首部字段 Expires 的响应后,会以缓存来应答请求,在Expires 字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。源服务器不希望缓存服务器对资源缓存时,最好在 Expires 字段内写入与首部字段 Date 相同的时间值。但是,当首部字段 Cache-Control 有指定 max-age 指令时,比起首部字段 Expires,会优先处理 max-age 指令。 |
Last-Modified | 资源的最后修改日期时间 | Last-Modified: Wed, 23 May 2012 09:59:55 GMT。首部字段 Last-Modified 指明资源最终修改的时间。一般来说,这个值就是 Request-URI 指定资源被修改的时间。但类似使用 CGI 脚本进行动态数据处理时,该值有可能会变成数据最终修改时的时间。 |