forked from username/flaskpaste
flaskpaste: initial commit with security hardening
Features: - REST API for text/binary pastes with MIME detection - Client certificate auth via X-SSL-Client-SHA1 header - SQLite with WAL mode for concurrent access - Automatic paste expiry with LRU cleanup Security: - HSTS, CSP, X-Frame-Options, X-Content-Type-Options - Cache-Control: no-store for sensitive responses - X-Request-ID tracing for log correlation - X-Proxy-Secret validation for defense-in-depth - Parameterized queries, input validation - Size limits (3 MiB anon, 50 MiB auth) Includes /health endpoint, container support, and 70 tests.
This commit is contained in:
173
README.md
Normal file
173
README.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# FlaskPaste
|
||||
|
||||
A lightweight, secure pastebin REST API built with Flask.
|
||||
|
||||
## Features
|
||||
|
||||
- **Simple REST API** - Create, retrieve, and delete pastes via HTTP
|
||||
- **Binary support** - Upload text, images, archives, and other binary content
|
||||
- **Automatic MIME detection** - Magic byte detection for common formats (PNG, JPEG, GIF, WebP, ZIP, PDF, GZIP)
|
||||
- **Client certificate authentication** - Optional auth via `X-SSL-Client-SHA1` header
|
||||
- **Automatic expiry** - Pastes expire after configurable period of inactivity
|
||||
- **Size limits** - Configurable limits for anonymous and authenticated users
|
||||
- **Security headers** - HSTS, CSP, X-Frame-Options, Cache-Control, and more
|
||||
- **Request tracing** - X-Request-ID support for log correlation
|
||||
- **Proxy trust validation** - Optional shared secret for defense-in-depth
|
||||
- **Minimal dependencies** - Flask only, SQLite built-in
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Clone and setup
|
||||
git clone <repository>
|
||||
cd flaskpaste
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run development server
|
||||
python run.py
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET /` | API information and usage |
|
||||
| `GET /health` | Health check (returns DB status) |
|
||||
| `POST /` | Create a new paste |
|
||||
| `GET /<id>` | Retrieve paste metadata |
|
||||
| `GET /<id>/raw` | Retrieve raw paste content |
|
||||
| `DELETE /<id>` | Delete paste (requires auth) |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Create a paste (raw text)
|
||||
```bash
|
||||
curl --data-binary @file.txt http://localhost:5000/
|
||||
```
|
||||
|
||||
### Create a paste (piped input)
|
||||
```bash
|
||||
echo "Hello, World!" | curl --data-binary @- http://localhost:5000/
|
||||
```
|
||||
|
||||
### Create a paste (JSON)
|
||||
```bash
|
||||
curl -H "Content-Type: application/json" \
|
||||
-d '{"content":"Hello from JSON!"}' \
|
||||
http://localhost:5000/
|
||||
```
|
||||
|
||||
### Retrieve paste metadata
|
||||
```bash
|
||||
curl http://localhost:5000/abc12345
|
||||
```
|
||||
|
||||
### Retrieve raw content
|
||||
```bash
|
||||
curl http://localhost:5000/abc12345/raw
|
||||
```
|
||||
|
||||
### Delete a paste (requires authentication)
|
||||
```bash
|
||||
curl -X DELETE \
|
||||
-H "X-SSL-Client-SHA1: <your-cert-fingerprint>" \
|
||||
http://localhost:5000/abc12345
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Configuration via environment variables:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `FLASK_ENV` | `development` | Environment (`development`, `production`, `testing`) |
|
||||
| `FLASKPASTE_DB` | `./data/pastes.db` | SQLite database path |
|
||||
| `FLASKPASTE_ID_LENGTH` | `12` | Paste ID length (hex characters) |
|
||||
| `FLASKPASTE_MAX_ANON` | `3145728` (3 MiB) | Max paste size for anonymous users |
|
||||
| `FLASKPASTE_MAX_AUTH` | `52428800` (50 MiB) | Max paste size for authenticated users |
|
||||
| `FLASKPASTE_EXPIRY` | `432000` (5 days) | Paste expiry in seconds |
|
||||
| `FLASKPASTE_PROXY_SECRET` | (empty) | Shared secret for proxy trust validation |
|
||||
|
||||
## Authentication
|
||||
|
||||
FlaskPaste uses client certificate authentication. When deployed behind a reverse proxy (nginx, Apache), configure the proxy to:
|
||||
|
||||
1. Terminate TLS and validate client certificates
|
||||
2. Extract the certificate SHA1 fingerprint
|
||||
3. Pass it via the `X-SSL-Client-SHA1` header
|
||||
|
||||
Example nginx configuration:
|
||||
```nginx
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header X-SSL-Client-SHA1 $ssl_client_fingerprint;
|
||||
}
|
||||
```
|
||||
|
||||
Authenticated users can:
|
||||
- Upload larger pastes (50 MiB vs 3 MiB)
|
||||
- Delete their own pastes
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### Using Gunicorn
|
||||
```bash
|
||||
pip install gunicorn
|
||||
gunicorn -w 4 -b 0.0.0.0:5000 wsgi:app
|
||||
```
|
||||
|
||||
### Using Podman/Docker
|
||||
```bash
|
||||
podman build -t flaskpaste .
|
||||
podman run -d -p 5000:5000 -v flaskpaste-data:/app/data flaskpaste
|
||||
```
|
||||
|
||||
See `Containerfile` for container build configuration.
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
pip install pytest pytest-cov
|
||||
pytest tests/ -v
|
||||
```
|
||||
|
||||
### Test Coverage
|
||||
```bash
|
||||
pytest tests/ --cov=app --cov-report=term-missing
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
```
|
||||
flaskpaste/
|
||||
├── app/
|
||||
│ ├── __init__.py # Flask app factory
|
||||
│ ├── config.py # Configuration classes
|
||||
│ ├── database.py # SQLite management
|
||||
│ └── api/
|
||||
│ ├── __init__.py # Blueprint setup
|
||||
│ └── routes.py # API endpoints
|
||||
├── tests/ # Test suite
|
||||
├── data/ # SQLite database
|
||||
├── run.py # Development server
|
||||
├── wsgi.py # Production WSGI entry
|
||||
├── Containerfile # Podman/Docker build
|
||||
└── requirements.txt # Dependencies
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Input validation** - Paste IDs are hex-only, auth headers validated
|
||||
- **MIME sanitization** - Content-Type headers are sanitized
|
||||
- **SQL injection protection** - Parameterized queries throughout
|
||||
- **Ownership enforcement** - Only owners can delete their pastes
|
||||
- **Size limits** - Prevents resource exhaustion attacks
|
||||
- **Security headers** - HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Cache-Control
|
||||
- **Request tracing** - X-Request-ID for log correlation and debugging
|
||||
- **Proxy trust** - Optional `X-Proxy-Secret` validation to prevent header spoofing
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user