Proxy-Authorization 是客户端向代理出示凭据,对应状态码是 407,不是 401。
它是逐跳字段,代理必须吃掉,绝不能转发给源服务器。
6.4.5 讲的是给源服务器的凭据,这一节是给代理的。两个字段一字之差,目标完全不同。
一、两套凭据,两套状态码
| 对比项 | 源服务器认证 | 代理认证 |
|---|---|---|
| 请求首部 | Authorization |
Proxy-Authorization |
| 响应首部 | WWW-Authenticate |
Proxy-Authenticate |
| 状态码 | 401 | 407 |
| 作用范围 | 端到端,一路传到底 | 逐跳,转发时必须删 |
| 分开的理由很实际:代理和源服务器是两个不同的信任域。 | ||
| 公司的出口代理要你出示公司账号,源服务器要你出示网站账号,这两者不该混在一起。 | ||
| 所以代理链上每一跳可以各要各的凭据,客户端要为每一跳分别出示——这也是为什么它必须是逐跳字段。 |
二、实测:凭据到不了源服务器
Demo 里代理校验 bozai:proxy-pass 的 base64。
第一次不带凭据,回 407 加 Proxy-Authenticate: Basic realm="CorpProxy",
源服务器一次都没被访问。
第二次带上凭据,回 200,源服务器被访问 1 次。
但源服务器收到的首部只有 Host 和 X-Forwarded-For 两个——Proxy-Authorization 不在里面。
那一行「里面有 Proxy-Authorization 吗:没有,被代理吃掉了」,就是逐跳字段的实际效果。
如果不删,等于把代理密码送给了源服务器。
三、一个容易搞错的地方
很多人以为 407 也是「未授权」,于是把它当成 401 处理——让用户去登录网站账号。
这是错的:407 是代理要你认证。
浏览器看到 407 会弹一个独立的代理认证框,凭据存在操作系统的代理设置里,跟网站登录完全是两套。
在抓包里区分也很简单:看有没有 Proxy- 前缀,看状态码是 401 还是 407。
如果看到 407 出现在业务日志里,说明中间有一层需要认证的代理,而你的客户端没配凭据。
四、动手 Demo:407 之后补上凭据
起一个要认证的代理和一个正常源服务器。先不带凭据请求一次,看 407 和代理要求; 再带上 base64 凭据请求一次,并检查源服务器到底收到了哪些首部。
auth = hd.get(u'proxy-authorization', u'')
if auth != u'Basic ' + GOOD:
return reply(u'HTTP/1.1 407 Proxy Authentication Required',
[(u'Proxy-Authenticate', u'Basic realm="CorpProxy"')],
b'need proxy auth')
keep = [(u'X-Forwarded-For', u'203.0.113.9')]
# 注意:凭据不转发,只带 Host 和 X-Forwarded-For
return ask(o_port, req(u'GET', path, u'up', keep, hdr_host=u'www.example.com'))
实跑输出:
--------------------------------------------------------------------
Proxy-Authorization:向代理出示凭据
--------------------------------------------------------------------
第一轮:不带凭据
状态 HTTP/1.1 407 Proxy Authentication Required
代理要求 Proxy-Authenticate: Basic realm="CorpProxy"
正文 先给代理凭据
源服务器被访问 0 次
第二轮:带上 Base64 凭据
状态 HTTP/1.1 200 OK
正文 这是源服务器的内容
源服务器被访问 1 次
源服务器收到的首部 Host | X-Forwarded-For
里面有 Proxy-Authorization 吗 没有,被代理吃掉了
407 出现次数 1 次
凭据字节数 24(Base64 后)
它和 `Authorization` 是一对,但目标完全不同:
`Authorization` 是给**源服务器**看的,
`Proxy-Authorization` 是给**代理**看的。
所以它是逐跳字段,代理必须吃掉,绝不能转发给源服务器——
输出里那一行「没有」就是这个意思。
状态码也分开了:代理要认证回 **407**,源服务器要认证回 401。
代理链上每一跳可以各要各的凭据,客户端要为每一跳分别出示。
第一轮不带凭据:407,代理要求 Basic realm="CorpProxy",正文「先给代理凭据」,
源服务器被访问 0 次。
第二轮带上凭据:200,正文「这是源服务器的内容」,源服务器被访问 1 次。
源服务器收到的首部只有 Host 和 X-Forwarded-For。
Proxy-Authorization 被代理吃掉了——这就是逐跳。
407 一共出现 1 次,凭据 base64 之后 24 字节。
这 24 字节只对这一个代理有效,换一个代理还得另给一份。
30 秒实验
- 让代理把
Proxy-Authorization原样转发出去,看源服务器会收到什么。 - 串两个都要求认证的代理,看客户端该怎么给两份不同的凭据。
- 想一想:为什么 407 的凭据不该被浏览器存在网站 Cookie 里?
常见误区
- 「
Proxy-Authorization和Authorization是一回事」——目标对象不同。 - 「代理认证失败回 401」——回 407。
- 「这个字段会一路传到源服务器」——是逐跳字段,必须被代理删掉。
自测三问(点开对答案)
1. 代理要认证时回什么状态码、配什么首部? —— 407 Proxy Authentication Required,配 `Proxy-Authenticate`。 2. 为什么 `Proxy-Authorization` 必须被代理删掉? —— 它是给代理的凭据,转发出去等于把代理账号密码泄露给源服务器。 3. 代理链上有两层都要认证怎么办? —— 客户端为每一跳分别出示凭据——这正是它必须是逐跳字段的原因。认证讲完了。下一个字段是下载功能的基础:只取一部分。
- ☐ (本节完,下一节 6.4.16 Range)