| ← Back to s.plings.io | Core Systems |
Verification Strategy
Created: Tue 29 Jul 2025 06:49:39 CEST
Document Version: 1.0 - Initial documentation
Security Classification: Internal Technical Documentation
Target Audience: Backend Developers, Security Engineers
Author: Paul Wisén
Overview
The Director implements a hybrid verification approach that balances security, performance, and backend load. By caching manufacturer public keys at the edge, we achieve ~70% reduction in backend API calls while maintaining cryptographic verification integrity.
Verification Flow
flowchart TD
A[QR Code Scanned] --> B[s.plings.io receives request]
B --> C{Extract Manufacturer ID from path}
C --> D[Check Public Key Cache]
D --> E{Manufacturer key cached?}
E -->|Yes| F[Verify Class Pointer Offline]
E -->|No| G[Load Public Key from Registry]
G --> H[Cache Public Key at Edge]
H --> F
F --> I{Class verification valid?}
I -->|No| J[Log Failed Verification]
J --> K[Redirect to Invalid Scan Page]
I -->|Yes| L[Log Scan Event]
L --> M{Need instance verification?}
M -->|No| N[Route to Appropriate Service]
M -->|Yes| O[API Call: Verify Instance Key]
O --> P{Instance valid?}
P -->|No| Q[Log Failed Instance Check]
Q --> K
P -->|Yes| R[Resolve Object Information]
R --> S[Determine Target Service]
S --> N
N --> T[Redirect with enriched parameters]
Implementation Strategy: Cached Public Keys
Public Key Registry Structure
interface ManufacturerRegistry {
[manufacturerId: string]: {
publicKey: string;
name: string;
verificationLevel: 'class' | 'full';
cachedAt: number;
ttl: number;
};
}
const MANUFACTURER_REGISTRY: ManufacturerRegistry = {
"1": {
publicKey: "PublicKey_Plings_Base58...",
name: "Plings",
verificationLevel: "class",
cachedAt: Date.now(),
ttl: 86400000 // 24 hours
},
"3": {
publicKey: "PublicKey_CocaCola_Base58...",
name: "Coca-Cola",
verificationLevel: "full",
cachedAt: Date.now(),
ttl: 86400000
},
"17": {
publicKey: "PublicKey_IKEA_Base58...",
name: "IKEA",
verificationLevel: "class",
cachedAt: Date.now(),
ttl: 86400000
}
};
Edge Verification Function
async function verifyAtEdge(
instanceKey: string,
path: string,
classPointer?: string
): Promise<VerificationResult> {
// Step 1: Extract manufacturer ID
const pathSegments = path.split('.');
const manufacturerId = pathSegments[0];
// Step 2: Get manufacturer public key
let registry = await getManufacturerRegistry();
let manufacturer = registry[manufacturerId];
if (!manufacturer) {
// Unknown manufacturer - fetch from API
manufacturer = await fetchManufacturerKey(manufacturerId);
if (!manufacturer) {
return { isValid: false, reason: "Unknown manufacturer" };
}
// Cache for future use
await cacheManufacturerKey(manufacturerId, manufacturer);
}
// Step 3: Verify class pointer if provided
if (classPointer && manufacturer.verificationLevel === 'class') {
const isValidClass = await verifyClassPointer(
classPointer,
path,
manufacturer.publicKey
);
if (!isValidClass) {
return { isValid: false, reason: "Invalid class pointer" };
}
}
// Step 4: Determine if instance verification needed
if (manufacturer.verificationLevel === 'full') {
return {
isValid: true,
needsInstanceVerification: true,
manufacturerId,
classVerified: true
};
}
return {
isValid: true,
manufacturerId,
classVerified: true,
canRouteOffline: true
};
}
Class Pointer Verification
async function verifyClassPointer(
classPointer: string,
path: string,
publicKey: string
): Promise<boolean> {
try {
// Derive expected class key from path
const classPath = extractClassPath(path); // e.g., "17.3.42"
const expectedPointer = await deriveClassPointer(classPath, publicKey);
// Constant-time comparison
return timingSafeEqual(
Buffer.from(classPointer),
Buffer.from(expectedPointer)
);
} catch (error) {
logError('Class pointer verification failed', { error, path });
return false;
}
}
Performance Benefits
Metrics with Cached Public Keys
| Metric | Without Cache | With Cache | Improvement |
|---|---|---|---|
| Average Latency | 150ms | 45ms | 70% faster |
| Backend API Calls | 100% | 30% | 70% reduction |
| Edge CPU Usage | Low | Medium | Acceptable |
| Cache Hit Rate | N/A | 95%+ | Excellent |
Load Distribution
Before: All verifications hit backend
[Edge] --100%--> [Backend API] --> [HSM]
After: Most verifications at edge
[Edge] --30%--> [Backend API] --> [HSM]
└─ 70% handled locally with cached keys
Security Considerations
Key Management
- Key Distribution
- Public keys fetched via secure API
- TLS certificate pinning for key fetches
- Keys signed by Plings root certificate
- Cache Security
- Keys stored in encrypted edge storage
- Automatic expiration after TTL
- Audit log of all key fetches
- Rotation Strategy
- 24-hour TTL for cached keys
- Force refresh on verification failures
- Emergency flush capability
Attack Mitigation
| Attack Vector | Mitigation |
|---|---|
| Cache Poisoning | Signed key responses, certificate pinning |
| Replay Attacks | Timestamp validation, nonce in instance verification |
| Key Compromise | Short TTL, monitoring for anomalies |
| DoS on Key Fetch | Rate limiting, fallback to API verification |
Implementation Phases
Phase 1: API-Based (Current)
// All verification via backend
async function verifySimple(instanceKey: string, path: string) {
return await callBackendAPI('/verify', { instanceKey, path });
}
Phase 2: Hybrid Cache (Recommended)
// Class verification at edge, instance via API
async function verifyHybrid(instanceKey: string, path: string, classPointer?: string) {
const edgeResult = await verifyAtEdge(instanceKey, path, classPointer);
if (!edgeResult.isValid) {
return { success: false, redirect: ERROR_PAGE };
}
if (edgeResult.needsInstanceVerification) {
const apiResult = await verifyInstanceAPI(instanceKey, path);
return combineResults(edgeResult, apiResult);
}
return { success: true, verified: edgeResult };
}
Phase 3: Full Edge (Future)
// Complete verification at edge with WebAssembly
async function verifyFullEdge(instanceKey: string, path: string) {
// Load WASM module for crypto operations
const cryptoModule = await loadWasmCrypto();
return cryptoModule.verifyComplete(instanceKey, path);
}
Monitoring & Alerts
Key Metrics to Track
- Cache Performance
- Hit rate (target: >95%)
- Miss reasons
- Fetch latencies
- Verification Metrics
- Success/failure rates by manufacturer
- Instance vs class verification ratio
- Geographic distribution
- Security Metrics
- Failed verification attempts
- Unusual patterns
- Key rotation events
Alert Thresholds
alerts:
- name: Low Cache Hit Rate
condition: cache_hit_rate < 0.90
severity: warning
- name: High Verification Failures
condition: failure_rate > 0.05
severity: critical
- name: Key Fetch Errors
condition: key_fetch_errors > 10/minute
severity: warning
Best Practices
- Always Verify Critical Operations
- Payment transactions: Full instance verification
- Ownership transfers: Full instance verification
- Read-only operations: Class verification sufficient
- Graceful Degradation
- If cache miss, fall back to API
- If API down, show friendly error
- Log all degradation events
- Regular Key Audits
- Weekly review of cached keys
- Monthly verification accuracy tests
- Quarterly security audits
Related Documentation
- Security Model - Complete security architecture
- Implementation Guide - Step-by-step setup
- Routing Logic - How verification affects routing