Files
flaskpaste/SECURITY.md
Username 2679bc8e69
Some checks failed
CI / Lint & Format (push) Failing after 29s
CI / Unit Tests (push) Has been skipped
CI / Memory Leak Check (push) Has been skipped
CI / Fuzz Testing (push) Has been skipped
CI / SBOM Generation (push) Has been skipped
CI / Security Scan (push) Successful in 33s
CI / Security Tests (push) Has been skipped
CI / Advanced Security Tests (push) Has been skipped
CI / Build & Push Image (push) Has been skipped
CI / Harbor Vulnerability Scan (push) Has been skipped
docs: add url shortener documentation
2026-02-16 20:56:55 +01:00

293 lines
8.0 KiB
Markdown

# Security
FlaskPaste is designed with security as a primary concern. This document describes security features, best practices, and responsible disclosure procedures.
## Security Features
### Authentication
**Client Certificate Authentication (mTLS)**
FlaskPaste supports mutual TLS authentication via reverse proxy:
1. Reverse proxy terminates TLS and validates client certificates
2. Proxy extracts SHA1 fingerprint and passes via `X-SSL-Client-SHA1` header
3. FlaskPaste uses fingerprint for ownership tracking and authorization
```nginx
# nginx example
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header X-SSL-Client-SHA1 $ssl_client_fingerprint;
}
```
**Proxy Trust Validation**
Defense-in-depth against header spoofing:
```bash
export FLASKPASTE_PROXY_SECRET="shared-secret"
```
The proxy must send `X-Proxy-Secret` header; requests without valid secret are treated as anonymous.
### Password Protection
Pastes can be password-protected using PBKDF2-HMAC-SHA256:
- 600,000 iterations (OWASP 2023 recommendation)
- 32-byte random salt per password
- Constant-time comparison prevents timing attacks
- Passwords never logged or stored in plaintext
```bash
# Create protected paste
curl -H "X-Paste-Password: secret" --data-binary @file.txt https://paste.example.com/
# Access protected paste
curl -H "X-Paste-Password: secret" https://paste.example.com/abc123/raw
```
### End-to-End Encryption
CLI supports client-side AES-256-GCM encryption:
- Key generated locally, never sent to server
- Key appended to URL as fragment (`#key`) which browsers never transmit
- Server stores only opaque ciphertext
- Zero-knowledge: server cannot read content
```bash
./fpaste create -e secret.txt
# Returns: https://paste.example.com/abc123#<base64-key>
```
### Abuse Prevention
**Content-Hash Deduplication**
Prevents spam flooding by throttling repeated identical submissions:
```bash
FLASKPASTE_DEDUP_WINDOW=3600 # 1 hour window
FLASKPASTE_DEDUP_MAX=3 # Max 3 identical submissions
```
**Proof-of-Work**
Computational puzzle prevents automated spam:
```bash
FLASKPASTE_POW_DIFFICULTY=20 # Leading zero bits required
FLASKPASTE_POW_TTL=300 # Challenge validity (seconds)
```
**Entropy Enforcement**
Optional minimum entropy requirement to enforce encrypted uploads:
```bash
FLASKPASTE_MIN_ENTROPY=6.0 # Bits per byte (encrypted ~7.5-8.0)
FLASKPASTE_MIN_ENTROPY_SIZE=256 # Only check content >= this size
```
### URL Shortener Security
**Open Redirect Prevention**
Short URL creation validates target URLs:
- Only `http` and `https` schemes allowed (rejects `javascript:`, `data:`, `ftp:`, `file:`)
- Network location (hostname) required — rejects scheme-only URLs
- Maximum URL length: 2048 bytes
- Short IDs: 8-char base62 (`[a-zA-Z0-9]`) with `secrets.choice()` for unpredictability
- Redirect responses include `Cache-Control: no-store, no-cache` to prevent caching
**Access Controls**
- Creation: rate-limited + proof-of-work (same as paste creation)
- Redirect: lookup rate limiting prevents enumeration
- Deletion: owner authentication required
- Listing: authentication required, shows only own URLs
### Security Headers
All responses include:
| Header | Value |
|--------|-------|
| `Strict-Transport-Security` | `max-age=31536000; includeSubDomains` |
| `X-Content-Type-Options` | `nosniff` |
| `X-Frame-Options` | `DENY` |
| `X-XSS-Protection` | `1; mode=block` |
| `Content-Security-Policy` | `default-src 'none'` |
| `Referrer-Policy` | `no-referrer` |
| `Permissions-Policy` | `geolocation=(), microphone=(), camera=()` |
| `Cache-Control` | `no-store, no-cache, must-revalidate` |
| `Pragma` | `no-cache` |
### Request Tracing
All requests receive `X-Request-ID` header for log correlation and debugging. Pass your own ID to trace requests through reverse proxies.
## Input Validation
### Paste IDs
- Hexadecimal only (`[a-f0-9]+`)
- Configurable length (default 12 characters)
- Validated on all endpoints
### Short URL IDs
- Base62 only (`[a-zA-Z0-9]+`)
- 8 characters (configurable via `FLASKPASTE_SHORT_ID_LENGTH`)
- Validated on all `/s/` endpoints
### MIME Types
- Magic byte detection for binary formats
- Sanitized against injection
- Only safe characters allowed: `[a-z0-9!#$&\-^_.+]`
### Size Limits
```bash
FLASKPASTE_MAX_ANON=3145728 # 3 MiB for anonymous
FLASKPASTE_MAX_AUTH=52428800 # 50 MiB for authenticated
```
### Password Limits
- Maximum 1024 characters (prevents DoS via hashing)
- Unicode supported
- Special characters allowed
## SQL Injection Prevention
All database queries use parameterized statements:
```python
# Correct - parameterized
db.execute("SELECT * FROM pastes WHERE id = ?", (paste_id,))
# Never - string concatenation
db.execute(f"SELECT * FROM pastes WHERE id = '{paste_id}'")
```
## Database Security
- SQLite with WAL mode for better concurrency
- Foreign keys enforced
- Automatic cleanup of expired content
- No sensitive data in plaintext (passwords are hashed)
## Deployment Recommendations
### Reverse Proxy
Always deploy behind a TLS-terminating reverse proxy:
```
┌─────────┐ TLS ┌─────────┐ HTTP ┌───────────┐
│ Client │ ──────────── │ nginx │ ──────────── │ FlaskPaste│
│ │ mTLS opt │ HAProxy │ local │ │
└─────────┘ └─────────┘ └───────────┘
```
### Container Security
```dockerfile
# Run as non-root
USER app
# Read-only filesystem where possible
# Mount /app/data as writable volume
```
### Network Isolation
- FlaskPaste should only listen on localhost or internal network
- Reverse proxy handles external traffic
- Use firewall rules to restrict direct access
### Secrets Management
```bash
# Use strong, unique secrets
FLASKPASTE_PROXY_SECRET="$(openssl rand -hex 32)"
FLASKPASTE_POW_SECRET="$(openssl rand -hex 32)"
```
## Security Checklist
### Before Deployment
- [ ] Deploy behind TLS-terminating reverse proxy
- [ ] Configure `FLASKPASTE_PROXY_SECRET` if using auth headers
- [ ] Enable proof-of-work if public-facing
- [ ] Set appropriate size limits
- [ ] Configure paste expiry
### Ongoing
- [ ] Monitor logs for suspicious activity
- [ ] Keep dependencies updated
- [ ] Review access patterns
- [ ] Rotate secrets periodically
- [ ] Test backup/restore procedures
## Known Limitations
1. **No user accounts** - PKI handles identity
2. **Single-node only** - SQLite limits horizontal scaling
## Reporting Vulnerabilities
If you discover a security vulnerability:
1. **Do not** open a public issue
2. Email security concerns to the repository maintainer
3. Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We aim to acknowledge reports within 48 hours and provide a fix timeline within 7 days.
## Security Updates
Security fixes are released as soon as possible. Subscribe to repository releases for notifications.
## Threat Model
### In Scope
- Unauthorized access to pastes
- Content injection attacks
- Authentication bypass
- Information disclosure
- Denial of service (application-level)
- Open redirect via URL shortener
### Out of Scope
- Physical access to server
- Compromise of reverse proxy
- Client-side vulnerabilities
- Network-level DoS
- Social engineering
## Version History
| Version | Security Changes |
|---------|------------------|
| 1.6.0 | URL shortener with open redirect prevention, scheme allowlist, target URL validation |
| 1.5.0 | Pentest remediation (15 items): timing attack prevention, serial collision detection, lookup rate limiting, content hash locking, anti-flood memory limits, CLI path validation, SSL hostname verification, config permission checks |
| 1.4.0 | Anti-flood dynamic PoW, IP-based rate limiting, audit logging |
| 1.2.0 | Password protection with PBKDF2, code modernization |
| 1.1.0 | E2E encryption, entropy enforcement, burn-after-read |
| 1.0.0 | Initial release with core security features |