cURL跨源Cookie泄漏与注入风险解析:自定义Host头的安全隐患

4 阅读3分钟

报告 #3516878 - 使用自定义Host头时的跨源Cookie泄漏与注入风险 | HackerOne

时间线

  • 16 小时前:ichise 向 cURL 提交了一份报告。

摘要

当指定自定义主机名时,如果该传输的Cookie引擎也已启用,则该主机名将用于Cookie匹配。即使在跨源重定向中,原始提供的主机名已被移除,这种匹配行为依然持续。

技术细节

Cookiehost的设置

cookiehost 从自定义的Host头中设置: lib/http.c 文件中的 http_set_aptr_host 函数:

ptr = Curl_checkheaders(data, STRCONST("Host"));
if(ptr && (!data->state.this_is_a_follow || curl_strequal(data->state.first_host, conn->host.name))) {
    /* 如果我们有一个给定的自定义 Host: 头,我们会提取主机名,
       以便稍后可能用于Cookie相关的操作。只有在这不是重定向的情况下,我们才允许自定义 Host: 头,
       因为在重定向请求中设置 Host: 是非常危险的操作。除非主机名与第一个相同! */
    char *cookiehost;
    CURLcode result = copy_custom_value(ptr, &cookiehost);
    ...
    aptr->cookiehost = cookiehost;
}

Cookiehost的使用

cookiehost 同时用于发送Cookie和处理Set-Cookie

lib/http.c 文件的 http_header_s 函数中:

v = (data->cookies && data->state.cookie_engine) ? HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
...
/* 如果存在自定义设置的 Host: 名称,则在此处使用它,否则使用真实的对方主机名。 */
const char *host = data->state.aptr.cookiehost ?
  data->state.aptr.cookiehost : conn->host.name;
...
result = Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
                         data->state.up.path, secure_context);

lib/http.c 文件的 http_cookies 函数中:

const char *host = data->state.aptr.cookiehost ?
  data->state.aptr.cookiehost : data->conn->host.name;
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
result = Curl_cookie_getlist(data, data->conn, &okay, host, &list);

问题根源:由于 cookiehost 在重定向时未被清除,此行为会在跨源重定向中持续存在。

官方文档说明

libcurl 关于 CURLOPT_HTTPHEADER 的文档[1]提到:

指定的主机名用于Cookie匹配,如果此传输的Cookie引擎也已启用...

没有明确警告此行为也适用于跨源重定向。

受影响版本

测试于 cURL 8.18.0。

复现步骤

user@pc:~$ curl -v -L -c cookies.txt -H "Host: example.com" --resolve b.com:8001:127.0.0.1 --resolve a.com:8000:127.0.0.1 a.com:8000
* 添加 b.com:8001:127.0.0.1 到 DNS 缓存
* 添加 a.com:8000:127.0.0.1 到 DNS 缓存
* 在 DNS 缓存中找到主机名 a.com
*   正在尝试 127.0.0.1:8000...
* 已建立连接到 a.com (127.0.0.1 端口 8000),源地址 127.0.0.1 端口 56874
* 使用 HTTP/1.x
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.18.0
> Accept: */*
>
* 请求已完全发送
* HTTP 1.0,假设在正文后关闭连接
< HTTP/1.0 302 Found
< Server: BaseHTTP/0.6 Python/3.12.3
< Date: Mon, 19 Jan 2026 12:35:05 GMT
< Location: http://b.com:8001/
* 为域 example.com、路径 /、过期时间 0 添加 Cookie ccc="secret"
< Set-Cookie: ccc=secret; Path=/
< Content-Length: 0
<
* 正在关闭连接 #0
* 清除认证信息,从端口 8000 重定向到 8001
* 向此 URL 发出另一个请求:'http://b.com:8001/'
* 在 DNS 缓存中找到主机名 b.com
*   正在尝试 127.0.0.1:8001...
* 已建立连接到 b.com (127.0.0.1 端口 8001),源地址 127.0.0.1 端口 43966
* 使用 HTTP/1.x
> GET / HTTP/1.0
> Host: b.com:8001
> User-Agent: curl/8.18.0
> Accept: */*
> Cookie: ccc=secret
>
* 请求已完全发送
* HTTP 1.0,假设在正文后关闭连接
< HTTP/1.0 302 Found
< Server: BaseHTTP/0.6 Python/3.12.3
< Date: Mon, 19 Jan 2026 12:35:05 GMT
* 为域 example.com、路径 /、过期时间 0 添加 Cookie bbb="test"
< Set-Cookie: bbb=test; Path=/
< Location: http://a.com:8000/check
< Content-Length: 0
<
* 正在关闭连接 #1
* 清除认证信息,从端口 8001 重定向到 8000
* 向此 URL 发出另一个请求:'http://a.com:8000/check'
* 在 DNS 缓存中找到主机名 a.com
*   正在尝试 127.0.0.1:8000...
* 已建立连接到 a.com (127.0.0.1 端口 8000),源地址 127.0.0.1 端口 56882
* 使用 HTTP/1.x
> GET /check HTTP/1.0
> Host: example.com
> User-Agent: curl/8.18.0
> Accept: */*
> Cookie: bbb=test; ccc=secret
>
* 请求已完全发送
* HTTP 1.0,假设在正文后关闭连接
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.12.3
< Date: Mon, 19 Jan 2026 12:35:05 GMT
< Content-Length: 0
<
* 正在关闭连接 #2

查看生成的Cookie文件:

user@pc:~$ cat cookies.txt
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# 此文件由 libcurl 生成!请自行承担编辑风险。

example.com	FALSE	/	FALSE	0	bbb	test
example.com	FALSE	/	FALSE	0	ccc	secret

参考文献

[1] curl.se/libcurl/c/C…

影响

跨源Cookie泄漏和注入风险。

项目方回复

  • 15 小时前bagder (cURL 员工) 发表评论:"这是预期的行为。"
  • 13 小时前bagder 关闭了报告并将状态更改为"不适用",并补充道:"欢迎建议改进文档的措辞以使其更清晰,但我们确实尝试记录这一点,并且任何实际尝试和测试此功能的应用程序都会看到它。这不是一个安全问题。"
  • 13 小时前bagder 请求公开此报告:"根据项目的透明度政策,我们希望所有报告都被公开。"
  • 4 小时前bagder 公开了此报告。

报告信息

  • 报告时间:2026年1月19日,下午6:46 (UTC)
  • 报告者:ichise
  • 报告对象:curl
  • 报告 ID:#3516878
  • 严重等级:未评级 (---)
  • 公开时间:2026年1月20日,上午6:48 (UTC)
  • 弱点:凭证保护不足
  • CVE ID:无
  • 赏金:无FINISHED biOK/hzhVF2yKaGc5mK8oeejIYuUYW8I3RsXQCFCiXX2FBas+esuFymsr4+a87Du