跳轉到

攻擊偵測與回應

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
flowchart TB REQ["傳入請求"] --> R1{"優先序 1<br/>管理員 IP<br/>限制"} R1 -->|"管理員路徑 + 錯誤 IP"| BLOCK1["封鎖"] R1 -->|"通過"| R2{"優先序 2<br/>TradingView<br/>Webhook 放行"} R2 -->|"TV IP + /webhook/*"| ALLOW["放行<br/>(略過速率限制)"] R2 -->|"通過"| R3{"優先序 3<br/>登入<br/>速率限制"} R3 -->|">100 次/5分鐘"| BLOCK3["封鎖"] R3 -->|"通過"| R4{"優先序 4<br/>全域<br/>速率限制"} R4 -->|">2000 次/5分鐘"| BLOCK4["封鎖"] R4 -->|"通過"| R5{"優先序 5-7<br/>AWS 受管理<br/>規則"} R5 -->|"SQLi/XSS/CVE"| BLOCK5["封鎖"] R5 -->|"通過"| APP["應用程式"]

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 和交易端點
flowchart LR REQ["請求<br/>(user_id=42)"] --> CLEAN["ZREMRANGEBYSCORE<br/>移除超過 60 秒<br/>的條目"] CLEAN --> ADD["ZADD<br/>timestamp:uuid"] ADD --> COUNT["ZCARD<br/>計算視窗內<br/>的條目數"] COUNT --> CHECK{"數量 ><br/>60?"} CHECK -->|"是"| REJECT["429 請求<br/>過多"] CHECK -->|"否"| PASS["繼續"] PASS --> EXPIRE["EXPIRE 鍵值<br/>65 秒 TTL"]

為什麼同時需要 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

即時警報

當安全事件被分類為攻擊時,系統會向受影響的使用者發送包含完整上下文的電子郵件警報。

flowchart TB ATTACK["偵測到攻擊<br/>(例如:錯誤的 Webhook 密鑰)"] --> LOG["log_audit()<br/>儲存至 audit_logs 資料表"] LOG --> ALERT["send_attack_alert_email()"] ALERT --> RATE{"速率限制檢查<br/>每位使用者每 30 分鐘<br/>最多 1 封郵件"} RATE -->|"近期已發送"| SKIP["略過郵件<br/>(避免垃圾郵件)"] RATE -->|"可以發送"| EMAIL["發送郵件給用戶"] EMAIL --> CONTENT["郵件內容:<br/>• 攻擊類型<br/>• 來源 IP 位址<br/>• 時間戳記<br/>• 帳戶名稱<br/>• 其他詳細資訊"]

警報屬性:

屬性 詳情
傳送方式 非同步(非阻塞、盡力傳送)——永遠不延遲請求處理
速率限制 每位使用者每 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_orderwebhook_credential_attacklogin
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
  • 受影響的交易帳戶
  • 歷史攻擊模式

這使使用者能夠:

  1. 識別 Webhook 密鑰是否已被洩漏(重複的 webhook_credential_attack 事件)
  2. 偵測基於 IP 的掃描行為(來自不同 IP 的多個 webhook_ip_blocked
  3. 驗證 IP 白名單是否正確設定
  4. 決定是否需要輪替 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 資源的明確白名單。每個白名單項目對應一個特定的前端功能——不允許使用萬用字元來源。