Security Architecture
Security Principles
Section titled “Security Principles”| Principle | Implementation |
|---|---|
| Defense in Depth | TLS, JWT, RLS, Argon2id, CSP headers |
| Least Privilege | Role-based access control (RBAC) |
| Secure by Default | SQLx compile-time query validation |
| Fail Securely | Rust’s Result type for error handling |
| Zero Trust | JWT validation on every API call |
Authentication
Section titled “Authentication”Password Policy
Section titled “Password Policy”- Minimum 12 characters with uppercase, lowercase, digit, and special character
- Hashing: Argon2id with OWASP parameters: m=65536 (64 MiB), t=3, p=4
JWT Tokens
Section titled “JWT Tokens”Stateless authentication via JSON Web Tokens (HS256):
pub struct Claims { pub sub: String, // User ID pub exp: usize, // Expiration time pub iat: usize, // Issued at time pub role: UserRole, // User role}| Setting | Value |
|---|---|
| Access token expiration | 1 hour (default, configurable) |
| Refresh token expiration | 7 days |
| Revocation | Redis-backed (JTI denylist) |
| Secret | JWT_SECRET, minimum 32 characters |
Token storage by platform:
| Platform | Method |
|---|---|
| Web (Leptos) | HttpOnly cookies |
| Desktop (Tauri) | Secure storage API |
| Mobile (Tauri) | Keychain/Keystore |
Authorization
Section titled “Authorization”Role-Based Access Control (RBAC)
Section titled “Role-Based Access Control (RBAC)”pub enum UserRole { Admin, Moderator, Homeowner, Tenant, Developer,}Resource Access Matrix
Section titled “Resource Access Matrix”| Resource | Admin | Moderator | Homeowner | Developer | Tenant |
|---|---|---|---|---|---|
/admin/* | ✓ | ✗ | ✗ | ✗ | ✗ |
/moderator/* | ✓ | ✓ | ✗ | ✗ | ✗ |
/developer/* | ✓ | ✓ | ✗ | ✓ | ✗ |
/user/profile | ✓ | ✓ | ✓ | ✓ | ✓ |
/public/* | ✓ | ✓ | ✓ | ✓ | ✓ |
Row-Level Security
Section titled “Row-Level Security”PostgreSQL RLS policies enforce access at the database level on 5 tables — users, properties, bids, payments, and notifications — providing a second layer of defense beyond application-level RBAC.
Network Security
Section titled “Network Security”- Protocol: TLS 1.3
- Cipher Suites: AEAD only
- Certificates: Let’s Encrypt (auto-renewal via cert-manager)
- HSTS: Enabled with long max-age
Rate Limiting
Section titled “Rate Limiting”Redis-based, tiered per-endpoint limits:
| Tier | Requests | Period | Applied To |
|---|---|---|---|
| Auth | 15 | 60s | /auth/* |
| Public | 100 | 60s | /search/* |
| User | 1000 | 60s | All protected routes |
Limits are enforced per IP and per user. If Redis is unavailable, rate limiting degrades gracefully and all requests are allowed.
Explicit origin whitelist via the CORS_ALLOWED_ORIGINS environment variable (comma-separated). Never set to * in production.
CSRF protection via middleware with origin validation on state-changing requests.
Security Headers
Section titled “Security Headers”All API responses include:
| Header | Value |
|---|---|
Strict-Transport-Security | max-age=63072000; includeSubDomains; preload |
X-Frame-Options | DENY |
X-Content-Type-Options | nosniff |
Content-Security-Policy | default-src 'none'; connect-src 'self'; frame-ancestors 'none' |
Referrer-Policy | strict-origin-when-cross-origin |
Permissions-Policy | camera=(), microphone=(), geolocation=() |
Cross-Origin-Embedder-Policy | require-corp |
Cross-Origin-Opener-Policy | same-origin |
Application Security
Section titled “Application Security”Input Validation
Section titled “Input Validation”- Serde deserialization with
validatorderive macros - Ammonia HTML sanitization on user-generated content
- Parameterized SQL queries via SQLx (compile-time validated)
SQL Injection Prevention
Section titled “SQL Injection Prevention”SQLx validates all queries at compile time:
sqlx::query_as!( User, "SELECT id, email, role FROM users WHERE id = $1", user_id).fetch_one(pool).awaitXSS Prevention
Section titled “XSS Prevention”Leptos automatically escapes HTML output. No raw HTML rendering without explicit inner_html.
WebSocket Security
Section titled “WebSocket Security”- JWT authentication required in handshake
- Message type validation before processing
- Rate limiting on connections
Data Security
Section titled “Data Security”Encryption at Rest
Section titled “Encryption at Rest”- PostgreSQL Transparent Data Encryption (TDE) on production
pgcryptoextension for sensitive field encryption- Tauri secure storage for mobile/desktop secrets
Data Masking
Section titled “Data Masking”Sensitive fields are excluded from API responses via #[serde(skip)]:
pub struct UserPublic { pub id: i32, pub email: String, #[serde(skip)] pub password_hash: String,}“Fog of War” Visibility
Section titled ““Fog of War” Visibility”Aggregate data (bloc compositions, owner identities) is exposed only after escrow deposit, protecting negotiation privacy.
Payment Security
Section titled “Payment Security”- Cardholder data: processed entirely by Stripe (PCI DSS Level 1); never stored locally
- Bank payments: processed by TrueLayer, an FCA-authorised Payment Institution
- Webhook verification: HMAC-SHA256 signatures for both Stripe and TrueLayer deliveries
- Fee calculation: buyer pays on top with a transparent breakdown
Supply Chain Security
Section titled “Supply Chain Security”| Control | Tool |
|---|---|
| Dependency auditing | cargo-deny |
| Secret scanning | gitleaks |
| SBOM generation | Syft (SPDX-JSON) |
| Image signing | Cosign |
| Container scanning | Trivy |
Session Management
Section titled “Session Management”| Setting | Value |
|---|---|
| Session Timeout | 24 hours |
| Idle Timeout | 1 hour |
| Secure Flag | Enabled |
| SameSite | Strict |