Security Features
HyperTor includes several security features to protect both clients and services. These are enabled by default where appropriate.
Overview
| Feature | Purpose | Default |
|---|---|---|
| Vanguards-lite | Protects guard relays from discovery | Enabled |
| Proof of Work | Prevents DDoS attacks on services | Off |
| Traffic Padding | Prevents traffic analysis | Configurable |
| Circuit Isolation | Separates different activities | Session-based |
| Rate Limiting | Controls request rates | Per-connection |
Vanguards-lite
What it protects against: Guard enumeration attacks that could deanonymize hidden services.
Tor uses “guard” relays as the first hop for all circuits. If an attacker can identify your guards, they can narrow down your location. Vanguards adds additional layers of protection.
How It Works
- Layer 2 Guards — A small set of relays used after the guard
- Rotation Policy — Guards rotate slowly, making enumeration expensive
- Persistent Selection — Guards persist across restarts
Configuration
// Enabled by default for OnionApp
let app = OnionApp::builder()
.vanguards_enabled(true) // Default
.vanguards_full(false) // Use lite mode
.build();
In Python:
app = OnionApp(
vanguards_enabled=True, # Default
vanguards_full=False # Use lite mode
)
Vanguards Modes
| Mode | Protection | Overhead |
|---|---|---|
| Lite (default) | Good protection, low overhead | ~10% more circuit build time |
| Full | Maximum protection | ~30% more circuit build time |
| Off | No additional protection | Baseline performance |
Proof of Work (PoW)
What it protects against: DDoS attacks and resource exhaustion.
When enabled, clients must solve a computational puzzle before connecting to your service. This makes attacks expensive while legitimate users pay only a small one-time cost.
How It Works
- Client requests connection
- Server sends PoW challenge
- Client solves puzzle (requires CPU work)
- Server verifies solution
- Connection proceeds
The difficulty adjusts automatically based on server load.
Configuration
let app = OnionApp::builder()
.pow_enabled(true)
.pow_target_bits(20) // Base difficulty
.pow_adaptive(true) // Auto-adjust to load
.pow_queue_size(100) // Max pending challenges
.build();
In Python:
app = OnionApp(
pow_enabled=True,
pow_target_bits=20, # Base difficulty
pow_adaptive=True, # Auto-adjust to load
pow_queue_size=100 # Max pending challenges
)
Difficulty Levels
| Target Bits | Time to Solve | Use Case |
|---|---|---|
| 16 | ~50ms | Light protection |
| 20 | ~500ms | Default, balanced |
| 24 | ~5s | High-value services |
| 28 | ~1min | Extreme protection |
Client Support
The TorClient automatically handles PoW challenges:
// Client automatically solves PoW if required
let resp = client.get("http://protected-service.onion")?
.send().await?;
# Client automatically solves PoW if required
resp = await client.get("http://protected-service.onion")
Traffic Padding
What it protects against: Traffic analysis attacks that correlate traffic patterns.
Traffic padding adds dummy data to mask the real traffic patterns, making it harder for observers to correlate your activity.
Configuration
let client = TorClient::builder()
.padding_enabled(true)
.padding_mode(PaddingMode::Normal) // or Reduced, Maximum
.build().await?;
In Python:
client = TorClient(
padding_enabled=True,
padding_mode="normal" # or "reduced", "maximum"
)
Padding Modes
| Mode | Description | Overhead |
|---|---|---|
Reduced |
Minimal padding | ~5% bandwidth |
Normal |
Balanced protection | ~15% bandwidth |
Maximum |
Full protection | ~30% bandwidth |
Circuit Isolation
What it protects against: Activity correlation across different operations.
Circuit isolation ensures different activities use different Tor circuits, preventing observers from linking them together.
Isolation Levels
use hypertor::{TorClient, IsolationLevel};
let client = TorClient::builder()
.isolation(IsolationLevel::PerSession) // Default
.build().await?;
| Level | Description | Use Case |
|---|---|---|
None |
All requests share circuits | Maximum performance |
PerSession |
Circuits per client instance | Default, balanced |
PerRequest |
Fresh circuit per request | Maximum privacy |
PerHost |
Circuits per destination | Multi-service |
Custom Isolation
Group related requests together while isolating from others:
use hypertor::IsolationToken;
// Create isolation groups
let session_a = IsolationToken::new();
let session_b = IsolationToken::new();
// These share a circuit
client.get("http://a.onion")?.isolation(session_a.clone()).send().await?;
client.get("http://a.onion/page")?.isolation(session_a.clone()).send().await?;
// This uses a different circuit
client.get("http://a.onion")?.isolation(session_b.clone()).send().await?;
Rate Limiting
Built-in rate limiting for services:
use hypertor::middleware::RateLimit;
use std::time::Duration;
let app = OnionApp::new();
// Global rate limit: 100 requests per minute per connection
app.middleware(RateLimit::new(100, Duration::from_secs(60)));
// Per-route rate limit
app.get("/api/expensive", expensive_handler)
.rate_limit(10, Duration::from_secs(60));
In Python:
from hypertor import OnionApp, RateLimit
from datetime import timedelta
app = OnionApp()
# Global rate limit
app.use(RateLimit(requests=100, window=timedelta(minutes=1)))
# Per-route rate limit
@app.get("/api/expensive", rate_limit=RateLimit(10, timedelta(minutes=1)))
async def expensive(request):
...
Security Best Practices
For Hidden Services
- Enable Proof of Work for public services
- Use Vanguards (enabled by default)
- Set rate limits appropriate for your use case
- Persist keys to maintain identity
- Monitor connections for anomalies
let app = OnionApp::builder()
.pow_enabled(true)
.pow_target_bits(20)
.vanguards_enabled(true)
.connection_limit(100)
.key_path("/secure/path/to/keys")
.build();
For Clients
- Use circuit isolation for sensitive operations
- Enable padding if traffic analysis is a concern
- Don’t reuse client instances for unrelated activities
- Handle timeouts gracefully — Tor can be slow
let client = TorClient::builder()
.isolation(IsolationLevel::PerRequest)
.padding_enabled(true)
.timeout(Duration::from_secs(60))
.build().await?;
Security Considerations
What HyperTor Protects
- ✅ IP address of client and server
- ✅ Network observer seeing connection endpoints
- ✅ Traffic content (encrypted)
- ✅ Guard enumeration (with Vanguards)
- ✅ DDoS attacks (with PoW)
- ✅ DNS leaks (all DNS via Tor exit automatically)
- ✅ Circuit path vulnerabilities (analysis via
circuitsmodule)
What HyperTor Does NOT Protect
- ❌ Application-level data leaks (if you put your name in POST body)
- ❌ Malware on your system
- ❌ Human error in operational security
- ❌ Compromised exit nodes (for clearnet access - use TLS)
- ❌ Side-channel attacks on your hardware
Design Philosophy
HyperTor is an HTTP client library, not a browser. Browser-level concerns like:
- Canvas/WebGL fingerprinting
- WebRTC leaks
- Font enumeration
- Plugin detection
…do not apply to an HTTP client. DNS resolution is handled automatically via Tor exit nodes by the underlying arti library — there is no way for DNS to leak if you use TorClient.
Additional Recommendations
- Keep dependencies updated — Security vulnerabilities get patched
- Use memory-safe code — HyperTor is written in Rust with
#![forbid(unsafe_code)] - Minimize logging — Logs can deanonymize users
- Sanitize user input — Same as any web application
- Use HTTPS in addition to Tor — Defense in depth
- Don’t add identifying headers — Avoid
X-Forwarded-For, customUser-Agent
Next Steps
- TorClient Documentation — HTTP client for Tor
- OnionApp Documentation — Host hidden services
- Python Bindings — Full Python API reference