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 文件,可以明确发送一份 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、预登录会话或其他特定请求头。具体要求应以该服务当前的接口文档为准。
备注:内容仅供参考。
