# Verification Security Model ## Attack Prevention: Signature Copying ### The Threat **Question**: What if Bob copies Alice's verification to his profile? ```json // Alice's profile (did:plc:alice123) { "verifications": [ { "type": "phone", "verifiedBy": "did:web:coves.social", "verifiedAt": "2025-01-15T10:00:00Z", "expiresAt": "2026-01-15T10:00:00Z", "signature": "abc123..." } ] } // Bob copies this to his profile (did:plc:bob456) // Will this work? NO! ``` ### The Defense The signature is created over this payload: ``` type + verifiedBy + verifiedAt + expiresAt + subjectDID ``` **Critical**: `subjectDID` is the DID of the person being verified. ### Example **Alice's signature payload:** ``` "phone" + "did:web:coves.social" + "2025-01-15T10:00:00Z" + "2026-01-15T10:00:00Z" + "did:plc:alice123" → Signature: "abc123..." ``` **Bob tries to use Alice's verification:** ``` Bob's DID: did:plc:bob456 Alice's signature: "abc123..." Third-party app verifies: payload = "phone" + "did:web:coves.social" + "2025-01-15T10:00:00Z" + "2026-01-15T10:00:00Z" + "did:plc:bob456" verify(payload, "abc123...", publicKey) → FALSE ❌ The signature doesn't match because Bob's DID is different from Alice's DID! ``` ### Implementation **Service (when creating signature):** ```go // service.go:216-222 verificationData := &VerificationData{ Type: "phone", VerifiedBy: s.signer.GetVerifierDID(), VerifiedAt: now, ExpiresAt: expiresAt, SubjectDID: did, // ← This binds it to the user } ``` **Third-party app (when verifying):** ```javascript // Reconstruct the EXACT same payload const payload = verification.type + verification.verifiedBy + verification.verifiedAt + verification.expiresAt + profileOwnerDID // ← MUST use the profile owner's DID // Verify signature const isValid = verifyECDSA(payload, verification.signature, publicKey) ``` ## Other Attack Vectors ### 1. Replay Attack (Using old verification) **Defense**: Expiry timestamp (`expiresAt`) is part of signed payload - Clients check `expiresAt < now()` → reject - Annual re-verification ensures freshness ### 2. Forged Signature **Defense**: ECDSA P-256 signature with private key known only to Coves - Attacker would need Coves' private key - Private key stored in secure environment (secrets manager) - Can't be brute-forced (256-bit security) ### 3. Man-in-the-Middle (DID document swap) **Defense**: HTTPS + optional DID pinning - DID document served over HTTPS - Clients can pin Coves' DID public key in app - DNS/TLS security prevents MITM ### 4. Verification Badge Removal **Defense**: User controls their own PDS - Only the user (or authorized apps with OAuth) can modify their profile - AppView writes via OAuth (with user consent) - Other apps can't remove verifications without permission ### 5. Phone Number Reuse (Carrier recycling) **Defense**: Expiry + re-verification - Verifications expire after 1 year - If carrier recycles number to new person, old verification expires - New person must verify to get new badge ### 6. SMS Interception (SIM swap) **Defense**: Rate limiting + audit logging - Max 3 OTP requests per phone per hour - Audit logs track suspicious patterns - Future: Add 2FA backup methods (email, authenticator) ### 7. Phone Hash Rainbow Table **Defense**: HMAC with secret pepper ```go phoneHash = HMAC-SHA256(phoneNumber, secretPepper) ``` - Even if DB is leaked, attacker can't reverse hashes without pepper - Pepper stored separately (environment variable) - Prevents bulk phone number enumeration ## Verification Lifecycle Security ### Creation 1. ✅ User authenticates with OAuth 2. ✅ AppView verifies phone ownership (OTP) 3. ✅ AppView creates signature (includes subject DID) 4. ✅ AppView writes to user's PDS (OAuth scope) 5. ✅ AppView stores phone_hash (duplicate prevention) ### Validation (Third-party apps) 1. ✅ Fetch user's profile from PDS 2. ✅ Extract verification from `verifications` array 3. ✅ Fetch Coves DID document (public key) 4. ✅ Reconstruct payload (including profile owner DID) 5. ✅ Verify signature matches 6. ✅ Check expiry timestamp ### Revocation 1. ✅ User loses phone → requests revocation 2. ✅ AppView removes verification from PDS 3. ✅ AppView deletes phone_hash from DB 4. ✅ Third-party apps see no verification (fetching latest from PDS) ## did:web Security ### Why `.well-known/did.json` is Safe **Q**: Can someone just change the DID document? **A**: No, because: 1. **Domain ownership**: Only owner of `coves.social` can serve files at `https://coves.social/.well-known/did.json` 2. **HTTPS**: TLS prevents MITM attacks 3. **Key rotation**: If private key compromised, we rotate (keep old key for 30 days for existing verifications) ### Alternative: DNS TXT Record We could also add a DNS TXT record for extra verification: ``` _did.coves.social TXT "did=did:web:coves.social key=" ``` This provides defense-in-depth (DNS + HTTPS both need to be compromised). ## Comparison to Other Verification Systems ### Twitter Blue (Centralized) - ❌ Phone stored on Twitter servers - ❌ Not portable (can't take verification to other apps) - ❌ Twitter controls badge (can remove) - ✅ Simple to verify (just trust Twitter) ### Bluesky Verification (Domain-based) - ✅ Decentralized (DNS TXT record) - ✅ Portable (works across apps) - ❌ Only works for domain owners - ❌ No phone verification ### Coves Verification (Hybrid) - ✅ Privacy-first (phone never stored) - ✅ Portable (PDS-stored, cryptographically signed) - ✅ Works for non-domain owners - ✅ Third-party verifiable (public key in DID document) - ✅ User-controlled (badge on their PDS) - ⚠️ Requires crypto verification (more complex for clients) ## Security Checklist When implementing, ensure: - [ ] Private key stored securely (secrets manager, not in code) - [ ] Phone hash pepper never changes (backup safely) - [ ] OTP generated with `crypto/rand` (not `math/rand`) - [ ] OTP comparison is constant-time (bcrypt) - [ ] Subject DID included in signature payload - [ ] Third-party apps verify signature correctly - [ ] Rate limits enforced at network edge - [ ] Audit logs don't leak phone numbers - [ ] HTTPS enforced for DID document - [ ] PDS writes use OAuth (user consent) ## Future Enhancements ### 1. Multi-factor Verification Require 2+ verification types: - Phone + Email - Phone + Domain - Government ID + Phone ### 2. Verification Revocation List Publish revoked verifications at `https://coves.social/.well-known/revocations.json` - Third-party apps can check if verification was revoked - User privacy preserved (DID hash, not full DID) ### 3. Hardware Security Module (HSM) Store signing key in HSM for production: - AWS CloudHSM - Google Cloud KMS - Azure Key Vault Prevents key extraction even with server compromise. ## Questions? Open an issue or ask on Discord!