Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
505
vendor/ruvector/examples/edge-net/docs/security-architecture.md
vendored
Normal file
505
vendor/ruvector/examples/edge-net/docs/security-architecture.md
vendored
Normal file
@@ -0,0 +1,505 @@
|
||||
# Edge-Net Relay Security Architecture
|
||||
|
||||
## System Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Edge-Net Security Layers │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Layer 1: Connection Security │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ • Origin Validation (CORS) │ │
|
||||
│ │ • Connection Limits (5 per IP) │ │
|
||||
│ │ • Heartbeat Timeout (30s) │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Layer 2: Message Security │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ • Rate Limiting (100 msg/min per node) │ │
|
||||
│ │ • Message Size Limits (64KB max) │ │
|
||||
│ │ • Message Type Validation │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Layer 3: Identity Security (⚠️ NEEDS IMPROVEMENT) │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ • Public Key Registration │ │
|
||||
│ │ • ❌ Signature Verification (NOT IMPLEMENTED) │ │
|
||||
│ │ • ⚠️ No Proof of Key Ownership │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Layer 4: Task Security (✅ SECURE) │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ • Assignment Tracking (Map-based) │ │
|
||||
│ │ • Node ID Verification │ │
|
||||
│ │ • Replay Prevention (Set-based) │ │
|
||||
│ │ • Task Expiration (5 min) │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Layer 5: Credit Security (✅ SECURE) │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ • QDAG Firestore Ledger (Source of Truth) │ │
|
||||
│ │ • Server-Only Crediting │ │
|
||||
│ │ • Credit Self-Reporting BLOCKED │ │
|
||||
│ │ • Public Key-Based Ledger │ │
|
||||
│ └────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task Lifecycle Security
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Submitter │
|
||||
│ (Node A) │
|
||||
└──────┬──────┘
|
||||
│
|
||||
│ 1. task_submit
|
||||
│ (task details + maxCredits)
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
│ Relay Server │
|
||||
│ ┌──────────────────────────────┐ │
|
||||
│ │ 2. Generate Task ID │ │
|
||||
│ │ task-{timestamp}-{random} │ │
|
||||
│ └──────────────┬───────────────┘ │
|
||||
│ │ │
|
||||
│ │ 3. Add to taskQueue│
|
||||
│ ↓ │
|
||||
│ ┌──────────────────────────────┐ │
|
||||
│ │ 4. Select Random Worker │ │
|
||||
│ │ (from connected nodes) │ │
|
||||
│ └──────────────┬───────────────┘ │
|
||||
│ │ │
|
||||
│ │ 5. Store Assignment│
|
||||
│ │ assignedTasks.set(taskId, {
|
||||
│ │ assignedTo: workerNodeId,
|
||||
│ │ assignedToPublicKey: workerPubKey,
|
||||
│ │ submitter: submitterNodeId,
|
||||
│ │ maxCredits: credits,
|
||||
│ │ assignedAt: timestamp
|
||||
│ │ })
|
||||
│ ↓ │
|
||||
└─────────────────┼────────────────────┘
|
||||
│
|
||||
│ 6. task_assignment
|
||||
↓
|
||||
┌──────────────┐
|
||||
│ Worker │
|
||||
│ (Node B) │
|
||||
└──────┬───────┘
|
||||
│
|
||||
│ 7. Processes task
|
||||
│
|
||||
│ 8. task_complete
|
||||
│ (taskId + result + reward)
|
||||
↓
|
||||
┌─────────────────────────────────────┐
|
||||
│ Relay Server │
|
||||
│ ┌──────────────────────────────┐ │
|
||||
│ │ 9. SECURITY CHECKS: │ │
|
||||
│ │ ✓ Task in assignedTasks? │ │
|
||||
│ │ ✓ Node ID matches? │ │
|
||||
│ │ ✓ Not already completed? │ │
|
||||
│ │ ✓ Public key exists? │ │
|
||||
│ └──────────────┬───────────────┘ │
|
||||
│ │ │
|
||||
│ │ 10. Mark Complete │
|
||||
│ │ completedTasks.add(taskId)
|
||||
│ │ assignedTasks.delete(taskId)
|
||||
│ ↓ │
|
||||
│ ┌──────────────────────────────┐ │
|
||||
│ │ 11. Credit Worker (Firestore)│ │
|
||||
│ │ creditAccount( │ │
|
||||
│ │ publicKey, │ │
|
||||
│ │ rewardAmount, │ │
|
||||
│ │ taskId │ │
|
||||
│ │ ) │ │
|
||||
│ └──────────────┬───────────────┘ │
|
||||
│ │ │
|
||||
│ │ 12. Notify Worker │
|
||||
│ │ credit_earned │
|
||||
│ │ │
|
||||
│ │ 13. Notify Submitter│
|
||||
│ │ task_result │
|
||||
└─────────────────┼────────────────────┘
|
||||
│
|
||||
↓
|
||||
┌────────────────┐
|
||||
│ QDAG Ledger │
|
||||
│ (Firestore) │
|
||||
│ │
|
||||
│ publicKey: │
|
||||
│ earned: +X │
|
||||
│ tasks: +1 │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Attack Vector Protections
|
||||
|
||||
### 1. Task Completion Spoofing Attack
|
||||
|
||||
```
|
||||
ATTACK SCENARIO:
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Attacker │ │ Victim │
|
||||
│ (Node C) │ │ (Node B) │
|
||||
└──────┬──────┘ └──────┬──────┘
|
||||
│ │
|
||||
│ │ Assigned task-123
|
||||
│ │
|
||||
│ ❌ task_complete (task-123) │
|
||||
│ "I completed it!" │
|
||||
↓ ↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Relay Server │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ SECURITY CHECK: │ │
|
||||
│ │ assignedTasks.get('task-123') │ │
|
||||
│ │ → { assignedTo: 'node-b' } │ │
|
||||
│ │ │ │
|
||||
│ │ if (assignedTo !== attackerNodeId) { │ │
|
||||
│ │ ❌ REJECT: "Not assigned to you" │ │
|
||||
│ │ } │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
|
||||
RESULT: ✅ Attack BLOCKED
|
||||
```
|
||||
|
||||
### 2. Replay Attack
|
||||
|
||||
```
|
||||
ATTACK SCENARIO:
|
||||
┌─────────────┐
|
||||
│ Worker │
|
||||
│ (Node B) │
|
||||
└──────┬──────┘
|
||||
│
|
||||
│ ✅ task_complete (task-123) → CREDITED 1000 rUv
|
||||
│
|
||||
│ Wait 1 second...
|
||||
│
|
||||
│ ❌ task_complete (task-123) → TRY AGAIN for another 1000 rUv
|
||||
↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Relay Server │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ FIRST COMPLETION: │ │
|
||||
│ │ 1. Verify assignment ✅ │ │
|
||||
│ │ 2. completedTasks.add('task-123') │ │
|
||||
│ │ 3. assignedTasks.delete('task-123') │ │
|
||||
│ │ 4. creditAccount() ✅ │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ SECOND COMPLETION (REPLAY): │ │
|
||||
│ │ 1. Check: completedTasks.has(task-123) │ │
|
||||
│ │ → TRUE │ │
|
||||
│ │ 2. ❌ REJECT: "Already completed" │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
|
||||
RESULT: ✅ Replay Attack BLOCKED
|
||||
```
|
||||
|
||||
### 3. Credit Self-Reporting Attack
|
||||
|
||||
```
|
||||
ATTACK SCENARIO:
|
||||
┌─────────────┐
|
||||
│ Attacker │
|
||||
│ (Node C) │
|
||||
└──────┬──────┘
|
||||
│
|
||||
│ ❌ ledger_update
|
||||
│ {
|
||||
│ publicKey: "my-key",
|
||||
│ ledger: {
|
||||
│ earned: 999999999, ← FAKE!
|
||||
│ spent: 0
|
||||
│ }
|
||||
│ }
|
||||
↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Relay Server │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ case 'ledger_update': │ │
|
||||
│ │ console.warn("REJECTED") │ │
|
||||
│ │ ws.send({ │ │
|
||||
│ │ type: 'error', │ │
|
||||
│ │ message: 'Credit self-reporting │ │
|
||||
│ │ disabled' │ │
|
||||
│ │ }) │ │
|
||||
│ │ ❌ RETURN (no action taken) │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
│
|
||||
│ Only way to earn credits:
|
||||
↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Complete assigned task → relay calls │
|
||||
│ creditAccount() → Firestore updated │
|
||||
└─────────────────────────────────────────────────┘
|
||||
|
||||
RESULT: ✅ Self-Reporting BLOCKED
|
||||
```
|
||||
|
||||
### 4. Public Key Spoofing Attack
|
||||
|
||||
```
|
||||
ATTACK SCENARIO:
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Attacker │ │ Victim │
|
||||
│ (Node C) │ │ (Node V) │
|
||||
│ │ │ │
|
||||
│ pubKey: │ │ pubKey: │
|
||||
│ "victim-pk" │ ← SPOOFED │ "victim-pk" │
|
||||
└──────┬──────┘ └─────────────┘
|
||||
│
|
||||
│ Register with victim's public key
|
||||
↓
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Relay Server │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ CURRENT PROTECTION (Limited): │ │
|
||||
│ │ ⚠️ Registration allowed │ │
|
||||
│ │ (no signature verification) │ │
|
||||
│ │ ✅ Credits assigned at task time │ │
|
||||
│ │ (uses publicKey from assignment) │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
|
||||
CURRENT SECURITY:
|
||||
✅ Attacker CANNOT steal victim's existing credits
|
||||
(ledger keyed by public key - victim still has their balance)
|
||||
|
||||
✅ Attacker CANNOT complete victim's assigned tasks
|
||||
(checked by NODE ID, not public key)
|
||||
|
||||
⚠️ Attacker CAN check victim's balance
|
||||
(ledger_sync is read-only, returns balance for any public key)
|
||||
|
||||
⚠️ Attacker working benefits victim
|
||||
(credits earned go to victim's public key)
|
||||
|
||||
NEEDED IMPROVEMENT:
|
||||
❌ Add Ed25519 signature verification
|
||||
❌ Challenge-response on registration
|
||||
❌ Signature required on sensitive operations
|
||||
|
||||
RESULT: ⚠️ Partially Protected (needs signatures)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## QDAG Ledger Architecture
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ QDAG Credit System │
|
||||
│ (Quantum Directed Acyclic Graph Ledger) │
|
||||
└───────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Firestore Database │
|
||||
│ (SOURCE OF TRUTH) │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ Collection: edge-net-qdag │ │
|
||||
│ │ ┌─────────────────────────────────────────────────┐ │ │
|
||||
│ │ │ Document: {publicKey} │ │ │
|
||||
│ │ │ { │ │ │
|
||||
│ │ │ earned: 5000000, ← Can only increase │ │ │
|
||||
│ │ │ spent: 1000000, │ │ │
|
||||
│ │ │ tasksCompleted: 5, │ │ │
|
||||
│ │ │ createdAt: 1234567890, │ │ │
|
||||
│ │ │ updatedAt: 1234567899, │ │ │
|
||||
│ │ │ lastTaskId: "task-123-xyz" │ │ │
|
||||
│ │ │ } │ │ │
|
||||
│ │ └─────────────────────────────────────────────────┘ │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└─────────────────┬───────────────────────────────────────────┘
|
||||
│
|
||||
│ Synced via
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Relay Server (In-Memory Cache) │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ ledgerCache = new Map() │ │
|
||||
│ │ "pubkey1" → { earned: 5000000, spent: 1000000 } │ │
|
||||
│ │ "pubkey2" → { earned: 2000000, spent: 500000 } │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ Credit Functions (SERVER ONLY): │ │
|
||||
│ │ │ │
|
||||
│ │ async function creditAccount(pubKey, amount, taskId) │ │
|
||||
│ │ ✅ ONLY way to increase credits │ │
|
||||
│ │ ✅ ONLY called after verified task completion │ │
|
||||
│ │ ✅ Writes to Firestore (source of truth) │ │
|
||||
│ │ │ │
|
||||
│ │ async function debitAccount(pubKey, amount, reason) │ │
|
||||
│ │ ✅ For spending credits │ │
|
||||
│ │ ✅ Checks balance before debiting │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ Clients can only:
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Client Nodes │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ ledger_sync (read-only) │ │
|
||||
│ │ → Returns balance from Firestore │ │
|
||||
│ │ │ │
|
||||
│ │ ledger_update (BLOCKED) │ │
|
||||
│ │ → Error: "Credit self-reporting disabled" │ │
|
||||
│ │ │ │
|
||||
│ │ task_complete (after assignment) │ │
|
||||
│ │ → Relay verifies → calls creditAccount() │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
KEY SECURITY PROPERTIES:
|
||||
✅ Credits keyed by PUBLIC KEY (identity, not node)
|
||||
✅ Same public key = same balance across devices
|
||||
✅ Server-side ONLY credit increases
|
||||
✅ Firestore is single source of truth
|
||||
✅ Clients cannot self-report credits
|
||||
✅ Persistent across sessions
|
||||
✅ Atomic operations with cache
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Control Matrix
|
||||
|
||||
| Control | Type | Status | Risk Mitigated | Code Location |
|
||||
|---------|------|--------|----------------|---------------|
|
||||
| Origin Validation | Preventive | ✅ Implemented | CSRF, unauthorized access | Lines 255-263 |
|
||||
| Connection Limits | Preventive | ✅ Implemented | DoS (single IP) | Lines 308-315 |
|
||||
| Rate Limiting | Preventive | ✅ Implemented | Message flooding | Lines 265-279 |
|
||||
| Message Size Limits | Preventive | ✅ Implemented | DoS (large payloads) | Lines 338-342 |
|
||||
| Heartbeat Timeout | Preventive | ✅ Implemented | Zombie connections | Lines 320-329 |
|
||||
| Task Assignment Tracking | Detective | ✅ Implemented | Completion spoofing | Lines 222-229 |
|
||||
| Assignment Verification | Preventive | ✅ Implemented | Completion spoofing | Lines 411-423 |
|
||||
| Replay Prevention | Preventive | ✅ Implemented | Replay attacks | Lines 425-430 |
|
||||
| Self-Report Blocking | Preventive | ✅ Implemented | Credit fraud | Lines 612-622 |
|
||||
| Server-Only Crediting | Preventive | ✅ Implemented | Credit fraud | Lines 119-129 |
|
||||
| QDAG Ledger | Preventive | ✅ Implemented | Credit tampering | Lines 66-117 |
|
||||
| Task Expiration | Preventive | ✅ Implemented | Stale assignments | Lines 243-253 |
|
||||
| Signature Verification | Preventive | ❌ NOT Implemented | Identity spoofing | Lines 281-286 |
|
||||
| Challenge-Response | Preventive | ❌ NOT Implemented | Registration fraud | N/A |
|
||||
| Global Conn Limit | Preventive | ❌ NOT Implemented | Distributed DoS | N/A |
|
||||
|
||||
---
|
||||
|
||||
## Security Metrics Dashboard
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Edge-Net Security Metrics │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Overall Security Score: 85/100 │
|
||||
│ ████████████████████████████████░░░░░░░░ │
|
||||
│ │
|
||||
│ Authentication: 50/100 ⚠️ │
|
||||
│ ██████████████████████░░░░░░░░░░░░░░░░░░ │
|
||||
│ (Missing signature verification) │
|
||||
│ │
|
||||
│ Authorization: 100/100 ✅ │
|
||||
│ ████████████████████████████████████████ │
|
||||
│ (Task assignment verification excellent) │
|
||||
│ │
|
||||
│ Credit System: 100/100 ✅ │
|
||||
│ ████████████████████████████████████████ │
|
||||
│ (QDAG ledger architecture excellent) │
|
||||
│ │
|
||||
│ DoS Protection: 80/100 ✅ │
|
||||
│ ████████████████████████████████░░░░░░░░ │
|
||||
│ (Missing global connection limit) │
|
||||
│ │
|
||||
│ Data Integrity: 100/100 ✅ │
|
||||
│ ████████████████████████████████████████ │
|
||||
│ (Firestore source of truth) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recommendations Priority Matrix
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────────┐
|
||||
│ Impact vs Effort Matrix │
|
||||
│ │
|
||||
│ High Impact │ │
|
||||
│ ↑ │ 🔴 Signature │ │
|
||||
│ │ │ Verification │ │
|
||||
│ │ │ (CRITICAL) │ 🟡 Global Conn │
|
||||
│ │ │ │ Limit │
|
||||
│ │ ├──────────────────────┼──────────────────────────┤
|
||||
│ │ │ │ │
|
||||
│ │ │ 🟡 Completed Tasks │ 🟢 Error Messages │
|
||||
│ │ │ Cleanup │ Generic │
|
||||
│ │ │ │ │
|
||||
│ Low Impact │ │ │
|
||||
│ └──────────────────────┴──────────────────────────┘
|
||||
│ Low Effort → → → High Effort │
|
||||
└───────────────────────────────────────────────────────────────┘
|
||||
|
||||
Legend:
|
||||
🔴 Critical Priority (Do before production)
|
||||
🟡 Medium Priority (Do within 1-2 weeks)
|
||||
🟢 Low Priority (Nice to have)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Audit Trail Example
|
||||
|
||||
```
|
||||
Typical Secure Task Flow (with all security checks):
|
||||
|
||||
2026-01-03 10:15:23 [Relay] Node registered: node-abc-123 with identity 8a7f3d2e...
|
||||
2026-01-03 10:15:24 [Relay] Task submitted: task-456-xyz from node-abc-123
|
||||
2026-01-03 10:15:25 [Relay] Assigned task task-456-xyz to node-def-789
|
||||
↳ Assignment: {
|
||||
assignedTo: 'node-def-789',
|
||||
assignedToPublicKey: '8a7f3d2e...',
|
||||
submitter: 'node-abc-123',
|
||||
maxCredits: 2000000,
|
||||
assignedAt: 1735900525000
|
||||
}
|
||||
2026-01-03 10:17:30 [Relay] Task task-456-xyz VERIFIED completed by node-def-789
|
||||
↳ Security checks passed:
|
||||
✅ Task in assignedTasks
|
||||
✅ Node ID matches assignment
|
||||
✅ Not already completed
|
||||
✅ Public key available
|
||||
2026-01-03 10:17:31 [QDAG] Credited 0.002 rUv to 8a7f3d2e... for task task-456-xyz
|
||||
2026-01-03 10:17:32 [QDAG] Saved ledger for 8a7f3d2e...: earned=0.005
|
||||
|
||||
Rejected Attack Example:
|
||||
|
||||
2026-01-03 10:20:15 [SECURITY] Task task-456-xyz was assigned to node-def-789, not node-evil-999 - SPOOFING ATTEMPT
|
||||
2026-01-03 10:20:15 [Relay] Rejected task_complete from node-evil-999 (not assigned)
|
||||
2026-01-03 10:20:20 [SECURITY] Task task-456-xyz already completed - REPLAY ATTEMPT from node-def-789
|
||||
2026-01-03 10:20:20 [Relay] Rejected duplicate task_complete
|
||||
2026-01-03 10:20:25 [QDAG] REJECTED ledger_update from node-evil-999 - clients cannot self-report credits
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Last Updated**: 2026-01-03
|
||||
**Related Documents**:
|
||||
- Full Security Audit Report: `SECURITY_AUDIT_REPORT.md`
|
||||
- Quick Reference: `SECURITY_QUICK_REFERENCE.md`
|
||||
- Test Suite: `/tests/relay-security.test.ts`
|
||||
Reference in New Issue
Block a user