Prevent slot blocking and reservation spam: - RateLimiter: per-sender cooldowns, hourly limits, pending caps - ProofOfWork: Hashcash-style PoW for reservation requests - SenderReputation: track honor rate, no-shows, auto-block - TherapistPolicy: configurable requirements per provider - 7 new tests (39 total) Docs: docs/anti-abuse.md with implementation roadmap
217 lines
6.6 KiB
Markdown
217 lines
6.6 KiB
Markdown
# Anti-Abuse: Preventing Slot Blocking
|
|
|
|
## Problem
|
|
|
|
Bad actors could abuse the reservation system by:
|
|
1. **Slot Squatting**: Reserving slots with no intention to attend
|
|
2. **Denial of Service**: Mass-reserving to block legitimate patients
|
|
3. **Competitor Sabotage**: Blocking a therapist's calendar
|
|
4. **Spam Queries**: Flooding the network with fake queries
|
|
|
|
## Defense Layers
|
|
|
|
### Layer 1: Rate Limiting (Protocol Level)
|
|
|
|
```rust
|
|
pub struct RateLimits {
|
|
/// Max reservations per sender per hour
|
|
pub max_reservations_per_hour: u8, // Default: 3
|
|
/// Max pending (unconfirmed) reservations per sender
|
|
pub max_pending_reservations: u8, // Default: 2
|
|
/// Min time between reservations (seconds)
|
|
pub reservation_cooldown_secs: u32, // Default: 300 (5 min)
|
|
/// Max queries per sender per minute
|
|
pub max_queries_per_minute: u8, // Default: 10
|
|
}
|
|
```
|
|
|
|
**Implementation**: Each relay tracks sender activity and drops excessive requests.
|
|
|
|
### Layer 2: Reservation Deposits (Economic)
|
|
|
|
Require a small proof-of-work or micro-deposit to make reservations:
|
|
|
|
| Method | Cost to Attacker | UX Impact |
|
|
|--------|------------------|-----------|
|
|
| **Hashcash PoW** | CPU time (~1-5s per reservation) | Slight delay |
|
|
| **Token Stake** | Loses stake on no-show | Requires token system |
|
|
| **Reputation Bond** | Loses reputation on abuse | Requires history |
|
|
|
|
**Recommended**: Start with Hashcash PoW — no external dependencies.
|
|
|
|
```rust
|
|
pub struct ReservationProof {
|
|
/// Hashcash proof-of-work (20-bit difficulty)
|
|
pub pow_nonce: u64,
|
|
/// Hash must start with N zero bits
|
|
pub difficulty: u8,
|
|
}
|
|
|
|
impl ReservationProof {
|
|
pub fn verify(&self, reservation_id: &[u8; 16]) -> bool {
|
|
let hash = sha256([reservation_id, &self.pow_nonce.to_le_bytes()].concat());
|
|
leading_zeros(&hash) >= self.difficulty
|
|
}
|
|
}
|
|
```
|
|
|
|
### Layer 3: Confirmation Requirements
|
|
|
|
Therapists can require confirmation steps:
|
|
|
|
```rust
|
|
pub enum ConfirmationMode {
|
|
/// Auto-confirm (trust network)
|
|
AutoConfirm,
|
|
/// Require patient to solve CAPTCHA-like challenge
|
|
ChallengeResponse { challenge: Vec<u8> },
|
|
/// Require callback to verify contact
|
|
ContactVerification { method: ContactMethod },
|
|
/// Manual review by therapist
|
|
ManualReview,
|
|
}
|
|
```
|
|
|
|
### Layer 4: No-Show Tracking
|
|
|
|
Track reservation outcomes per sender:
|
|
|
|
```rust
|
|
pub struct SenderReputation {
|
|
pub address: [u8; 16],
|
|
pub reservations_made: u32,
|
|
pub reservations_honored: u32,
|
|
pub reservations_cancelled: u32, // With notice
|
|
pub no_shows: u32, // Without notice
|
|
pub last_no_show: Option<u64>,
|
|
}
|
|
|
|
impl SenderReputation {
|
|
pub fn honor_rate(&self) -> f32 {
|
|
if self.reservations_made == 0 { return 0.5; }
|
|
(self.reservations_honored as f32) / (self.reservations_made as f32)
|
|
}
|
|
|
|
pub fn is_blocked(&self) -> bool {
|
|
self.no_shows >= 3 || self.honor_rate() < 0.5
|
|
}
|
|
}
|
|
```
|
|
|
|
**Therapists can share blocklists** via signed messages:
|
|
|
|
```rust
|
|
pub struct BlocklistEntry {
|
|
pub blocked_address: [u8; 16],
|
|
pub reason: BlockReason,
|
|
pub reported_by: [u8; 16],
|
|
pub signature: [u8; 64],
|
|
pub timestamp: u64,
|
|
}
|
|
|
|
pub enum BlockReason {
|
|
NoShow,
|
|
Spam,
|
|
Harassment,
|
|
FakeIdentity,
|
|
}
|
|
```
|
|
|
|
### Layer 5: Reservation Limits per Therapist
|
|
|
|
Therapists set their own limits:
|
|
|
|
```rust
|
|
pub struct TherapistPolicy {
|
|
/// Max pending reservations from new senders
|
|
pub max_pending_new: u8, // Default: 1
|
|
/// Max pending from established senders
|
|
pub max_pending_established: u8, // Default: 3
|
|
/// Require verification level for reservations
|
|
pub min_verification_level: u8, // 0 = any, 2 = peer-endorsed
|
|
/// Auto-reject senders with low honor rate
|
|
pub min_honor_rate: f32, // Default: 0.7
|
|
}
|
|
```
|
|
|
|
## Implementation Roadmap
|
|
|
|
### Phase 1: Basic Rate Limiting (Week 1)
|
|
- [ ] Add `RateLimiter` to `ServiceRouter`
|
|
- [ ] Track per-sender reservation counts
|
|
- [ ] Drop excessive requests with `ServiceAction::RateLimited`
|
|
|
|
### Phase 2: Proof-of-Work (Week 2)
|
|
- [ ] Add `ReservationProof` to reserve message payload
|
|
- [ ] Verify PoW before processing reservation
|
|
- [ ] Adaptive difficulty based on network load
|
|
|
|
### Phase 3: Reputation System (Week 3-4)
|
|
- [ ] `SenderReputation` storage
|
|
- [ ] Honor/no-show reporting from therapists
|
|
- [ ] Blocklist propagation
|
|
|
|
### Phase 4: Therapist Policies (Week 4+)
|
|
- [ ] Policy field in `SlotAnnounce`
|
|
- [ ] Policy enforcement in reservation handling
|
|
|
|
## Example: Complete Anti-Abuse Flow
|
|
|
|
```
|
|
Patient Relay Therapist
|
|
| | |
|
|
|-- Query (CBT, 104xx) -->| |
|
|
|<-- Matches (3 slots) ---| |
|
|
| | |
|
|
|-- Reserve (slot_id) --->| |
|
|
| + PoW proof | |
|
|
| (1.2s computation) | |
|
|
| |-- Check rate limit ------>|
|
|
| | (OK: 1st today) |
|
|
| |-- Check reputation ------>|
|
|
| | (OK: new sender, 0.5) |
|
|
| |-- Forward reserve ------->|
|
|
| | |
|
|
| |<-- Confirm (pending) -----|
|
|
|<-- Pending -------------| |
|
|
| | |
|
|
| [Patient attends] | |
|
|
| |<-- Outcome: honored ------|
|
|
| | (reputation += 1) |
|
|
```
|
|
|
|
## Edge Cases
|
|
|
|
### New Users (No History)
|
|
|
|
- Allow 1 pending reservation
|
|
- Require PoW
|
|
- Lower priority than established users
|
|
|
|
### Therapist Gaming the System
|
|
|
|
- Therapists could falsely report no-shows
|
|
- Mitigation: Require mutual confirmation (patient confirms attendance too)
|
|
- Weight reports by reporter reputation
|
|
|
|
### Sybil Attacks (Many Fake Identities)
|
|
|
|
- Each identity requires new Ed25519 keypair
|
|
- PoW per reservation makes mass-blocking expensive
|
|
- Cross-relay blocklist sharing limits damage
|
|
|
|
## Privacy Considerations
|
|
|
|
- Reputation is tied to mesh address, not real identity
|
|
- No-show reports don't reveal appointment details
|
|
- Blocklists only contain addresses + reason, not personal data
|
|
|
|
## Metrics to Monitor
|
|
|
|
| Metric | Healthy Range | Alert Threshold |
|
|
|--------|---------------|-----------------|
|
|
| Reservation/Confirm ratio | > 0.8 | < 0.5 |
|
|
| Unique senders per relay | Growing | Flat with high volume |
|
|
| PoW rejection rate | < 5% | > 20% |
|
|
| Blocklist growth | Slow | Rapid spike |
|