📘 第四章 返回结果的HTTP状态码
📄 一句话概括

403 是「知道你是谁,但你没这个权限」。重新登录没用,除非换个账号。

📝 本节和前面几节的关系

上一节 401 是没认证,这一节 403 是没授权。 这一对是权限系统里最容易混的两个码,也是排查方向的分水岭。

一、认证与授权是两步

认证(authentication)回答「你是谁」——密码、token、证书。 授权(authorization)回答「你能干什么」——角色、权限、ACL。 401 是第一步没过,403 是第二步没过。所以处理方式完全不同:401 去补凭据,403 去改权限表。 Demo 里三行很能说明问题:未登录访问 /admin 回 403(不是 401!),普通用户回 403,管理员回 200。 这个系统把「没登录」也当成了 403,因为它的判定逻辑是「你有没有 admin 角色」, 而不是「你有没有登录」。

二、为什么很多系统故意回 403 或 404

安全上有一条惯例:不要告诉攻击者「这个资源存在但你不能看」, 因为那本身就泄露了信息(存在性探测)。 所以有两种做法:把无权限一律当 403(承认存在),或者一律当 404(假装不存在)。 GitHub 对私有仓库就是回 404。 这两种都合理,取决于你的威胁模型。 但同一个系统里必须统一,不能一会儿 403 一会儿 404,那样攻击者反而能从差异里推断出东西。

三、403 的响应里别解释太多

「你没有 admin 角色,请联系管理员开通」——这句话对人友好,对攻击者也友好:它确认了 /admin 存在、 确认了它是靠角色控制、甚至还告诉了他该去找谁。 正确做法:前端给友好提示,后端日志里记详细原因,响应正文保持中性。 这是一个典型的「可用性与安全性折中」,取舍点在日志。 另外注意:403 通常不该带 WWW-Authenticate,因为它不是认证问题。 带了会让客户端误以为需要重新认证。

四、动手 Demo:三种身份访问同一个地址

服务端按 X-User 首部判断身份,对 /admin 要求必须是 admin。 分别用「无身份」「普通用户」「管理员」试三次。

if path == u'/admin' and user != u'admin':
    return (u'HTTP/1.1 403 Forbidden',
            [(u'Content-Type', u'text/plain')], b'no')
return (u'HTTP/1.1 200 OK', [(u'Content-Type', u'text/plain')], b'yes')

实跑输出:

--------------------------------------------------------------------
403 Forbidden:知道你是谁,就是不给你看
--------------------------------------------------------------------
  未登录访问 /admin                HTTP/1.1 403 Forbidden
  已登录普通用户访问 /admin        HTTP/1.1 403 Forbidden
  管理员访问 /admin                HTTP/1.1 200 OK

  401 的含义                 **未认证**:你还没说你是谁,去带上凭据再来
  403 的含义                 **未授权**:你是谁我知道了,但你没这个权限
  重新登录有用吗             401 有用;403 没用,除非换个账号
  安全要点                   403 的响应里别放「为什么不行」,否则就是信息泄露
  这个区别在排查时决定方向:
  看到 401 去查 token 有没有带上、有没有过期;
  看到 403 去查角色、权限表、IP 白名单。

三行依次是 403、403、200——未登录和普通用户拿到的是同一个码。 这说明这个系统的判定只看「有没有 admin」,不看「有没有登录」。 这是刻意设计还是疏漏?取决于系统。 但对排查的人来说,看到 403 时不能假定已经登录了——先去确认 token 到底有没有生效。 安全要点 403 的响应里别放「为什么不行」,否则就是信息泄露——这一句值得贴在代码评审的检查表里。

30 秒实验

  1. 把「未登录」也改成回 401 加 WWW-Authenticate,想想客户端行为会怎么变。
  2. 把 /admin 的 403 改成 404,看外部能不能探测出这个路径存在。
  3. 想一想:CDN 的防盗链失败该回 403 还是 404?(多数回 403)

常见误区

  1. 「403 就是没登录」——没登录是 401。403 是登录了但没权限。
  2. 「403 重试几次会好」——不会,除非权限变了或换了账号。
  3. 「403 要带 WWW-Authenticate」——不该带,那不是认证问题。
自测三问(点开对答案) 1. 认证与授权分别回答什么问题? —— 认证回答「你是谁」,授权回答「你能干什么」。 2. 为什么有的系统把无权限回成 404? —— 为了不泄露「这个资源存在」这一信息,防止存在性探测。 3. 403 响应里为什么不该写详细原因? —— 会泄露资源存在性、权限模型、联系渠道等信息。

403 是「有但你不能看」。下一节看「根本不存在」的那个码。

相关笔记