Files
TimeTracker/docs/CSRF_CONFIGURATION.md
Dries Peeters 20824dbcb1 feat: Add customizable Kanban board columns and enhance CSRF configuration
This commit introduces a comprehensive Kanban board customization system and
improves CSRF token configuration for Docker deployments.

## Major Features

### 1. Customizable Kanban Board Columns
Add complete kanban column customization system allowing users to define
custom workflow states beyond the default columns.

**New Components:**
- Add KanbanColumn model with full CRUD operations (app/models/kanban_column.py)
- Add kanban routes blueprint with admin endpoints (app/routes/kanban.py)
- Add kanban column management templates (app/templates/kanban/)
- Add migration 019 for kanban_columns table (migrations/)

**Features:**
- Create unlimited custom columns with unique keys, labels, icons, and colors
- Drag-and-drop column reordering with position persistence
- Toggle column visibility without deletion
- Protected system columns (todo, in_progress, done) prevent accidental deletion
- Complete state marking for columns that should mark tasks as done
- Real-time updates via SocketIO broadcasts when columns change
- Font Awesome icon support (5000+ icons)
- Bootstrap color scheme integration
- Comprehensive validation and error handling

**Integration:**
- Update Task model to work with dynamic column statuses (app/models/task.py)
- Update task routes to use kanban column API (app/routes/tasks.py)
- Update project routes to fetch active columns (app/routes/projects.py)
- Add kanban column management links to base template (app/templates/base.html)
- Update kanban board templates to render dynamic columns (app/templates/tasks/)
- Add cache prevention headers to force fresh column data

**API Endpoints:**
- GET /api/kanban/columns - Fetch all active columns
- POST /api/kanban/columns/reorder - Reorder columns
- GET /kanban/columns - Column management interface (admin only)
- POST /kanban/columns/create - Create new column (admin only)
- POST /kanban/columns/<id>/edit - Edit column (admin only)
- POST /kanban/columns/<id>/delete - Delete column (admin only)
- POST /kanban/columns/<id>/toggle - Toggle column visibility (admin only)

### 2. Enhanced CSRF Configuration
Improve CSRF token configuration and documentation for Docker deployments.

**Configuration Updates:**
- Add WTF_CSRF_ENABLED environment variable to all docker-compose files
- Add WTF_CSRF_TIME_LIMIT environment variable with 1-hour default
- Update app/config.py to read CSRF settings from environment
- Add SECRET_KEY validation in app/__init__.py to prevent production deployment
  with default keys

**Docker Compose Updates:**
- docker-compose.yml: CSRF enabled by default for security testing
- docker-compose.remote.yml: CSRF always enabled in production
- docker-compose.remote-dev.yml: CSRF enabled with production-like settings
- docker-compose.local-test.yml: CSRF can be disabled for local testing
- Add helpful comments explaining each CSRF-related environment variable
- Update env.example with CSRF configuration examples

**Verification Scripts:**
- Add scripts/verify_csrf_config.sh for Unix systems
- Add scripts/verify_csrf_config.bat for Windows systems
- Scripts check SECRET_KEY, CSRF_ENABLED, and CSRF_TIME_LIMIT settings

### 3. Database Initialization Improvements
- Update app/__init__.py to run pending migrations on startup
- Add automatic kanban column initialization after migrations
- Improve error handling and logging during database setup

### 4. Configuration Management
- Update app/config.py with new CSRF and kanban-related settings
- Add environment variable parsing with sensible defaults
- Improve configuration validation and error messages

## Documentation

### New Documentation Files
- CUSTOM_KANBAN_README.md: Quick start guide for kanban customization
- KANBAN_CUSTOMIZATION.md: Detailed technical documentation
- IMPLEMENTATION_SUMMARY.md: Implementation details and architecture
- KANBAN_AUTO_REFRESH_COMPLETE.md: Real-time update system documentation
- KANBAN_REFRESH_FINAL_FIX.md: Cache and refresh troubleshooting
- KANBAN_REFRESH_SOLUTION.md: Technical solution for data freshness
- docs/CSRF_CONFIGURATION.md: Comprehensive CSRF setup guide
- CSRF_DOCKER_CONFIGURATION_SUMMARY.md: Docker-specific CSRF setup
- CSRF_TROUBLESHOOTING.md: Common CSRF issues and solutions
- APPLY_KANBAN_MIGRATION.md: Migration application guide
- APPLY_FIXES_NOW.md: Quick fix reference
- DEBUG_KANBAN_COLUMNS.md: Debugging guide
- DIAGNOSIS_STEPS.md: System diagnosis procedures
- BROWSER_CACHE_FIX.md: Browser cache troubleshooting
- FORCE_NO_CACHE_FIX.md: Cache prevention solutions
- SESSION_CLOSE_ERROR_FIX.md: Session handling fixes
- QUICK_FIX.md: Quick reference for common fixes

### Updated Documentation
- README.md: Add kanban customization feature description
- Update project documentation with new features

## Testing

### New Test Files
- test_kanban_refresh.py: Test kanban column refresh functionality

## Technical Details

**Database Changes:**
- New table: kanban_columns with 11 columns
- Indexes on: key, position
- Default data: 4 system columns (todo, in_progress, review, done)
- Support for both SQLite (development) and PostgreSQL (production)

**Real-Time Updates:**
- SocketIO events: 'kanban_columns_updated' with action type
- Automatic page refresh when columns are created/updated/deleted/reordered
- Prevents stale data by expiring SQLAlchemy caches after changes

**Security:**
- Admin-only access to column management
- CSRF protection on all column mutation endpoints
- API endpoints exempt from CSRF (use JSON and other auth mechanisms)
- System column protection prevents data integrity issues
- Validation prevents deletion of columns with active tasks

**Performance:**
- Efficient querying with position-based ordering
- Cached column data with cache invalidation on changes
- No-cache headers on API responses to prevent stale data
- Optimized database indexes for fast lookups

## Breaking Changes

None. This is a fully backward-compatible addition.

Existing workflows continue to work with the default columns.
Custom columns are opt-in via the admin interface.

## Migration Notes

1. Run migration 019 to create kanban_columns table
2. Default columns are initialized automatically on first run
3. No data migration needed for existing tasks
4. Existing task statuses map to new column keys

## Environment Variables

New environment variables (all optional with defaults):
- WTF_CSRF_ENABLED: Enable/disable CSRF protection (default: true)
- WTF_CSRF_TIME_LIMIT: CSRF token expiration in seconds (default: 3600)
- SECRET_KEY: Required in production, must be cryptographically secure

See env.example for complete configuration reference.

## Deployment Notes
2025-10-11 19:56:45 +02:00

227 lines
6.3 KiB
Markdown

# CSRF Token Configuration for Docker
This document explains how CSRF (Cross-Site Request Forgery) protection is configured in TimeTracker when running in Docker containers.
## Overview
TimeTracker uses Flask-WTF's `CSRFProtect` extension to protect against CSRF attacks. CSRF tokens are cryptographic tokens that ensure forms are submitted by legitimate users from your application, not from malicious third-party sites.
## How CSRF Tokens Work
1. When a user visits a page with a form, the server generates a unique CSRF token
2. This token is embedded in the form (usually as a hidden field)
3. When the form is submitted, the token is sent back to the server
4. The server validates the token matches what was originally generated
5. If the token is invalid or missing, the request is rejected with a 400 error
## Critical: SECRET_KEY Configuration
**CSRF tokens are signed using the Flask `SECRET_KEY`.** This means:
- ✅ The same `SECRET_KEY` must be used across container restarts
- ✅ The same `SECRET_KEY` must be used if you run multiple app replicas
- ⚠️ If `SECRET_KEY` changes, all existing CSRF tokens become invalid
- ⚠️ Users will get CSRF errors on form submissions if the key changes
### Generating a Secure SECRET_KEY
Generate a cryptographically secure random key:
```bash
python -c "import secrets; print(secrets.token_hex(32))"
```
### Setting SECRET_KEY in Docker
#### Option 1: Environment Variable File
Create a `.env` file (do not commit this to git):
```bash
SECRET_KEY=your-generated-key-here
```
Then run docker-compose:
```bash
docker-compose up -d
```
#### Option 2: Export Environment Variable
```bash
export SECRET_KEY="your-generated-key-here"
docker-compose up -d
```
#### Option 3: Docker Secrets (Production Recommended)
For production deployments with Docker Swarm or Kubernetes, use secrets management:
```yaml
secrets:
secret_key:
external: true
services:
app:
secrets:
- secret_key
environment:
- SECRET_KEY_FILE=/run/secrets/secret_key
```
## CSRF Configuration Variables
### WTF_CSRF_ENABLED
Controls whether CSRF protection is enabled.
- **Default in Production**: `true`
- **Default in Development**: `false` (for easier testing)
- **Recommended**: Keep enabled in production
Set in docker-compose:
```yaml
environment:
- WTF_CSRF_ENABLED=true
```
### WTF_CSRF_TIME_LIMIT
Time in seconds before a CSRF token expires.
- **Default**: `3600` (1 hour)
- **Range**: Set to `null` for no expiration, or any positive integer
Set in docker-compose:
```yaml
environment:
- WTF_CSRF_TIME_LIMIT=3600
```
## Docker Compose Files
### docker-compose.yml (Local Development)
```yaml
environment:
# CSRF enabled by default for security testing
- WTF_CSRF_ENABLED=${WTF_CSRF_ENABLED:-true}
- WTF_CSRF_TIME_LIMIT=${WTF_CSRF_TIME_LIMIT:-3600}
- SECRET_KEY=${SECRET_KEY:-your-secret-key-change-this}
```
### docker-compose.remote.yml (Production)
```yaml
environment:
# CSRF always enabled in production
- WTF_CSRF_ENABLED=${WTF_CSRF_ENABLED:-true}
- WTF_CSRF_TIME_LIMIT=${WTF_CSRF_TIME_LIMIT:-3600}
- SECRET_KEY=${SECRET_KEY:-your-secret-key-change-this}
```
**Important**: The app will refuse to start in production mode with the default `SECRET_KEY`.
### docker-compose.local-test.yml (Testing)
```yaml
environment:
# CSRF can be disabled for local testing
- WTF_CSRF_ENABLED=${WTF_CSRF_ENABLED:-false}
- WTF_CSRF_TIME_LIMIT=${WTF_CSRF_TIME_LIMIT:-3600}
- SECRET_KEY=${SECRET_KEY:-local-test-secret-key}
```
## Verifying CSRF Protection
### Check if CSRF is Enabled
Look at the application logs when starting:
```bash
docker-compose logs app | grep -i csrf
```
### Test CSRF Protection
1. Open your browser's developer tools
2. Navigate to a form in TimeTracker
3. Look for a hidden input field: `<input type="hidden" name="csrf_token" value="...">`
4. Try submitting the form without the token (should fail with 400 error)
### Common Issues
#### Issue: "CSRF token missing or invalid"
**Cause**: One of the following:
- `SECRET_KEY` changed between token generation and validation
- Token expired (check `WTF_CSRF_TIME_LIMIT`)
- Clock skew between server and client
- Browser cookies disabled or blocked
**Solution**:
1. Check `SECRET_KEY` is consistent
2. Verify `WTF_CSRF_ENABLED=true`
3. Ensure cookies are enabled
4. Check system time is synchronized
#### Issue: Forms work in development but not in production Docker
**Cause**: Missing or misconfigured `SECRET_KEY`
**Solution**:
1. Set a proper `SECRET_KEY` in your `.env` file
2. Verify the environment variable is passed to the container:
```bash
docker-compose exec app env | grep SECRET_KEY
```
#### Issue: CSRF tokens expire too quickly
**Cause**: `WTF_CSRF_TIME_LIMIT` too short
**Solution**: Increase the time limit or disable expiration:
```yaml
environment:
- WTF_CSRF_TIME_LIMIT=7200 # 2 hours
```
## API Endpoints
The `/api/*` endpoints are **exempted from CSRF protection** because they use JSON and are designed for programmatic access. They rely on other authentication mechanisms instead.
## Security Best Practices
1. ✅ **Always use a strong SECRET_KEY in production**
2. ✅ **Keep SECRET_KEY secret** - never commit to version control
3. ✅ **Use the same SECRET_KEY across all app replicas**
4. ✅ **Enable CSRF protection in production** (`WTF_CSRF_ENABLED=true`)
5. ✅ **Use HTTPS in production** for secure cookie transmission
6. ✅ **Set appropriate cookie security flags**:
- `SESSION_COOKIE_SECURE=true` (HTTPS only)
- `SESSION_COOKIE_HTTPONLY=true` (no JavaScript access)
- `SESSION_COOKIE_SAMESITE=Lax` (CSRF defense)
## Additional Resources
- [Flask-WTF CSRF Protection](https://flask-wtf.readthedocs.io/en/stable/csrf.html)
- [OWASP CSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)
- [Flask Security Considerations](https://flask.palletsprojects.com/en/2.3.x/security/)
## Summary
For CSRF tokens to work correctly in Docker:
1. **Set a strong SECRET_KEY** and keep it consistent
2. **Enable CSRF protection** with `WTF_CSRF_ENABLED=true`
3. **Configure timeout** appropriately with `WTF_CSRF_TIME_LIMIT`
4. **Use HTTPS in production** with secure cookie flags
5. **Never change SECRET_KEY** without understanding the impact
All docker-compose files have been updated with these settings and include helpful comments.