init: consolidate all ephron.ren PRDs and docs

This commit is contained in:
Ubuntu
2026-05-15 10:39:54 +08:00
parent 9568533314
commit ee8cddf8b8
21 changed files with 6991 additions and 2 deletions

View File

@@ -0,0 +1,239 @@
# ephron.ren 登录重定向失败问题分析报告
> **严重等级**: 🔴 Critical
> **影响范围**: 所有需要登录的页面Home / Blog / Canvas / Prompt / Auth
> **发现日期**: 2026-05-05
> **状态**: 已确认复现
---
## 1. 问题概述
在 ephron.ren 全站所有页面中,未登录用户点击「登录」后跳转至 `auth.ephron.ren/login?redirect=<base64编码的目标URL>`,填写账号密码点击登录按钮后,**无法重定向回原始页面**,始终停留在登录页。
**影响的所有入口**:
| 来源页面 | 登录页 redirect 参数 | 结果 |
|----------|---------------------|------|
| https://www.ephron.ren/ | `aHR0cHM6Ly93d3cuZXBocm9uLnJlbi8=` | ❌ 失败 |
| https://blog.ephron.ren/ | `aHR0cHM6Ly9ibG9nLmVwaHJvbi5yZW4v` | ❌ 失败 |
| https://canvas.ephron.ren/ | `aHR0cHM6Ly9jYW52YXMuZXBocm9uLnJlbi8=` | ❌ 失败 |
| https://prompt.ephron.ren/ | `aHR0cHM6Ly9wcm9tcHQuZXBocm9uLnJlbi8=` | ❌ 失败 |
| auth.ephron.ren/admin同源 | `aHR0cHM6Ly9hdXRoLmVwaHJvbi5yZW4vYWRtaW4=` | ✅ 成功 |
| 无 redirect 参数 | N/A → `/login-success` | ✅ 成功 |
**关键发现**: 当 redirect 目标与 auth.ephron.ren **同源**时登录正常,**跨源**(不同子域)时失败。
---
## 2. 根因分析
### 2.1 问题根因
**CSP `form-action 'self'` 策略阻止了登录接口的 303 跨源重定向。**
完整流程分析:
```
① 用户在 www.ephron.ren 点击「登录」
→ 跳转到 https://auth.ephron.ren/login?redirect=aHR0cHM6Ly93d3cuZXBocm9uLnJlbi8=
② 用户填写账号密码,点击「登录」按钮
→ 浏览器 POST 到 https://auth.ephron.ren/api/login同源 ✅ 允许)
③ 服务端验证成功,返回 HTTP 303 重定向
→ Location: https://www.ephron.ren/(跨源 ❌)
→ 响应头包含 Content-Security-Policy: ... form-action 'self'
④ 浏览器检查 CSP form-action 策略
→ 重定向目标 https://www.ephron.ren/ ≠ 'self'https://auth.ephron.ren
→ 浏览器阻止重定向,停留在登录页
⑤ 结果Cookie 已设置ephron_auth但页面未跳转
```
### 2.2 技术细节
#### CSP 配置auth.ephron.ren 所有响应)
```
Content-Security-Policy: default-src 'self';
script-src 'self' 'unsafe-inline';
script-src-elem 'self' 'unsafe-inline' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline';
style-src-elem 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net https://maxcdn.bootstrapcdn.com;
img-src 'self' data: https:;
font-src 'self' data: https://fonts.gstatic.com https:;
connect-src 'self';
frame-ancestors 'none';
base-uri 'self';
form-action 'self'
```
关键指令: **`form-action 'self'`**
#### CSP `form-action` 行为说明
根据 CSP Level 2/3 规范,`form-action` 指令限制的是「表单提交的目标 URL」。在 Chromium 的实现中,表单提交触发的 **整个重定向链** 都受此策略约束:
1. 表单 POST 到 `/api/login``https://auth.ephron.ren`)→ ✅ 同源,允许
2. 服务端返回 303 到 `https://www.ephron.ren/` → ❌ 跨源,被阻止
#### 登录接口响应curl 验证)
```http
HTTP/2 303
location: https://www.ephron.ren/
set-cookie: ephron_auth=eyJ2...; Domain=.ephron.ren; HttpOnly; Max-Age=604800; Path=/; SameSite=lax; Secure
content-security-policy: ... form-action 'self'
```
服务端逻辑完全正确:验证凭证 → 签发 token → 设置 Cookie → 303 重定向。但浏览器因 CSP 策略拒绝执行重定向。
#### 源码定位
- **CSP 配置**: `shared/security_headers.py` 第 8-20 行,`_CSP_POLICY` 常量
- **登录接口**: `auth/src/routes/api.py` 第 174-241 行,`POST /api/login`
- **重定向校验**: `auth/src/utils/redirect.py` 第 16-75 行,`validate_redirect()`
- **登录页面模板**: `auth/templates/login.html` 第 140 行,表单 action
---
## 3. 浏览器复现证据
### 3.1 控制台错误
```
[ERROR] Sending form data to 'https://auth.ephron.ren/api/login' violates
the following Content Security Policy directive: "form-action 'self'".
```
### 3.2 网络请求分析
| 请求 | 状态 | 说明 |
|------|------|------|
| `GET /login?redirect=...` | 200 ✅ | 登录页正常加载 |
| `POST /api/login` | 已发送 ✅ | 浏览器确实发出了 POST 请求 |
| 303 重定向响应 | ❌ 未跟随 | 浏览器收到 303 但未执行跳转 |
### 3.3 Cookie 状态
登录后 `ephron_auth` Cookie 已正确设置(`Domain=.ephron.ren; HttpOnly; Secure; SameSite=Lax`),说明服务端逻辑完全正常。问题纯粹在客户端 CSP 策略。
### 3.4 对照实验
| 测试场景 | 结果 | CSP 错误 |
|----------|------|----------|
| 无 redirect 参数登录 | ✅ 跳转到 `/login-success` | 无 |
| redirect = `auth.ephron.ren/admin`(同源) | ✅ 跳转到 admin | 无 |
| redirect = `www.ephron.ren`(跨源) | ❌ 停留登录页 | `form-action 'self'` |
| redirect = `blog.ephron.ren`(跨源) | ❌ 停留 API URL | `form-action 'self'` |
| redirect = `canvas.ephron.ren`(跨源) | ❌ 停留 API URL | `form-action 'self'` |
| redirect = `prompt.ephron.ren`(跨源) | ❌ 停留 API URL | `form-action 'self'` |
---
## 4. 修复方案
### 方案 A推荐: 从 303 响应中移除 CSP 头
`shared/security_headers.py` 的中间件中,对 303 重定向响应不添加 CSP 头:
```python
@app.middleware("http")
async def _security_headers(request: Request, call_next):
response = await call_next(request)
response.headers.setdefault("X-Content-Type-Options", "nosniff")
response.headers.setdefault("X-Frame-Options", "DENY")
response.headers.setdefault("Referrer-Policy", "strict-origin-when-cross-origin")
# 仅对非重定向响应添加 CSP避免 form-action 阻止跨源重定向)
if response.status_code not in (301, 302, 303, 307, 308):
response.headers.setdefault("Content-Security-Policy", _CSP_POLICY)
# ... Cache-Control 逻辑不变
```
**优点**: 最小改动,不影响其他页面的 CSP 保护
**缺点**: 重定向响应失去 CSP 保护(但重定向响应通常无 HTML 内容CSP 保护意义不大)
### 方案 B: 修改 form-action 策略
`form-action 'self'` 改为允许所有 ephron.ren 子域:
```
form-action 'self' https://*.ephron.ren
```
或更精确地列出所有子域:
```
form-action 'self' https://www.ephron.ren https://blog.ephron.ren https://canvas.ephron.ren https://prompt.ephron.ren
```
**优点**: 明确允许列表,安全性可审计
**缺点**: 新增子域需同步更新 CSP通配符 `*` 可能过于宽松
### 方案 C: 改用 JavaScript 重定向
修改登录接口,返回 200 + JSON由前端 JS 执行 `window.location.href` 跳转:
```javascript
// 前端
const res = await fetch('/api/login', { method: 'POST', body: formData });
const data = await res.json();
if (data.success) {
window.location.href = data.redirect_url;
}
```
**优点**: 完全绕开 CSP form-action 限制
**缺点**: 需要修改前后端逻辑JS 禁用时无法登录(渐进增强降级)
### 方案 D: 使用中间页面中转
登录成功后先重定向到 `auth.ephron.ren/redirect?url=<target>`(同源),再由该页面通过 meta refresh 或 JS 跳转到目标:
```html
<!-- auth.ephron.ren/redirect 页面 -->
<meta http-equiv="refresh" content="0;url=https://www.ephron.ren/">
<script>window.location.href = decodeURIComponent(params.get('url'));</script>
```
**优点**: 保持 form-action 'self' 不变
**缺点**: 多一次跳转,增加延迟;需要额外的路由和页面
---
## 5. 推荐修复路径
**推荐方案 A**,理由:
1. **改动最小**: 仅修改 `security_headers.py` 中间件的 1 行逻辑
2. **安全性可接受**: 303 重定向响应体为空(`content-length: 0`CSP 对其无实际保护作用
3. **不影响其他安全头**: `X-Content-Type-Options``X-Frame-Options``Referrer-Policy` 仍正常添加
4. **无需修改前端**: 登录流程保持 HTML 表单提交,不依赖 JavaScript
---
## 6. 附录
### 6.1 受影响的完整页面列表
所有跳转到 `auth.ephron.ren/login?redirect=...` 的页面均受影响:
- `www.ephron.ren` — 首页
- `blog.ephron.ren` — 博客(含文章详情页、管理后台)
- `canvas.ephron.ren` — 画布
- `prompt.ephron.ren` — 提示词(含详情页、管理后台)
- `auth.ephron.ren` — 注册成功后跳转、管理后台
### 6.2 注册表单同样受影响
注册页面 (`auth.ephron.ren/register`) 使用相同的 CSP 策略和表单提交模式,注册成功后的 303 重定向也可能受 `form-action 'self'` 影响。需一并验证和修复。
### 6.3 测试环境
- 浏览器: Chromium (Playwright headless)
- 测试账号: `Elaina_user` / `Elaina_owner`
- 测试时间: 2026-05-05 22:00-22:30 CST