PAYATHON 2026

curl 登录 API 返回 HTTP/1.1 403 的原因是什么?

数据小陈

结论

Mark bundle as not supporting multiuse 与 HTTP/1.1 403 无关。这只是 curl 的调试信息,表示当前 HTTP/1.1 连接不支持多路复用,并非请求失败的原因。--http0.9 也无法解决这个问题。

服务端拒绝登录请求,很可能是因为 CSRF/XSRF 校验失败。请求中出现了两个 Cookie 头,第二个头发送的还是空值:

Cookie: XSRF-TOKEN=[my XSRF-TOKEN]
Cookie: XSRF-TOKEN=

原命令中的 Cookie 写法也有问题,等号后多了一个空格:

-H "Cookie: XSRF-TOKEN= $TOKEN"

正确写法是:

-H "Cookie: XSRF-TOKEN=$TOKEN"

不过,既然已经通过 -b cookie.txt 让 curl 从 Cookie 文件中读取并发送 Cookie,通常就不需要再手工添加 Cookie 头。

为什么会返回 403

TLS 握手已经成功,服务器也正常收到了 POST /auth/login 请求,所以问题不在 TLS 版本、HTTP 协议版本或 curl 功能上。

实际发出的请求头是:

> Cookie: XSRF-TOKEN=[my XSRF-TOKEN]
> X-XSRF-TOKEN: [token]
> Cookie: XSRF-TOKEN=

也就是说,请求中同时包含:

  • 从 cookie.txt 加载的 XSRF-TOKEN
  • 手工添加的另一个 Cookie 头
  • 一个值为空或因格式错误而未按预期展开的 Cookie

采用双提交 Cookie 防护的服务通常要求:

Cookie 中的 XSRF-TOKEN == X-XSRF-TOKEN 请求头中的值

只要 Cookie 缺失、重复、为空,或者两处 token 不一致,服务器就可能返回 403 Forbidden。响应中的以下内容也表明问题可能出在 CSRF token 的获取或校验上:

x-csrf-token: Fetch

推荐的请求流程

先访问能够下发 XSRF Cookie 的端点,并保存 Cookie:

curl -k --tlsv1.2 \
  -c cookie.txt \
  -b cookie.txt \
  'https://api-gateway.inpi.fr/'

具体应该访问哪个初始化端点,需要查看该 API 的登录教程或当前接口文档。响应中应包含类似内容:

Set-Cookie: XSRF-TOKEN=...

接着,从 Netscape 格式的 Cookie 文件中读取 token:

TOKEN=$(awk '$6 == "XSRF-TOKEN" {print $7}' cookie.txt | tail -n 1)

确认变量不为空:

test -n "$TOKEN" || {
  echo "未从 cookie.txt 获取到 XSRF-TOKEN" >&2
  exit 1
}

最后发送登录请求。Cookie 交给 -b cookie.txt 处理,只在请求头中手工发送对应的 XSRF token:

ID1=$(curl -k --tlsv1.2 \
  -b cookie.txt \
  -c cookie.txt \
  'https://api-gateway.inpi.fr/auth/login' \
  -H 'Accept: application/json, text/plain, */*' \
  -H "X-XSRF-TOKEN: $TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"username":"[email address]","password":"[account password]","rememberMe":true}')

不要再添加:

-H "Cookie: XSRF-TOKEN=$TOKEN"

curl 已经通过 -b cookie.txt 发送了 Cookie。

如果不使用 Cookie 文件,可以明确发送一份 Cookie:

curl -k --tlsv1.2 \
  'https://api-gateway.inpi.fr/auth/login' \
  -H 'Accept: application/json, text/plain, */*' \
  -H 'Content-Type: application/json' \
  -H "X-XSRF-TOKEN: $TOKEN" \
  -H "Cookie: XSRF-TOKEN=$TOKEN" \
  --data '{"username":"[email address]","password":"[account password]","rememberMe":true}'

此时需要确认:

  • TOKEN 已正确赋值;
  • 等号后没有多余空格;
  • Cookie 和请求头中的 token 完全一致;
  • token 没有过期;
  • token 来自同一个会话;
  • 如果服务对 token 做了 URL 编码,应保留 Cookie 中的原始值,除非接口文档明确要求解码。

可以先检查变量:

printf 'TOKEN=<%s>\n' "$TOKEN"

如果输出是:

TOKEN=<>

说明变量为空。此时应先修正 token 的获取步骤,而不是继续调整 HTTP 版本。

调试时的注意事项

下面的信息只说明服务器选择了 HTTP/1.1:

* ALPN, server accepted to use http/1.1
* Mark bundle as not supporting multiuse

HTTP/1.1 不具备 HTTP/2 的流多路复用能力,这是正常现象,不会导致服务器返回 403。

--http0.9 用于允许处理非常老旧的 HTTP/0.9 响应。当前服务器明确返回 HTTP/1.1 响应,因此不应使用这个选项。

另外:

  • Connection: keep-alive 通常不需要手工添加,curl 会自行管理连接。
  • -k 会跳过证书验证,只适合在明确了解风险的测试场景中使用。生产环境应修复本机 CA 信任链。
  • -v 会输出 Cookie、token 等敏感信息,分享日志前必须脱敏。
  • 使用 export ID1=\…`虽然可行,但ID1=$(…)` 更清晰,也更容易嵌套。
  • 命令替换只会捕获响应正文。-v 的调试信息写入标准错误,不会进入 ID1。
  • 如果修正 Cookie 后仍然返回 403,还需要检查响应正文,并确认接口是否要求 Origin、Referer、预登录会话或其他特定请求头。具体要求应以该服务当前的接口文档为准。

备注:内容仅供参考。