Web 认证与浏览器安全边界
用信任链把 HTTP 语义、浏览器凭证、Authentication、Session/Token 生命周期、Authorization、CORS/CSRF/XSS 与安全响应头分层,避免把登录、JWT、Cookie 与浏览器安全混成一个问题。
[!info] related notes
- 所属 MOC: 安全 MOC, HTTP 与前端网络请求 MOC
- 凭证关系: Cookie、Session、Token 与 JWT 的关系
- 架构选择: Stateful、Stateless 与 Hybrid 认证架构
- Session: Server-side Session 鉴权
- Token: Access Token, Refresh Token, JWT
- Password: Password Policy, Password Storage & Verification
- 在线攻击: Credential Stuffing / Spraying / Brute Force
- 在线防御: Authentication Throttling & Account Lockout, Password 与 MFA 的安全边界
- Recovery: Password Reset & Account Recovery, Credential Change & Session Revocation
- Session Trust: Active Sessions & Device Management, Trusted Device & Remember MFA, Reauthentication Freshness
- Risk / History: Risk-Based Authentication, Authentication Security Events & Login History
- 浏览器边界: Same-Origin, CORS, CSRF, XSS
- 安全头: CSP, X-Frame-Options
- API 契约: API 认证与安全, 稳定 API 错误模型
Web 认证与浏览器安全边界
一张总图
一个 Web 请求要经过的不是“Token 对不对”这一关,而是多层信任链:
HTTP method / request contract
↓
browser transport / cookie / origin rules
↓
credential validation
↓
Authentication principal
↓
session / token lifecycle authority
↓
Authorization
↓
resource ownership / policy
↓
application action
↓
browser-side rendering / security policy
不同层回答不同问题。
1. HTTP 层:请求想做什么
HTTP method 先表达操作语义。GET 属于 safe + idempotent;POST 默认不保证幂等。
这一层决定哪些操作适合自动 retry、哪些操作需要 idempotency key,以及 crawler / prefetcher 是否可能安全访问。
它与“当前用户是谁”是不同问题。详见 HTTP 方法语义 与 GET vs POST。
2. Browser Transport:浏览器怎样携带凭证
浏览器可能通过 Cookie 自动携带,或由 JavaScript 设置 Authorization Header,也可能通过 WebAuthn / Passkey 等浏览器 API 完成认证交互。
Cookie 是浏览器存储/发送机制,不等于 Session。详见 Cookie、Session、Token 与 JWT 的关系。
3. Same-Origin / CORS:脚本能否跨源读取
Same-Origin Policy
→ 默认隔离跨源脚本能力
CORS
→ 服务器声明哪些跨源脚本可以读取 HTTP response
CORS 不回答用户是谁、是否有权限,也不等于 CSRF 防御。详见 CORS。
4. Authentication:这个请求代表谁
Authentication 的输出应是可信 principal:
credential
→ validate
→ authenticated principal
例如 user_id、tenant_id、session_id、scopes。
后续业务代码应依赖已经验证的 principal,而不是信任客户端自己提交的 body.user_id 或 query.owner_id。
5. Credential Entry:密码登录不是一次 Hash Compare
在建立 principal 之前,password authentication 还要经历一层在线攻击防御:
username / password input
→ account existence-safe lookup
→ password verifier
→ per-account + per-source throttling
→ breached/common-password policy(创建/改密阶段)
→ MFA / step-up when required
→ authenticated principal
这里要区分三类攻击:
- Brute Force:一个账号尝试大量密码;
- Password Spraying:少量常见密码横向尝试大量账号;
- Credential Stuffing:拿其他站点泄漏的真实账号密码对来复用。
因此:
one IP rate limit
≠ complete login defense
five failures lock account
≠ complete login defense
真实系统需要 account、IP/device、跨账号扫描、风险信号等多维控制,并避免固定锁号被反向利用制造 DoS。
6. Session / Token:登录状态怎样持续
Stateful Session
opaque session credential
→ session store lookup
→ principal
优势是 revoke 可立即生效、session/device 管理明确;代价是每请求依赖共享状态。
Stateless Access Token
signed short-lived token
→ local validation
→ principal
优势是普通请求不需要 session lookup;代价是已签发 token 通常在过期前仍有效。
Hybrid
ordinary API
→ short-lived Access Token
refresh / logout / revoke
→ durable Session / Grant authority
它把高频访问快路径与长期登录生命周期分开。完整关系见 Stateful、Stateless 与 Hybrid 认证架构。
Session 不是一个 Boolean
登录成功后,Session 最好不只保存:
user_id
还应能表达:
session_id
created_at / last_seen_at
auth_time
authentication methods
mfa_verified_at / assurance
device/browser context
risk state
revoked_at
于是系统可以区分:
session live
≠ auth fresh
≠ device trusted
≠ high-risk action allowed
Active Session、Trusted Device 和 Login History 也应基于这些状态分别投影,而不是全塞进一个“device_id”。
详见 Active Sessions & Device Management。
Trusted Device 只是受控便利信任
remember this device
通常表示:
strong authentication completed
→ issue revocable remembered-device credential
→ future low-risk login can reduce MFA friction
Browser fingerprint、IP、UA 只能作为 risk signal,不自动成为新的认证 factor。
高风险动作仍应检查 近期认证与 Assurance。
Security Events / Risk
认证系统还需要记录和关联:
login success/failure
new device
MFA failure
recovery
credential change
session revoke
suspicious login
这些事件可以驱动 Risk-Based Authentication:
low risk → allow
medium risk → step-up
high risk → deny / recovery / alert
而用户可见 Login History 只是内部安全事件的最小化投影。
7. JWT:格式,不是架构
JWT 回答 Token 怎样携带 claims 并被签名验证。
它不自动回答是否存在服务器 Session、revoke 是否即时、Refresh Token 怎样存、用户当前是否仍有资源权限。
JWT valid
≠ session live
≠ user exists
≠ resource authorized
详见 JWT。
8. Refresh:长期 credential lifecycle
Refresh Token 真正的安全问题是 storage、rotation、replay detection、family/session revoke 与 atomic single-winner transition。
详见 Refresh Token。
9. Authorization:身份已知以后能做什么
Authentication 回答你是谁;Authorization 回答你能对这个资源做什么。
典型层次:
principal
→ coarse role/scope
→ resource ownership
→ policy / business rule
前端隐藏按钮不是安全边界,真正约束必须发生在服务器端。
10. Resource Ownership / BOLA
如果接口只允许用户访问自己的对象,resource_id 必须和可信 principal / tenant policy 一起进入查询或授权判断。
知道资源 ID 不等于获得权限。
11. CSRF:借自动携带凭证发请求
CSRF 常和浏览器自动携带 credential 有关。防御可能组合 SameSite、CSRF Token、Origin/Referer validation 与正确的 HTTP method。
CORS 不能替代 CSRF 防御。详见 CSRF 与 XSS vs CSRF。
12. XSS:数据越过代码执行边界
XSS 的核心不是有没有 script 字符串,而是不可信数据是否进入 dangerous HTML / JS / URL sink。
防御包括 context-aware escaping、安全渲染、sanitization 与 CSP defense in depth。详见 XSS。
13. Security Headers:浏览器纵深防御
CSP
→ 哪些资源/脚本可以加载执行
HSTS
→ 以后必须走 HTTPS
X-Content-Type-Options
→ 不要 MIME sniff
frame-ancestors / X-Frame-Options
→ 谁可以 frame 当前页面
Referrer-Policy
→ 跨站时泄露多少来源 URL
它们不能替代 Authentication、Authorization 或输入验证。
14. Error Boundary:不要把内部失败直接暴露
安全相关错误仍需要稳定公共契约:401 表示未建立有效身份,403 表示身份已知但不允许,404 有时用于隐藏资源存在性,409 表示状态冲突。
内部 DB error、stack、provider details 应进入安全日志,而不是原样返回浏览器。详见 稳定 API 错误模型。
15. Recovery:另一条 Authentication Path
Account Recovery 不是 Authentication 之外的“辅助设置”。
它实际上是:
normal authenticators unavailable
→ alternate proof
→ bind/change credentials
→ restore account access
所以 Recovery 的 assurance 如果显著低于主认证,攻击者会绕开:
Password + MFA
直接攻击:
Forgot Password / MFA Reset / Email Change / Helpdesk
设计时应单独检查:
- request enumeration;
- reset-token entropy / single-use / expiry;
- recovery channel assurance;
- MFA recovery;
- session/refresh revocation;
- security notifications;
- reauthentication after recovery。
详见 Password Reset & Account Recovery。
16. 最小设计检查表
设计 Web Auth 时依次回答:
- 请求使用什么 HTTP method?
- credential 存在哪里、怎样发送?
- 谁验证 credential?
- Authentication 输出什么 principal?
- 登录 lifecycle 的 authority 在哪里?
- Access credential 多久失效?
- revoke 多久生效?
- Refresh 是否 rotation / replay-safe?
- resource authorization 在哪里执行?
- Browser 是否有 CSRF/XSS/CORS 风险?
- 哪些 security headers 是 defense in depth?
- 错误如何安全投影到 HTTP?
- Password 登录是否有 account-level + source-level throttling?
- 是否区分 brute force、password spraying 与 credential stuffing?
- MFA/recovery/step-up 的 assurance boundary 在哪里?
- Password/MFA/Email recovery 完成后,哪些 Session/Refresh/remembered-device credential 必须撤销或降级?
- Session live、auth fresh、device trusted、risk low 为什么是四个不同判断?
- 哪些认证事件应进入内部 Security Event Log,哪些只适合投影给用户?
学习检查
不看正文:
- Cookie、Session、JWT、Access Token、Refresh Token 分别处在哪一层?
- 为什么 JWT valid 不能推出当前 resource authorized?
- Stateful 与 Hybrid 的 revoke semantics 有什么差异?
- CORS 与 CSRF 分别控制什么?
- 为什么 HttpOnly 能降低一种 XSS 风险,却不能自动防 CSRF?
- Authentication principal 为什么不能来自 body.user_id?
- Security Headers 为什么属于 defense in depth,而不是认证系统?
- 给一个浏览器登录后删除订单的请求,按 HTTP → credential-entry defense → authn → session/token → authz → browser security 画完整链路。
- 为什么 per-IP rate limit 与固定 5 次锁号都不能单独作为完整 Password 登录防线?
- MFA 为什么降低 credential stuffing 的直接接管风险,却不能替代 Password Policy 和 recovery security?