攻擊偵測與回應¶
4pass 結合邊緣層保護(AWS WAF)和應用層偵測(速率限制、稽核日誌、電子郵件警報)來即時識別和回應攻擊。WAF 在網路邊緣處理大量流量和已知模式的攻擊;應用層則分類並告警 WAF 無法偵測的業務邏輯攻擊。
回應承諾
針對每種分類的攻擊(憑證攻擊、重送嘗試、IP 違規),系統會向受影響的使用者發送即時電子郵件警報。警報頻率限制為每位使用者每 30 分鐘 1 封以防止疲勞。警報投遞為非同步且即發即忘 — 安全監控永遠不會降低主要交易功能。使用者可透過儀表板安全面板查看所有攻擊歷史。
WAF 規則¶
AWS WAFv2 Web ACL 與 Application Load Balancer 關聯,按優先順序評估規則。第一條匹配的規則決定處理動作。
| 優先序 | 規則名稱 | 動作 | 條件 | 目標 | 用途 |
|---|---|---|---|---|---|
| 1 | Admin IP Restriction | 封鎖 | 不在 admin_ips IP 集合中且路徑匹配 /setup/*、/deployment/* |
基礎設施端點 | 防止未經授權存取管理員/遷移端點 |
| 2 | TradingView Webhook Allow | 放行 | 在 tradingview_ips IP 集合中且路徑匹配 /webhook/* |
Webhook 端點 | 豁免 TradingView IP 的速率限制(共享 IP 服務所有使用者) |
| 3 | Login Rate Limit | 封鎖 | 速率限制:每 IP 每 5 分鐘 100 次請求 | /auth/login、/auth/register、/auth/forgot-password |
防止撞庫攻擊和暴力破解 |
| 4 | Blanket Rate Limit | 封鎖 | 速率限制:每 IP 每 5 分鐘 2,000 次請求 | 所有請求 | DDoS 防護;在 10K 使用者時擴展至 10K(waf_rate_limit 變數) |
| 5 | AWS Common Rule Set | 封鎖/計數 | 受管理規則群組:AWSManagedRulesCommonRuleSet |
所有請求 | SQL 注入、XSS、路徑遍歷、檔案包含 |
| 6 | AWS Known Bad Inputs | 封鎖 | 受管理規則群組:AWSManagedRulesKnownBadInputsRuleSet |
所有請求 | Log4j、Java 反序列化、已知漏洞酬載 |
| 7 | AWS IP Reputation | 封鎖 | 受管理規則群組:AWSManagedRulesAmazonIpReputationList |
所有請求 | 殭屍網路、Tor 出口節點、已知惡意 IP |
TradingView IP 豁免
TradingView 從共享的 IP 集合為所有使用者發送 Webhook。如果這些 IP 觸及全域速率限制,所有使用者的合法訂單都會被阻擋。規則 2 豁免這些 IP 的 WAF 速率限制。每位使用者的濫用由應用層速率限制器處理(每位使用者每分鐘 60 次請求)。
AWS 受管理規則覆寫¶
Common Rule Set 包含可能對交易酬載產生誤判的規則。特定規則被設定為計數 (Count) 模式而非封鎖:
| 規則 | 覆寫方式 | 原因 |
|---|---|---|
SizeRestrictions_BODY |
計數 | 交易酬載可能超過預設主體大小限制 |
CrossSiteScripting_BODY |
計數 | 包含特殊字元的 JSON 酬載觸發誤判 |
GenericRFI_BODY |
計數 | 交易設定欄位中的 URL 類字串 |
所有被覆寫的規則仍會記錄到 CloudWatch 以供人工審查。
應用層速率限制¶
應用程式使用 Redis 有序集合滑動視窗實作每位使用者速率限制,補充 WAF 的每 IP 方式。
| 屬性 | 值 |
|---|---|
| 演算法 | 有序集合滑動視窗(ZADD + ZREMRANGEBYSCORE + ZCARD) |
| 鍵值格式 | ratelimit:{user_id} |
| 視窗 | 60 秒 |
| 預設限制 | 每分鐘 60 次請求 |
| 故障模式 | 故障開放 (Fail-Open) —— Redis 錯誤時靜默通過 |
| 套用於 | Webhook 和交易端點 |
為什麼同時需要 WAF 和應用層速率限制?
| 維度 | WAF(邊緣) | 應用層 |
|---|---|---|
| 鍵值 | 每 IP | 每位使用者(已認證) |
| 層級 | 網路邊緣(應用程式之前) | 應用程式(認證之後) |
| 範圍 | 所有請求 | 僅 Webhook + 交易 |
| 用途 | DDoS、大量流量攻擊 | 每位使用者濫用、失控機器人 |
| 故障模式 | 強制封鎖 | 故障開放(不阻斷交易) |
偵測的攻擊類型¶
應用程式按類型分類攻擊,並以適當的 HTTP 狀態碼、稽核事件和電子郵件警報回應。
| 攻擊類型 | 觸發條件 | HTTP 狀態碼 | 電子郵件警報 | 稽核動作 |
|---|---|---|---|---|
webhook_ip_blocked |
請求 IP 不在使用者的白名單中 | 403 Forbidden |
有 立即 | 有 |
webhook_timestamp_expired |
請求時間戳記超過 max_request_age |
401 Unauthorized |
有 立即 | 有 |
webhook_credential_attack |
無效的 Webhook 密鑰(常數時間比對) | 401 Unauthorized |
有 立即 | 有 |
webhook_replay_attack |
在 Redis 中發現重複的請求雜湊 | 409 Conflict |
有 立即 | 有 |
webhook_payload_invalid |
請求主體格式錯誤或缺少必要欄位 | 400 Bad Request |
無 | 有 |
csrf_validation_failed |
CSRF Token 缺失或與 Session 不匹配 | 403 Forbidden |
無 | 有 |
即時警報¶
當安全事件被分類為攻擊時,系統會向受影響的使用者發送包含完整上下文的電子郵件警報。
警報屬性:
| 屬性 | 詳情 |
|---|---|
| 傳送方式 | 非同步(非阻塞、盡力傳送)——永遠不延遲請求處理 |
| 速率限制 | 每位使用者每 30 分鐘最多 1 封電子郵件(防止警報疲勞) |
| 錯誤處理 | 所有例外均被捕捉並記錄——警報失敗永遠不干擾請求流程 |
| 內容 | 攻擊類型、來源 IP、時間戳記、受影響帳戶名稱、人類可讀的描述 |
警報設計理念
警報刻意設計為發送即忘 (Fire-and-Forget)。_send_attack_alert() 函式將所有邏輯包裝在 try/except 中,確保電子郵件服務故障、速率限制器錯誤或任何其他問題都不會導致 Webhook 請求失敗。安全監控不應降低主要交易功能的可用性。
稽核日誌¶
每個與安全相關的操作都透過 log_audit() 函式記錄到 audit_logs PostgreSQL 資料表中。
| 欄位 | 類型 | 內容 |
|---|---|---|
id |
Serial | 自動遞增主鍵 |
user_id |
FK → users | 已認證的使用者(或 Webhook 攻擊的目標使用者) |
action |
String | 事件類型:webhook_order、webhook_credential_attack、login 等 |
success |
Boolean | 操作是否成功 |
ip_address |
String | 透過可信代理鏈擷取的客戶端 IP(X-Forwarded-For) |
user_agent |
String | 請求的 User-Agent 標頭 |
request_path |
String | 完整的請求 URL 路徑 |
request_method |
String | HTTP 方法(GET、POST 等) |
error_message |
String | 失敗原因(成功時為 null) |
resource_type |
String | 受影響的資源類型(order、account、session 等) |
resource_id |
String | 特定的資源識別碼 |
metadata |
JSONB | 任意結構化資料(攻擊詳情、請求時效、交易帳戶 ID 等) |
created_at |
Timestamp | 事件時間戳記 |
稽核記錄範例:
{
"action": "webhook_credential_attack",
"success": false,
"ip_address": "203.0.113.42",
"error_message": "Invalid webhook secret",
"metadata": {
"attack_type": "wrong_secret",
"trading_account_id": 15
}
}
{
"action": "webhook_replay_attack",
"success": false,
"ip_address": "198.51.100.7",
"error_message": "Replay attack detected (duplicate request)",
"metadata": {
"payload_hash": "a1b2c3d4e5f6..."
}
}
安全儀表板¶
使用者可透過控制面板監控針對其帳戶的攻擊:
| 端點 | 用途 |
|---|---|
GET /settings/security-attacks |
已認證使用者的安全事件分頁列表 |
儀表板顯示:
- 按類型統計的攻擊次數(憑證攻擊、重放嘗試、IP 違規)
- 近期事件,含時間戳記和來源 IP
- 受影響的交易帳戶
- 歷史攻擊模式
這使使用者能夠:
- 識別 Webhook 密鑰是否已被洩漏(重複的
webhook_credential_attack事件) - 偵測基於 IP 的掃描行為(來自不同 IP 的多個
webhook_ip_blocked) - 驗證 IP 白名單是否正確設定
- 決定是否需要輪替 Webhook Token 和密鑰
安全標頭¶
每個 HTTP 回應都包含一組完整的安全標頭,由 SecurityHeadersMiddleware 注入(在 ALB 後方執行時取代 NGINX security-headers.conf)。
| 標頭 | 值 | 防護 |
|---|---|---|
Strict-Transport-Security |
max-age=31536000; includeSubDomains; preload |
強制 HTTPS 1 年;符合瀏覽器預載入清單資格 |
Content-Security-Policy |
含明確白名單的嚴格策略,涵蓋腳本、樣式、圖片、連線、框架 | 防止 XSS、行內注入、未授權資源載入 |
X-Content-Type-Options |
nosniff |
防止瀏覽器對回應進行 MIME 嗅探,偏離宣告的內容類型 |
X-Frame-Options |
SAMEORIGIN |
透過禁止跨來源 iframe 嵌入來防止點擊劫持 (Clickjacking) |
X-XSS-Protection |
1; mode=block |
啟用舊版瀏覽器 XSS 稽核器(為舊版瀏覽器的縱深防禦) |
Cross-Origin-Opener-Policy |
same-origin |
隔離瀏覽上下文以防止 Spectre 類別的側通道攻擊 |
Cross-Origin-Resource-Policy |
same-origin |
防止其他來源讀取此來源的資源 |
Cross-Origin-Embedder-Policy |
unsafe-none |
放寬限制以避免破壞 CDN 資源(Tailwind、Vue、Font Awesome) |
Referrer-Policy |
strict-origin-when-cross-origin |
同源時傳送完整 Referrer,跨來源時僅傳送來源 |
Permissions-Policy |
geolocation=(), microphone=(), camera=(), payment=() |
明確停用應用程式未使用的瀏覽器 API |
CSP 白名單
Content-Security-Policy 包含針對 TradingView 小工具(s3.tradingview.com)、Cloudflare Turnstile(challenges.cloudflare.com)、Google Analytics 和 CDN 資源的明確白名單。每個白名單項目對應一個特定的前端功能——不允許使用萬用字元來源。