240 lines
6.0 KiB
Markdown
240 lines
6.0 KiB
Markdown
# DramaLing 後端帳號管理分析報告
|
||
|
||
## 📊 總體狀況概覽
|
||
|
||
### ✅ 已實現功能
|
||
- **用戶註冊 (`POST /api/auth/register`)**
|
||
- **用戶登入 (`POST /api/auth/login`)**
|
||
- **JWT Token 認證系統**
|
||
- **用戶資料管理 (`GET/PUT /api/auth/profile`)**
|
||
- **用戶設定管理 (`GET/PUT /api/auth/settings`)**
|
||
- **認證狀態檢查 (`GET /api/auth/status`)**
|
||
|
||
### ⚠️ 安全性問題
|
||
- **開發環境中存在硬編碼測試用戶ID**
|
||
- **部分控制器缺乏權限驗證**
|
||
- **JWT Secret 可能使用開發預設值**
|
||
|
||
---
|
||
|
||
## 🔐 認證系統詳細分析
|
||
|
||
### 1. 註冊系統 (`AuthController.cs:28-110`)
|
||
|
||
**功能特點:**
|
||
- 用戶名唯一性檢查
|
||
- Email 唯一性檢查
|
||
- BCrypt 密碼雜湊
|
||
- 自動生成 JWT Token
|
||
- 完整的輸入驗證
|
||
|
||
**驗證規則:**
|
||
```csharp
|
||
Username: 3-50 字符長度
|
||
Email: 標準 Email 格式驗證
|
||
Password: 最少 8 字符
|
||
```
|
||
|
||
### 2. 登入系統 (`AuthController.cs:112-175`)
|
||
|
||
**功能特點:**
|
||
- Email + 密碼認證
|
||
- BCrypt 密碼驗證
|
||
- JWT Token 生成
|
||
- 統一錯誤訊息(避免用戶名洩露)
|
||
|
||
### 3. JWT Token 系統 (`AuthController.cs:177-204`)
|
||
|
||
**設定分析:**
|
||
```csharp
|
||
Secret 來源優先順序:
|
||
1. 環境變數: DRAMALING_SUPABASE_JWT_SECRET
|
||
2. 環境變數: DRAMALING_JWT_SECRET
|
||
3. 預設值: "dev-secret-minimum-32-characters-long-for-jwt-signing-in-development-mode-only"
|
||
|
||
Token 有效期: 7 天
|
||
包含 Claims: NameIdentifier, sub, email, username, name
|
||
```
|
||
|
||
---
|
||
|
||
## 🛡️ 權限控制分析
|
||
|
||
### 已實現權限保護的端點
|
||
|
||
| 控制器 | 端點 | 權限類型 | 備註 |
|
||
|--------|------|----------|------|
|
||
| AuthController | `/api/auth/profile` | `[Authorize]` | 用戶資料 |
|
||
| AuthController | `/api/auth/settings` | `[Authorize]` | 用戶設定 |
|
||
| AuthController | `/api/auth/status` | `[Authorize]` | 認證檢查 |
|
||
| StatsController | 全部端點 | `[Authorize]` | 統計數據 |
|
||
|
||
### ⚠️ 缺乏權限保護的端點
|
||
|
||
| 控制器 | 權限設定 | 風險等級 |
|
||
|--------|----------|----------|
|
||
| FlashcardsController | `[AllowAnonymous]` | 🔴 高風險 |
|
||
| AIController | 未明確設定 | 🟡 中風險 |
|
||
| ImageGenerationController | 未明確設定 | 🟡 中風險 |
|
||
| OptionsVocabularyTestController | 未明確設定 | 🟡 中風險 |
|
||
|
||
---
|
||
|
||
## 🚨 硬編碼用戶問題
|
||
|
||
### 問題位置
|
||
1. **BaseController.cs:79**
|
||
```csharp
|
||
return Guid.Parse("00000000-0000-0000-0000-000000000001");
|
||
```
|
||
|
||
2. **ImageGenerationController.cs:160**
|
||
```csharp
|
||
return Guid.Parse("00000000-0000-0000-0000-000000000001");
|
||
```
|
||
|
||
### 觸發條件
|
||
- 開發環境 (`ASPNETCORE_ENVIRONMENT=Development`)
|
||
- JWT Token 解析失敗時的 Fallback
|
||
|
||
### 風險評估
|
||
- **開發環境**: 可接受(便於測試)
|
||
- **生產環境**: 🔴 高風險(繞過認證)
|
||
|
||
---
|
||
|
||
## 🔧 AuthService 核心邏輯
|
||
|
||
### Token 驗證流程 (`AuthService.cs:56-101`)
|
||
|
||
```csharp
|
||
JWT Secret 來源優先順序:
|
||
1. 環境變數: DRAMALING_SUPABASE_JWT_SECRET
|
||
2. 配置檔案: Supabase:JwtSecret
|
||
3. 無設定時返回 null(驗證失敗)
|
||
|
||
驗證參數:
|
||
- ValidateIssuer: true
|
||
- ValidateAudience: true
|
||
- ValidateLifetime: true
|
||
- ValidateIssuerSigningKey: true
|
||
- ClockSkew: 5 分鐘
|
||
```
|
||
|
||
### 用戶ID 提取邏輯 (`AuthService.cs:25-54`)
|
||
|
||
```csharp
|
||
Claims 查找優先順序:
|
||
1. ClaimTypes.NameIdentifier
|
||
2. "sub" claim
|
||
3. 嘗試解析為 Guid
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 配置管理分析
|
||
|
||
### 環境變數配置
|
||
```bash
|
||
# JWT 相關
|
||
DRAMALING_SUPABASE_JWT_SECRET=<實際密鑰>
|
||
DRAMALING_SUPABASE_URL=<Supabase URL>
|
||
|
||
# API 服務
|
||
ASPNETCORE_ENVIRONMENT=Development|Production
|
||
```
|
||
|
||
### 配置檔案 (`appsettings.json`)
|
||
- **無敏感資訊洩露** ✅
|
||
- **所有密鑰為空字串** ✅
|
||
- **依賴環境變數或 User Secrets** ✅
|
||
|
||
---
|
||
|
||
## 🎯 建議改進措施
|
||
|
||
### 1. 立即修復(高優先級)
|
||
|
||
#### 🔴 移除 FlashcardsController 的 AllowAnonymous
|
||
```csharp
|
||
// 當前
|
||
[AllowAnonymous]
|
||
public class FlashcardsController : BaseController
|
||
|
||
// 建議改為
|
||
[Authorize]
|
||
public class FlashcardsController : BaseController
|
||
```
|
||
|
||
#### 🔴 統一權限保護
|
||
為所有業務控制器添加 `[Authorize]` 屬性:
|
||
- AIController
|
||
- ImageGenerationController
|
||
- OptionsVocabularyTestController
|
||
|
||
### 2. 安全性強化(中優先級)
|
||
|
||
#### 🟡 硬編碼用戶ID 處理
|
||
```csharp
|
||
// 建議修改 BaseController.GetCurrentUserIdAsync()
|
||
protected async Task<Guid> GetCurrentUserIdAsync()
|
||
{
|
||
// ... JWT 解析邏輯 ...
|
||
|
||
// 開發環境 fallback(僅限測試數據庫)
|
||
if (IsTestEnvironment() && IsUsingTestDatabase())
|
||
{
|
||
return Guid.Parse("00000000-0000-0000-0000-000000000001");
|
||
}
|
||
|
||
throw new UnauthorizedAccessException("Invalid or missing user authentication");
|
||
}
|
||
```
|
||
|
||
#### 🟡 JWT Secret 強化
|
||
確保生產環境使用強密鑰:
|
||
```csharp
|
||
// 添加密鑰強度檢查
|
||
if (environment != "Development" && jwtSecret.Length < 32)
|
||
{
|
||
throw new InvalidOperationException("Production JWT secret must be at least 32 characters");
|
||
}
|
||
```
|
||
|
||
### 3. 監控和日誌(低優先級)
|
||
|
||
#### 添加安全事件日誌
|
||
- 失敗的登入嘗試
|
||
- Token 驗證失敗
|
||
- 權限拒絕事件
|
||
|
||
#### 添加指標監控
|
||
- 活躍用戶數
|
||
- 認證失敗率
|
||
- API 調用頻率
|
||
|
||
---
|
||
|
||
## 📊 總結
|
||
|
||
### 優點
|
||
✅ 完整的用戶註冊/登入流程
|
||
✅ 安全的密碼雜湊(BCrypt)
|
||
✅ 標準的 JWT 認證機制
|
||
✅ 配置安全(無硬編碼密鑰)
|
||
✅ 統一的錯誤處理
|
||
|
||
### 待改進
|
||
🔴 部分控制器缺乏權限保護
|
||
🟡 開發環境硬編碼用戶ID
|
||
🟡 需要更完善的安全監控
|
||
|
||
### 風險等級評估
|
||
**整體風險等級**: 🟡 **中等風險**
|
||
|
||
主要風險來自於 FlashcardsController 的 `[AllowAnonymous]` 設定,可能導致未認證用戶存取單字卡數據。建議優先修復此問題。
|
||
|
||
---
|
||
|
||
*分析完成時間: 2025-10-07*
|
||
*後端服務狀態: 正常運行 (http://localhost:5000)* |