认证回答「你是谁」,授权回答「你能干什么」。 两件事常常连着做,但判断是分开的:认对了人,也可能什么都不许他做。
第六、七章讲的是报文和传输的安全。 从这一章开始换角度:怎么确认对面那个人是谁——这是应用层自己要做的事。
一、三种要素
认证凭据按性质分三类:知识(密码、PIN)、持有(手机、U 盾、证书)、特征(指纹、 人脸)。Demo 只用了第一类,最常见也最弱。 两类的组合叫双因素;两类必须是不同性质的才算。「密码 + 密保问题」不算双因素,两个都是知识。 这一点在 8.4.2 会用实测再讲一次:证书(持有)加密码(知识)才是真正的两把锁。
二、认证与授权要分开
Demo 里五组请求,第 2 行最能说明问题:guest 认证通过了,但访问 /admin 回 403 Forbidden。
403 的含义是「我知道你是谁,但你不能进」。
它和 401 的区别不是程度,是性质:401 是「我不知道你是谁」,403 是「知道,但不给」。
把这两件事混在一起是很多越权漏洞的根源。
典型症状是「只在页面上隐藏了按钮,接口没做检查」——攻击者直接调接口,认证通过、授权缺失,
照样拿到数据。
三、别泄露「谁存在」
Demo 第 5 行:账号根本不存在,服务端回的还是 401,和密码错一模一样。这是故意的。 如果「账号不存在」单独给一个提示,攻击者就能拿一份常见用户名列表逐个试, 把哪些账号真实存在全部筛出来。这叫用户名枚举,是撞库攻击的第一步。 同理,登录失败提示统一写「账号或密码错误」, 注册和找回密码接口也要注意——「该邮箱已注册」这句话本身就泄露了信息。
四、动手 Demo:五种请求,五条不同的路
一个极简的 BASIC 认证服务端,带两个账号(管理员和读者)。 分别用「有权限」「没权限」「密码错」「账号不存在」四种身份去访问两个路径,看状态码怎么区分。
USERS = {u'bozai': u'pw-bozai', u'guest': u'pw-guest'}
ROLES = {u'bozai': u'admin', u'guest': u'reader'}
if not auth.startswith(u'Basic '):
return 401 + WWW-Authenticate # 我不知道你是谁
if USERS.get(name) != pw:
return 401 + WWW-Authenticate # 密码错 / 账号不存在,同一个回应
if path == u'/admin' and ROLES.get(name) != u'admin':
return 403 # 知道你是谁,但不给
return 200
实跑输出:
--------------------------------------------------------------------
认证回答「你是谁」,授权回答「你能干什么」
--------------------------------------------------------------------
三种要素,本 Demo 只用了第一种(知识):
知识 密码、口令、PIN ← 本 Demo
持有 手机、U 盾、客户端证书
特征 指纹、人脸、虹膜
账号 路径 状态 含义
bozai /admin HTTP/1.1 200 OK 认证过 + 有权限
guest /admin HTTP/1.1 403 Forbidden 认证过 + 没权限
guest /me HTTP/1.1 200 OK 认证过 + 普通页
bozai /me HTTP/1.1 401 Unauthorized 密码错
nobody /me HTTP/1.1 401 Unauthorized 账号不存在(但回的是同一个 401)
第 2 行和第 5 行最值得看。
第 2 行:**认证通过,授权失败**,回 403。这是两个独立的判断,
别把「登录了」当成「什么都能做」。
第 5 行:账号不存在时也回 401,和密码错一模一样。
这是故意的——如果「账号不存在」有单独提示,攻击者就能用它枚举出
哪些账号是真实存在的。这叫用户名枚举。
bozai 访问 /admin 得 200;guest 访问同一个 /admin 得 403。
同一处资源,两个已认证用户,结果不同——这就是授权。
guest 访问 /me 得 200:认证够了,路径也不要求管理员,所以放行。
密码错得 401,账号不存在还是 401。两行输出一模一样,这是有意的设计,不是偷懒。
五种请求只用了「知识」这一类凭据。三类要素的分工在 8.4.2 会用真证书再演示一遍。
30 秒实验
- 把账号不存在的分支改成一个带提示的 401,想想攻击者能从中拿到什么。
- 给
guest加上 admin 角色,看那两行结果会不会反过来。 - 想一想:手机验证码属于哪一类要素?为什么它常被当成第二因素?
常见误区
- 「登录了就有权限」——认证和授权是两次判断。
- 「401 和 403 只是程度不同」——一个是没认出来,一个是认出来了但不给。
- 「提示越详细越友好」——在登录接口上,详细提示等于泄露账号是否存在。
自测三问(点开对答案)
1. 认证和授权的区别是什么? —— 认证确认身份,授权决定这个身份能做什么。 2. 401 和 403 分别是什么含义? —— 401 是未认证(不知道你是谁),403 是已认证但无权限。 3. 为什么「账号不存在」不该单独提示? —— 否则可以被用来枚举出哪些账号真实存在。认证的概念清楚了。接下来按历史顺序看四种具体做法,第一个是 BASIC。
- ☐ (本节完,下一节 8.2 BASIC认证)