diff --git a/documentation/security-testing-status.md b/documentation/security-testing-status.md index 6af4ee3..9cdc136 100644 --- a/documentation/security-testing-status.md +++ b/documentation/security-testing-status.md @@ -203,7 +203,7 @@ Not tested (no signature defined): ``` [ ] Add remaining MIME test results to security assessment [ ] Document rate limiting behavior under attack -[ ] Create threat model diagram +[x] Create threat model diagram (documentation/threat-model.md) [x] Add security headers audit to CI pipeline ``` diff --git a/documentation/threat-model.md b/documentation/threat-model.md new file mode 100644 index 0000000..42beecf --- /dev/null +++ b/documentation/threat-model.md @@ -0,0 +1,287 @@ +# FlaskPaste Threat Model + +Security architecture, attack surfaces, and mitigations for FlaskPaste. + +--- + +## System Architecture + +``` + INTERNET + | + +-----------+-----------+ + | HAProxy/nginx | + | (TLS termination) | + +-----------+-----------+ + | + +-----------+-----------+ + | FlaskPaste | + | (Flask + Gunicorn) | + +-----------+-----------+ + | + +-----------+-----------+ + | SQLite DB | + | (paste storage) | + +-----------------------+ +``` + +### Trust Boundaries + +``` ++----------------------------------------------------------------+ +| UNTRUSTED ZONE | +| - Anonymous users | +| - Public internet | ++----------------------------------------------------------------+ + | + [TLS + PoW Challenge] + | ++----------------------------------------------------------------+ +| SEMI-TRUSTED ZONE | +| - HAProxy/nginx reverse proxy | +| - Rate limiting enforcement | ++----------------------------------------------------------------+ + | + [X-Proxy-Secret validation] + | ++----------------------------------------------------------------+ +| TRUSTED ZONE | +| - Flask application | +| - SQLite database | +| - PKI CA (if enabled) | ++----------------------------------------------------------------+ +``` + +--- + +## Attack Surface Analysis + +### Entry Points + +| Entry Point | Protocol | Auth | Rate Limited | Description | +|-------------|----------|------|--------------|-------------| +| POST / | HTTPS | Optional | Yes | Create paste | +| GET /{id} | HTTPS | Optional | Yes | View paste metadata | +| GET /{id}/raw | HTTPS | Optional | Yes | View raw content | +| HEAD /{id} | HTTPS | None | Yes | Check existence | +| DELETE /{id} | HTTPS | Required | Yes | Delete paste | +| GET /challenge | HTTPS | None | Yes | Get PoW challenge | +| POST /pki/* | HTTPS | Required | Yes | PKI operations | +| GET /metrics | HTTPS | None | No | Prometheus metrics | +| GET /health | HTTPS | None | No | Health check | + +### Data Flows + +``` +User Input Flow: ++--------+ +-------+ +---------+ +--------+ +| Client | --> | Proxy | --> | Flask | --> | SQLite | ++--------+ +-------+ +---------+ +--------+ + | | | + | [Rate Limit] [Validation] + | | | + +-- PoW -------+ [MIME detect] + +-- Password --+--------[PBKDF2 hash] + +-- Content ---+--------[Size check] + +-- mTLS cert -+--------[SHA1 verify] +``` + +--- + +## Threat Actors + +### Anonymous Attacker +- **Motivation:** Abuse, DoS, content injection +- **Capabilities:** Automated tools, botnets +- **Mitigations:** PoW, rate limiting, anti-flood + +### Authenticated Attacker +- **Motivation:** Data exfiltration, privilege escalation +- **Capabilities:** Valid credentials, API access +- **Mitigations:** Ownership checks, audit logging + +### Malicious Operator +- **Motivation:** Credential theft, data access +- **Capabilities:** Proxy access, log access +- **Mitigations:** X-Proxy-Secret, no plaintext passwords + +### Sophisticated Attacker +- **Motivation:** Zero-day exploitation, APT +- **Capabilities:** Reverse engineering, timing attacks +- **Mitigations:** Constant-time operations, defense in depth + +--- + +## Threat Categories (STRIDE) + +### Spoofing + +| Threat | Vector | Mitigation | Status | +|--------|--------|------------|--------| +| Client identity spoofing | Forge X-SSL-Client-SHA1 | X-Proxy-Secret validation | MITIGATED | +| IP address spoofing | Forge X-Forwarded-For | Proxy secret required | MITIGATED | +| Paste ownership claim | Guess owner cert SHA1 | 40-char hex, DB lookup | MITIGATED | + +### Tampering + +| Threat | Vector | Mitigation | Status | +|--------|--------|------------|--------| +| Content modification | MITM attack | TLS 1.3 required | MITIGATED | +| Paste content tampering | Direct DB access | File permissions, no shell access | MITIGATED | +| PoW token replay | Reuse solved challenge | Token expiration (60s) | MITIGATED | + +### Repudiation + +| Threat | Vector | Mitigation | Status | +|--------|--------|------------|--------| +| Deny paste creation | No audit trail | Audit logging with X-Request-ID | MITIGATED | +| Deny deletion | Claim not deleted | Audit log with operator ID | MITIGATED | + +### Information Disclosure + +| Threat | Vector | Mitigation | Status | +|--------|--------|------------|--------| +| Paste enumeration | Sequential IDs | Random hex IDs (64-bit entropy) | MITIGATED | +| Password-protected content | Brute force | PBKDF2 600k iterations, rate limit | MITIGATED | +| Timing oracle on passwords | Response time variance | Constant-time comparison | MITIGATED | +| Burn-after-read race | HEAD then GET | HEAD triggers deletion | MITIGATED | +| Metrics exposure | /metrics endpoint | Public by design (no PII) | ACCEPTED | + +### Denial of Service + +| Threat | Vector | Mitigation | Status | +|--------|--------|------------|--------| +| Request flooding | High volume requests | Rate limiting (per-IP) | MITIGATED | +| Content spam | Large pastes | Size limits (100KB anon, 10MB auth) | MITIGATED | +| Memory exhaustion | Unbounded dicts | MAX_ENTRIES caps (10000) | MITIGATED | +| CPU exhaustion | Complex operations | PoW offloads to client | MITIGATED | +| Anti-flood bypass | Distributed attack | Dynamic PoW (16-28 bits) | MITIGATED | +| Content hash bypass | Unique content | Dedup window + PoW | MITIGATED | + +### Elevation of Privilege + +| Threat | Vector | Mitigation | Status | +|--------|--------|------------|--------| +| Delete others' pastes | Guess owner ID | Ownership verification | MITIGATED | +| Bypass size limits | Forge auth header | X-Proxy-Secret required | MITIGATED | +| PKI CA compromise | Unauthorized cert issue | Client cert required | MITIGATED | +| SQL injection | Malformed input | Parameterized queries | MITIGATED | +| SSTI | Template injection | No user content in templates | MITIGATED | +| Command injection | Shell escape | No shell execution | MITIGATED | + +--- + +## Security Controls Matrix + +``` ++---------------------+------------------------------------------+ +| Layer | Controls | ++---------------------+------------------------------------------+ +| Network | TLS 1.3, mTLS (optional), X-Proxy-Secret | +| Transport | Security headers, CSP, X-Frame-Options | +| Application | Input validation, MIME detection, PoW | +| Session | Stateless, no cookies, no CSRF needed | +| Data | PBKDF2 passwords, random IDs, expiry | +| Audit | Request ID tracking, structured logging | +| Operations | Rate limiting, anti-flood, size limits | ++---------------------+------------------------------------------+ +``` + +--- + +## MIME Detection Security + +Content is detected by magic bytes, not user-supplied Content-Type: + +``` +User uploads "image.png" with PHP payload + | + v +[Magic byte detection] --> Not PNG magic --> text/plain + | +[X-Content-Type-Options: nosniff] --> Browser won't sniff + | +[CSP: default-src 'none'] --> No script execution +``` + +### Polyglot Attack Mitigations + +| Attack | Detection | Result | +|--------|-----------|--------| +| PNG + HTML | PNG magic detected | image/png | +| GIF + JS | GIF magic detected | image/gif | +| PDF + ZIP | PDF magic detected | application/pdf | +| SVG + script | No XML magic | text/plain | +| JPEG + PHP | JPEG magic detected | image/jpeg | + +--- + +## Cryptographic Controls + +| Purpose | Algorithm | Parameters | +|---------|-----------|------------| +| Password hashing | PBKDF2-SHA256 | 600,000 iterations | +| Paste ID generation | secrets.token_hex | 32 chars (128 bits) | +| PoW challenge | SHA-256 | Variable difficulty (16-28 bits) | +| HMAC verification | hmac.compare_digest | Constant-time | +| PKI certificates | RSA-2048 / ECDSA P-256 | SHA-256 signing | + +--- + +## Residual Risks + +### Accepted Risks + +| Risk | Justification | Monitoring | +|------|---------------|------------| +| Metrics exposed | No PII, needed for monitoring | Access logs | +| Anonymous paste creation | Core functionality | Rate limiting | +| Content storage | User-provided, may be malicious | MIME detection | + +### Known Limitations + +| Limitation | Impact | Workaround | +|------------|--------|------------| +| TAR detection | ustar at offset 257 | Falls back to text/plain | +| Java .class files | 0xCAFEBABE = Mach-O | Falls back to Mach-O | +| Large file DoS | Memory during upload | Gunicorn body limit | + +--- + +## Audit Compliance + +| Control | Evidence | Frequency | +|---------|----------|-----------| +| Input validation | Unit tests | Every commit (CI) | +| Rate limiting | Integration tests | Every commit (CI) | +| Security headers | headers_audit.py | Every commit (CI) | +| Injection prevention | Fuzz tests | Every commit (CI) | +| Timing attacks | Timing tests | Weekly | +| Penetration testing | pentest_session.py | Monthly | + +--- + +## Incident Response + +### Detection Points + +- `/metrics` - Request rates, error rates, PoW difficulty +- Audit logs - Unusual patterns, failed auth attempts +- Anti-flood - Difficulty increase indicates attack + +### Response Actions + +| Trigger | Automatic Response | Manual Response | +|---------|-------------------|-----------------| +| High request rate | PoW difficulty increase | Review logs, block IPs | +| Failed auth spike | Rate limit enforcement | Investigate, rotate certs | +| Large paste flood | Size limit rejection | Block IP range | +| Enumeration attempt | 400 responses | Add to blocklist | + +--- + +## Version History + +| Date | Change | +|------|--------| +| 2025-12-26 | Initial threat model |