盲中繼濫用防護
AeroNyx 節點如何在不讀取密文的前提下抑制重放、迴圈、速率濫用與故障 peer,並提供隱私安全的營運證據。
盲中繼濫用防護是 AeroNyx 去中心化密文轉發的安全邊界。它限制惡意或不穩定的中繼行為,但不解析密文、不建立持久路徑歷史,也不讓節點營運者變成流量觀察者。
狀態與範圍
防護已在 Rust 實作,聚合結果會透過節點健康 metadata 與 Nodeboard 顯示。它只負責控制風險並提供誠實證據:顯示不透明中繼工作是已接受、受防護、降級或過期,而不透露密文內容。
| 控制項 | 狀態 |
|---|---|
| Blind payload forwarding | 已實作 |
| Signed freshness and replay suppression | 已實作 |
| Previous-hop rate limiting and quarantine | 已實作 |
| Privacy-safe runtime evidence | 已實作 |
| Nodeboard operator visibility | 已實作 |
| Plaintext or payload inspection | 禁止 |
| User, route, or social-graph analytics | 禁止 |
盲節點不變量
中繼可以驗證路由 metadata 的簽名、執行有界策略、轉發不透明 envelope,並回傳 terminal 簽名 receipt;但不能檢查或推導 payload,也不能公開足以重建路徑、使用者身分或社交關係的 metadata。
- 訊息明文、封包 payload、媒體內容或 MemChain 明文
- DNS 內容、目的地、網域、URL 或瀏覽紀錄
- route ID、完整路徑、endpoint URL 或 client 公網 IP
- 完整公鑰、receiver 身分、message ID 或社交圖譜邊
- 私鑰、voucher secret、wallet-level 流量或解密材料
准入處理流程
每個請求在占用轉發容量前都會經過有界檢查。以下是概念順序;所有判定只使用已簽名路由 metadata 與本地聚合狀態,不使用解密內容。
verify signed previous_hop and envelope
apply in-flight backpressure
check timestamp freshness
check route replay cache
apply previous-hop rate/quarantine decision
validate TTL, loop safety, next-hop descriptor, and endpoint
forward opaque ciphertext or terminate into pending store
重放與時效防護
重放抑制僅存在本機、保存期短且容量有界。簽名 envelope timestamp 會拒絕過期或不合理的未來 frame。下表是目前 main 的執行期預設值,不是永久協議承諾;調整時必須同步測試與文件。
| 執行期常數 | 目前預設 |
|---|---|
MAX_BLIND_RELAY_SEEN_ROUTES | 8192 route IDs |
BLIND_RELAY_ROUTE_REPLAY_WINDOW_SECS | 600 seconds |
BLIND_RELAY_PREVIOUS_HOP_RATE_LIMIT | 120 requests / 60 seconds |
BLIND_RELAY_PREVIOUS_HOP_FAILURE_THRESHOLD | 12 scored failures / 300 seconds |
BLIND_RELAY_PREVIOUS_HOP_QUARANTINE_SECS | 300 seconds |
MAX_BLIND_RELAY_PREVIOUS_HOP_BUCKETS | 4096 buckets |
BLIND_RELAY_MAX_ENVELOPE_AGE_SECS | 600 seconds |
BLIND_RELAY_MAX_FUTURE_SKEW_SECS | 120 seconds |
BLIND_RELAY_DELIVERY_RECEIPT_MAX_AGE_SECS | 120 seconds |
MAX_BLIND_RELAY_FORWARD_ATTEMPTS | 3 attempts |
前一跳速率限制與隔離
速率限制以已簽名的前一跳身分分桶。60 秒內超過 120 個請求會啟動五分鐘本地隔離;另一組失敗分數會在五分鐘內累積 12 次具攻擊性的驗證失敗後啟動相同隔離。
invalid_previous_hop | invalid_signature | self_loop | route_loop | ttl_exhausted
只有惡意驗證原因會增加失敗分數。傳輸 timeout、ACK 遺失與重複 route 重試不會污染健康前一跳。bucket 儲存有容量上限且閒置狀態會到期,因此不能演變成持久通訊關係圖。
冪等與重試語義
重放視窗內重複的 route ID 會得到冪等成功回應:節點增加一次聚合 replay drop,但不會再次投遞或轉發 envelope。暫時性下一跳錯誤最多嘗試三次並加入有界 jitter;永久驗證錯誤不重試。
duplicate route_id -> accepted=true, reason=duplicate_route, no second delivery
transient next-hop failure -> bounded retry with deterministic jitter
permanent validation failure -> no retry
聚合執行期計數
Rust 在下列兩個路徑提供粗粒度累積計數與 freshness timestamp。這些是節點範圍的營運證據,不是訊息日誌、可計費使用者分析,也不能證明某段特定對話發生。
system_stats.discovery_status.peer_store.runtime.blind_relay
system_stats.discovery_status.peer_store.peer_health_summary
| 計數分組 | 欄位 |
|---|---|
| 接收與處置 | received, terminal, forwarded, rejected |
| 驗證與防護 | invalid_signature, envelope_too_large, ttl_exhausted, no_route, invalid_endpoint, loop_detected, replay_dropped, timestamp_rejected, rate_limited, quarantined, quarantine_started |
| 傳輸與重試 | backpressure_dropped, forward_failed, retry_attempted, retry_succeeded, retry_exhausted |
| Synthetic 證據 | probe_attempted, probe_succeeded, probe_failed, two_hop_probe_attempted, two_hop_probe_succeeded, two_hop_probe_failed |
| 真實投遞與 freshness | verified_client_onion_deliveries, last_verified_client_onion_delivery_at, last_accepted_at, last_event_at |
證據品質語義
品質摘要會區分已接受的不透明工作、synthetic 可達性 probe、synthetic 兩跳控制 proof,以及 terminal 簽名的真實 client delivery receipt。只有預期 terminal 對新鮮、經認證的 client-originated delivery 簽名時,real_relay_ready 才成立;synthetic 證據不得宣稱為 App/使用者流量。
status | 含義 |
|---|---|
idle | 尚無中繼或 probe 證據。 |
observing | 已有部分證據,但尚未建立 readiness。 |
stale | 先前成功證據已不新鮮。 |
ready | 有新鮮的已接受工作或合格 proof,且無活動中的傳輸警示。 |
protecting | 濫用防護計數已觸發,但中繼仍可運作。 |
degraded | 轉發或 probe 失敗需要調查。 |
attention | Backpressure 或重試耗盡需要立即處理。 |
proof_scope 進一步區分 client_message_delivery、relay_acceptance、message_delivery、control_plane、single_hop_control_plane、attempted 與 none。歷史總量持續累積,但 readiness boolean 必須依賴新鮮證據並納入目前傳輸故障。
隱私安全的 peer 健康摘要
peer_health_summary 使用縮短的 node identifier 與粗粒度健康 bucket,讓營運者能隔離故障或被 quarantine 的 peer,而不看見流量關係。它是帶明確隱私邊界的控制面診斷資訊。
允許:
- 縮短的
node_id_prefix - 粗粒度 health 與 descriptor 狀態
- gossip 與 route success freshness bucket
- 聚合 route 成功與失敗計數
- 聚合 loop、replay、rate-limit 與 quarantine 計數
- 隔離剩餘時間與有界原因 bucket
不允許:
- 完整節點公鑰
- route ID 或 endpoint 清單
- 密文 blob 或 payload hash
- message ID 或 receiver 身分
- client IP、目的地或 DNS 資料
- 社交圖譜邊或誰與誰通訊
營運者流程
開啟 Nodeboard、選擇節點,再進入 Discovery 與 Security / Relay Protection。只以節點健康、可達性、queue 壓力及簽名 proof freshness 解讀趨勢。
- 確認 discovery descriptor 與 bootstrap recovery 保持新鮮。
- 宣告 runtime ready 前,比較
accepted_total、accepted_percent與最後接受事件的 age。 - 區分
real_relay_ready與 synthetic probe readiness;只有前者證明經認證 client-originated terminal receipt。 - 若出現 protecting、degraded 或 attention,只檢查聚合原因 bucket 與傳輸健康,不要求使用者層級日誌。
源碼關係圖
文件使用倉庫相對路徑,因此基礎設施移轉主機後規格仍有效。後端與 Nodeboard 位於不同倉庫,但只消費 owner-scoped、隱私安全的節點 metadata。
| 層級 | 倉庫路徑 | 職責 |
|---|---|---|
| Rust 中繼 API | crates/aeronyx-server/src/api/chat_peer.rs | 驗證 envelope,執行 loop、replay、freshness、rate、quarantine、retry 與 terminal receipt 規則。 |
| Rust PeerStore | crates/aeronyx-server/src/services/peer_store.rs | 保存有界聚合計數、peer health、readiness 與 proof 分類。 |
| Rust 健康 API | crates/aeronyx-server/src/api/vpn_health.rs | 輸出本地隱私安全 health JSON。 |
| Rust reporter | crates/aeronyx-server/src/management/reporter.rs | 在節點 heartbeat metadata 傳送聚合狀態。 |
| 後端可觀測性 | privacy_network/api/vpn_observability.py | 向營運控制台回傳 owner-scoped system metadata。 |
| Nodeboard types | types/index.ts | 定義 blind relay 與 peer health response type。 |
| Nodeboard 詳情與 i18n | app/dashboard/nodes/[id]/page.tsx and lib/i18n/index.ts | 以多語言隱私邊界文案呈現 Security / Relay Protection。 |
多跳路由的基礎
多跳路由需要抗重放、迴圈控制、有界重試、peer 隔離,以及不會被誤解成使用者流量的證據。這套防護為分層加密與後續路徑多樣性提供基礎,同時不削弱盲節點不變量。
開發規則
每個新增欄位都必須視為隱私審查。有效的營運指標應回答節點層級可靠性問題,卻不能識別 payload、sender、receiver、path、endpoint 或 conversation。
- 所有中繼路徑都必須維持
payload_b64不透明。 - 只新增聚合計數或有界原因 bucket。
- 計數不得與 route ID、endpoint、user、receiver 或 message metadata join。
- Synthetic probe 不得計入加密訊息、封包或 byte 總量。
- 語義變更時同步更新 Rust tests、Nodeboard types 與本頁所有語言。