DEV1.0: Initial commit - Workflow Portal with security fixes

- Backend: Express.js + PostgreSQL/SQLite with LDAP/AD integration
- Frontend: React 18 + Vite + TailwindCSS/DaisyUI
- Security fixes applied (2026-07 + 2026-08):
  - LDAP injection prevention, CSRF protection, HttpOnly cookies
  - Session hashing (SHA-256), account lockout, rate limiting
  - Input validation (zod), file upload security, CSP/HSTS headers
  - V3: express-rate-limit updated (ip-address SSRF fix)
  - V4: postcss updated (nanoid DoS fix)
  - V5: Rate-limit on /health endpoint
  - V6: Session rotation on login (session fixation prevention)
  - V9: Task values array limit (DoS prevention)
  - V10: Frontend XSS audit completed
- Docker: Multi-stage build, non-root user, PostgreSQL + backup service
This commit is contained in:
Kühn
2026-08-24 09:45:28 +02:00
commit 6be1791c62
103 changed files with 12253 additions and 0 deletions

91
docker-compose.yml Normal file
View File

@@ -0,0 +1,91 @@
services:
app:
build: .
ports:
- "5000:5000"
volumes:
- ./backend/data:/app/data
environment:
- LDAP_SERVER=${LDAP_SERVER:-}
- LDAP_PORT=${LDAP_PORT:-389}
- LDAP_SEARCH_BASE=${LDAP_SEARCH_BASE:-}
- LDAP_DOMAIN=${LDAP_DOMAIN:-}
- LDAP_IGNORE_CERT_ERRORS=${LDAP_IGNORE_CERT_ERRORS:-false}
- LDAP_BIND_USER=${LDAP_BIND_USER:-}
- LDAP_BIND_PASSWORD=${LDAP_BIND_PASSWORD:-}
- LDAP_SYNC_INTERVAL=${LDAP_SYNC_INTERVAL:-300000}
- LDAP_FILTER=${LDAP_FILTER:-}
- LDAP_ATTRIBUTES=${LDAP_ATTRIBUTES:-mail,displayName,memberOf,distinguishedName,sAMAccountName}
- LDAP_CREATE_OU=${LDAP_CREATE_OU:-}
- LDAP_UPN_SUFFIX=${LDAP_UPN_SUFFIX:-}
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@workflow.local}
- ADMIN_INIT_PASSWORD=${ADMIN_INIT_PASSWORD:-}
- CORS_ORIGIN=${CORS_ORIGIN:-http://localhost:5000}
- NODE_ENV=${NODE_ENV:-production}
# Punkt 4: PostgreSQL (auto-started)
- DATABASE_URL=postgresql://${POSTGRES_USER:-workflow}:${POSTGRES_PASSWORD:-workflow}@db:5432/${POSTGRES_DB:-workflow}
# Punkt 9: Session-Limitierung
- SESSION_MAX_PER_USER=${SESSION_MAX_PER_USER:-5}
- SESSION_TTL_HOURS=${SESSION_TTL_HOURS:-168}
# Punkt 12: Account-Lockout
- LOGIN_MAX_ATTEMPTS=${LOGIN_MAX_ATTEMPTS:-5}
- LOGIN_LOCKOUT_MINUTES=${LOGIN_LOCKOUT_MINUTES:-15}
# Punkt 14: Body-Size-Limit
- BODY_LIMIT=${BODY_LIMIT:-1mb}
depends_on:
db:
condition: service_healthy
restart: unless-stopped
# Punkt 4: PostgreSQL Database (auto-started)
db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=${POSTGRES_DB:-workflow}
- POSTGRES_USER=${POSTGRES_USER:-workflow}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-workflow}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-workflow} -d ${POSTGRES_DB:-workflow}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
# Punkt 5: DB-Backup Service (auto-started)
db-backup:
image: postgres:16-alpine
environment:
- POSTGRES_USER=${POSTGRES_USER:-workflow}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-workflow}
- POSTGRES_DB=${POSTGRES_DB:-workflow}
- BACKUP_INTERVAL_HOURS=${BACKUP_INTERVAL_HOURS:-6}
- BACKUP_RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-30}
- PGHOST=db
- PGUSER=${POSTGRES_USER:-workflow}
- PGPASSWORD=${POSTGRES_PASSWORD:-workflow}
volumes:
- ./backups:/backups
entrypoint: |
/bin/sh -c "
echo '[Backup] Starting backup service (interval: '$$BACKUP_INTERVAL_HOURS'h, retention: '$$BACKUP_RETENTION_DAYS'd)';
while true; do
TIMESTAMP=$$(date +%Y%m%d_%H%M%S);
FILENAME=/backups/workflow_$$TIMESTAMP.sql.gz;
echo '[Backup] Creating backup: '$$FILENAME;
pg_dump -h db -U $$PGUSER $$POSTGRES_DB | gzip > $$FILENAME;
echo '[Backup] Done: '$$FILENAME;
find /backups -name 'workflow_*.sql.gz' -mtime +$$BACKUP_RETENTION_DAYS -delete;
echo '[Backup] Cleaned old backups (older than '$$BACKUP_RETENTION_DAYS' days)';
SLEEP_SECONDS=$$((BACKUP_INTERVAL_HOURS * 3600));
sleep $$SLEEP_SECONDS;
done
"
depends_on:
db:
condition: service_healthy
restart: unless-stopped
volumes:
pgdata: