HTTP Agent using Host header for SNI server_name
还没有人认领这个 Issue。
- 主要语言
- JavaScript
- 星标
- 122k
- 派生
- 37.4k
- 平均合并
- 4 天 3 小时
- 30 天内合并 PR
- 272
描述
- Version: v14.15.1`
- Platform: Darwin C02DFH5SMD6M 19.6.0 Darwin Kernel Version 19.6.0: Tue Nov 10 00:10:30 PST 2020; root:xnu-6153.141.10~1/RELEASE_X86_64 x86_64
- Subsystem: http
What steps will reproduce the bug?
I'm not 100% sure that this is a bug, but it was surprising behavior that is different from any other http clients I've looked at (curl, python's httplib, nginx).
If you make an HTTPS request specifying a host header that is different from the request host, the servername used for SNI will be set to the value of the host header, unless the host header contains an IP address or you explicitly pass a servername in the agent options.
https://github.com/nodejs/node/blob/b0c0111b04201bf99fde0fe0616b9fdf1f33655d/lib/http.js#L1086-L1092
What is the expected behavior?
This was very surprising to me as the host header is part of the HTTP layer, and the servername belongs to the TLS layer, and I have never seen a client behave this way. I would have expected the host (not the host header) to be used as the default servername.
For example using curl:
$ curl -vvI https://www.google.com -H "Host: https://not-google.com"
* Trying 172.217.21.164...
* TCP_NODELAY set
* Connected to www.google.com (172.217.21.164) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-ECDSA-CHACHA20-POLY1305
* ALPN, server accepted to use h2
* Server certificate:
* subject: C=US; ST=California; L=Mountain View; O=Google LLC; CN=www.google.com
* start date: Jan 5 12:13:00 2021 GMT
* expire date: Mar 30 12:12:59 2021 GMT
* subjectAltName: host "www.google.com" matched cert's "www.google.com"
* issuer: C=US; O=Google Trust Services; CN=GTS CA 1O1
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fecd500f600)
> HEAD / HTTP/2
> Host: https://not-google.com
> User-Agent: curl/7.64.1
> Accept: */*
>
As you can see, the certificate is accepted:
subjectAltName: host "www.google.com" matched cert's "www.google.com"
If we do the same thing in Node, the certificate will be rejected as the certificate host name does not match the server name that we send:
const https = require('https');
const options = {
headers: {
host: 'https://not-google.com'
}
};
https.get('https://google.com', options, (res) => {}).on('error', console.error);
This will result in [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames.
Changing this so that the host is used as the default servername instead of the host header is a small and simple change, but my question would be if this is done intentionally, and if so, why?
Additional information
- I was not able to find any reference in the git history of why this decision was made - only that it was made back in 2012.
- Having a mismatched servername and host header is domain fronting, but it doesn't seem like something the HTTP client should be responsible for preventing. And the current design still allows for it by just setting the servername yourself.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
首先检查 lib/http.js 中 1086-1092 行附近的代码,并使用与请求主机不同的 Host 标头重现 HTTPS 请求。将得到的 SNI 和证书验证结果与预期行为进行比较,然后添加回归测试,表明默认情况下使用请求主机,同时仍会遵循显式提供的 servername。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- javascript, node.js
- 领域
- networking
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 52/100