126

基于node.js的HTTP/2客户端/服务器连接实验及RawCap抓包分析

 6 years ago
source link: https://zhuanlan.zhihu.com/p/30743038?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

基于node.js的HTTP/2客户端/服务器连接实验及RawCap抓包分析

知乎浅知识分享

最近,我在Windows 7 PC上,用Chrome 62浏览器打开知乎首页(https://www.zhihu.com),发现知乎竟然是基于HTTP/2的。之前一直以为只有Google、Facebook才支持HTTP/2,没想到它竟然这么快流入寻常百姓家了。

这篇小短文介绍一下在Windows 7上用node.js构建HTTP/2客户端及服务器,并采用RawCap抓包,用Wireshark解码分析,观察HTTP/2的流量特征。

1.安装Chocolatey

choco是Windows上的基于命令行的软件包管理工具,类似于Linux上的yum、apt-get。因为后续需要用到OpenSSL,而通过choco安装OpenSSL(Windows版)很方便,所以这里先安装choco。{choco官网地址:Chocolatey - The package manager for Windows - https://chocolatey.org/ }

v2-c82846a09e9b98737470128ec6a23067_720w.jpg

2.安装OpenSSL (for Windows)

OpenSSL是一个SSL/TLS开发库及工具集,后续需要用OpenSSL工具生成自签CA证书和网站证书及私钥,所以这里先安装OpenSSL。

choco提供了OpenSSL for Windows版本,用 choco install openssl.light 即可安装。安装路径默认为 C:\Program Files\OpenSSL\ ,需要手工将这个路径追加到PATH环境变量中。

3.安装RawCap

RawCap是Windows上的抓包工具,支持对localhost(127.0.0.1)接口抓包。Wireshark/Winpcap不支持对localhost抓包,所以这里先安装RawCap。RawCap也支持用choco安装;也可以从官网下载。{RawCap官网:http://www.netresec.com/?page=RawCap}

4.用OpenSSL生成证书和私钥

通过openssl工具生成证书和私钥。

openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -keyout localhost-privkey.pem -out localhost-cert.pem

openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -keyout localhost-privkey.pem -out localhost-cert.pem
Generating a 2048 bit RSA private key
...........................+++
........................................................+++
writing new private key to 'localhost-privkey.pem'

5.node.js HTTP/2服务器程序

编写并运行HTTP/2服务器程序。

const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer ({
   key: fs.readFileSync('localhost-privkey.pem'),
   cert: fs.readFileSync('localhost-cert.pem')
});
server.on('error', (err) => console.error(err));
server.on('socketError', (err) => console.error(err));
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'text/html',
':status': 200
   });
stream.end('<h1>Hello HTTP/2</h1');
});
server.listen(443);

注意:node.js给出提示,至今(v8.9.0)为止,http2仍为实验版本,相关API并不稳定。

6.RawCap对localhost抓包

运行rawcap对localhost (127.0.0.1) 抓包。

7.node.js HTTP/2客户端程序

编写并运行HTTP/2客户端程序。运行完成后,停止RawCap抓包。

const http2 = require('http2');
const fs = require('fs');
const client = http2.connect('https://localhost:443', {
   ca: fs.readFileSync('localhost-cert.pem')
});
client.on('socketError', (err) => console.error(err));
client.on('error', (err) => console.error(err));
const req = client.request({':path': '/'});
req.on('response', (headers, flags) => {
for (const name in headers) {
console.log (`${name}: ${headers[name]}`);
   }
});
req.setEncoding('utf-8');
let data = '';
req.on('data', (chunk) => {data += chunk;});
req.on('end', () => {
console.log (`\n${data}`);
client.destroy();
});
req.end();

注意:node.js给出提示,至今(v8.9.0)为止,http2仍为实验版本,相关API并不稳定。

8.观察ClientHello的ALPN

打开RawCap抓包文件,观察客户端发出的ClientHello,其中ALPN扩展为h2,表示应用层为HTTP/2协议。符合预期,OK。

9.观察ServerHello的ALPN

观察服务器发回的ServerHello,其中ALPN扩展为h2,表示应用层为HTTP/2协议。符合预期,OK。

10.总结

可以看到node.js内置http2模块使用起来非常简单方便,因为HTTP/2 RFC推荐基于TLS以确保传输安全,因此http2模块的用法与tls模块的用法几乎无异。在TLS协议ClientHello中ALPN为h2指示应用层协议为HTTP/2,以供服务端接收时选用正确的HTTP/2协议栈,同时ServerHello中ALPN为h2以指示服务端支持HTTP/2,后续应用层可以传输HTTP/2数据。

Reference:

0. 老宋的独家号

1. http2 | Node.js API 文档

2. Hypertext Transfer Protocol Version 2 (HTTP/2)

注:本文为老宋原创文章,欢迎随意转载,有任何疑问前请至【知乎专栏-老宋的独家号】评论区讨论交流。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK