diff --git a/README.md b/README.md index c9ecbd23..c98ea245 100644 --- a/README.md +++ b/README.md @@ -49,5 +49,36 @@ For more details, see [PROJECT_ARCHITECTURE.md](PROJECT_ARCHITECTURE.md). --- +## 🔐 Security & Production Deployment + +### Critical Environment Variables +The application requires the following environment variables for production deployment: + +| Variable | Purpose | Example | +|----------|---------|---------| +| **JWT_SECRET_KEY** | JWT token signing key (REQUIRED for production) | `openssl rand -hex 32` | +| **ALLOWED_ORIGINS** | CORS-allowed domain origins (comma-separated) | `https://inventory.example.com,https://api.example.com` | +| **DATA_DIR** | SQLite database location | `/app/data` | +| **LOGS_DIR** | Application logs directory | `/app/logs` | + +**⚠️ IMPORTANT:** +- In development, `JWT_SECRET_KEY` defaults to an ephemeral random value, which is reset on restart. +- For production, set `JWT_SECRET_KEY` to a stable, long random string and store it in a secrets manager (AWS Secrets, HashiCorp Vault, etc.). +- `ALLOWED_ORIGINS` **must** be set to your actual production domain(s). Wildcard origins (`*`) are rejected when `allow_credentials=True`. + +### Docker Production Deployment +```bash +# Set environment variables +export JWT_SECRET_KEY="$(openssl rand -hex 32)" +export ALLOWED_ORIGINS="https://your-domain.com" + +# Launch stack +docker-compose up -d --build +``` + +For detailed security audit report, see [dev_docs/SECURITY_REPORT.md](dev_docs/SECURITY_REPORT.md). + +--- + ## 📜 AI Operational Rules AI agents working on this project MUST follow the guidelines in [AI_RULES.md](AI_RULES.md). diff --git a/dev_docs/SESSION_STATE.md b/dev_docs/SESSION_STATE.md index f5fe6b55..93f4dd0d 100644 --- a/dev_docs/SESSION_STATE.md +++ b/dev_docs/SESSION_STATE.md @@ -1,4 +1,4 @@ -# CURRENT AI WORKING SESSION — FINALIZAT +# CURRENT AI WORKING SESSION — COMPLETED **Active AI:** Claude (Sonnet 4.6) **Last Updated:** 2026-04-11 @@ -7,127 +7,128 @@ --- -## 🎯 SESIUNE COMPLETATĂ — TOȚI PAȘII FINALIZAȚI +## 🎯 SESSION COMPLETED — ALL TASKS FINALIZED -### Status Final +### Final Status -✅ **Audit de Securitate** — complet (12 vulnerabilități, 6 patch-uri directe) -✅ **[C-01] JWT Bearer Auth** — complet (backend + frontend) -✅ **[H-02] Rate Limiting** — complet (10 req/min pe /items/extract-label) -✅ **[M-01] CORS Config** — complet (ALLOWED_ORIGINS din env) -✅ **[L-01] Token Expiry** — complet (8h expirare JWT) +✅ **Security Audit** — complete (12 vulnerabilities, 6 direct patches) +✅ **[C-01] JWT Bearer Auth** — complete (backend + frontend) +✅ **[H-02] Rate Limiting** — complete (10 req/min on /items/extract-label) +✅ **[M-01] CORS Configuration** — complete (ALLOWED_ORIGINS from env) +✅ **[L-01] Token Expiry** — complete (8h JWT expiration) -### Commits (Sesiune) +### Session Commits -| Hash | Descriere | -|------|-----------| -| `247ea454` | security: audit + 6 patch-uri (C-02, C-03, H-01, H-03, M-01, M-03) | -| `9b6adad6` | feat: JWT Bearer auth pe toți routers | -| `e9ada004` | docs: UPDATE SESSION_STATE JWT complete | +| Hash | Description | +|------|-------------| +| `247ea454` | security: audit + 6 patches (C-02, C-03, H-01, H-03, M-01, M-03) | +| `9b6adad6` | feat: JWT Bearer auth on all routers | +| `e9ada004` | docs: update SESSION_STATE JWT complete | | `e6ca33f2` | feat: frontend JWT, rate limiting, CORS | +| `2574726f` | docs: final SESSION_STATE all tasks complete | --- -## 📋 Implementări Complete +## 📋 Complete Implementations ### Backend -#### Autentificare JWT [C-01] +#### JWT Authentication [C-01] - ✅ `backend/auth.py` — JWT creation, validation, role checking -- ✅ `/users/login` — returnează `TokenResponse` (access_token, user_id, role, expirare 8h) -- ✅ Toți routers-ii — `Depends(get_current_user)` enforce +- ✅ `/users/login` — returns `TokenResponse` (access_token, user_id, role, 8h expiry) +- ✅ All routers — `Depends(get_current_user)` enforcement - ✅ Admin-only endpoints — `Depends(get_current_admin)` -- ✅ user_id — extras din JWT token, NU din request body [M-02] +- ✅ user_id — extracted from JWT token, NOT from request body [M-02] #### Rate Limiting [H-02] -- ✅ `slowapi` integrat în requirements.txt +- ✅ `slowapi` integrated in requirements.txt - ✅ `/items/extract-label` — `@limiter.limit("10/minute")` per IP -- ✅ Protecție împotriva spam pe AI endpoint +- ✅ Protection against spam on AI endpoint -#### CORS Configurație [M-01] -- ✅ `ALLOWED_ORIGINS` din env var (fallback: localhost:3000, localhost:3002) -- ✅ Allow methods specific: GET, POST, PUT, DELETE, OPTIONS -- ✅ allow_credentials=True (valid cu specific origins) +#### CORS Configuration [M-01] +- ✅ `ALLOWED_ORIGINS` from environment variable (fallback: localhost:3000, localhost:3002) +- ✅ Specific HTTP methods: GET, POST, PUT, DELETE, OPTIONS +- ✅ allow_credentials=True (valid with specific origins) -#### Patch-uri Directe -- ✅ C-02 — Eliminat bypass password -- ✅ C-03 — Admin seed cu parola aleatoare +#### Direct Patches +- ✅ C-02 — Removed passwordless bypass +- ✅ C-03 — Admin seed with random password - ✅ H-01 — LDAP injection fix (escape_filter_chars) -- ✅ H-03 — MIME validation + 10MB limit upload -- ✅ M-03 — Logging LDAP via log.debug() +- ✅ H-03 — MIME validation + 10MB upload limit +- ✅ M-03 — LDAP logging via log.debug() ### Frontend #### JWT Handling [L-01] - ✅ `frontend/lib/auth.ts` — saveToken, getToken, getAuthHeader, clearAuth - ✅ Token storage — localStorage (inventory_token + inventory_user) -- ✅ Login page — salveaza TokenResponse din /users/login -- ✅ Token attach — Axios interceptor adauga `Authorization: Bearer ` pe toate cererile +- ✅ Login page — saves TokenResponse from /users/login +- ✅ Token attachment — Axios interceptor adds `Authorization: Bearer ` to all requests #### Token Expiry [L-01] - ✅ 401 Unauthorized → clearAuth() + redirect /login -- ✅ Interceptor pe axiosInstance -- ✅ Auto-logout pe expirare +- ✅ Interceptor on axiosInstance +- ✅ Auto-logout on expiration ### Deployment #### docker-compose.yml -- ✅ Backend environment vars: DATA_DIR, LOGS_DIR, ALLOWED_ORIGINS, JWT_SECRET_KEY -- ✅ Comentarii pentru producție -- ✅ Fallback values pentru development +- ✅ Backend environment variables: DATA_DIR, LOGS_DIR, ALLOWED_ORIGINS, JWT_SECRET_KEY +- ✅ Comments for production configuration +- ✅ Fallback values for development #### Environment Variables -| Var | Dev Default | Prod Requă | Purpose | -|-----|-------------|-----------|---------| -| ALLOWED_ORIGINS | localhost:3000, localhost:3002 | SETEAZĂ! | CORS origins | -| JWT_SECRET_KEY | ephemeral (random) | SETEAZĂ! | JWT signing key | -| DATA_DIR | /app/data | - | Database location | -| LOGS_DIR | /app/logs | - | Logs location | +| Variable | Dev Default | Production Required | Purpose | +|----------|-------------|-------------------|---------| +| ALLOWED_ORIGINS | localhost:3000, localhost:3002 | SET REQUIRED | CORS allowed origins | +| JWT_SECRET_KEY | ephemeral (random) | SET REQUIRED | JWT signing key | +| DATA_DIR | /app/data | - | SQLite database location | +| LOGS_DIR | /app/logs | - | Application logs location | --- -## 📊 Stare Vulnerabilități +## 📊 Vulnerability Status -| ID | Severitate | Descriere | Status | -|----|-----------|-----------|--------| -| C-01 | 🔴 CRITIC | Zero auth på API | ✅ PATCHAT (JWT) | -| C-02 | 🔴 CRITIC | Bypass fără parolă | ✅ PATCHAT | -| C-03 | 🔴 CRITIC | Parola default "admin" | ✅ PATCHAT | -| C-04 | 🔴 CRITIC | Gemini API key exposed | ✅ SAFE (never in git) | -| H-01 | 🟠 HIGH | LDAP injection | ✅ PATCHAT | -| H-02 | 🟠 HIGH | Rate limit missing | ✅ PATCHAT | -| H-03 | 🟠 HIGH | File upload validation | ✅ PATCHAT | -| H-04 | 🟠 HIGH | Admin endpoints exposed | ✅ PATCHAT (JWT) | -| M-01 | 🟡 MEDIUM | CORS wildcard | ✅ PATCHAT | -| M-02 | 🟡 MEDIUM | user_id dari body | ✅ PATCHAT | -| M-03 | 🟡 MEDIUM | Debug logging LDAP | ✅ PATCHAT | -| L-01 | 🔵 LOW | Token expiry | ✅ PATCHAT | +| ID | Severity | Description | Status | +|----|----------|-------------|--------| +| C-01 | 🔴 CRITICAL | Zero authentication on API | ✅ PATCHED (JWT) | +| C-02 | 🔴 CRITICAL | Passwordless user bypass | ✅ PATCHED | +| C-03 | 🔴 CRITICAL | Default "admin" password | ✅ PATCHED | +| C-04 | 🔴 CRITICAL | Gemini API key exposed | ✅ SAFE (never in git) | +| H-01 | 🟠 HIGH | LDAP injection | ✅ PATCHED | +| H-02 | 🟠 HIGH | Missing rate limit | ✅ PATCHED | +| H-03 | 🟠 HIGH | File upload validation | ✅ PATCHED | +| H-04 | 🟠 HIGH | Admin endpoints exposed | ✅ PATCHED (JWT) | +| M-01 | 🟡 MEDIUM | CORS wildcard | ✅ PATCHED | +| M-02 | 🟡 MEDIUM | user_id from body | ✅ PATCHED | +| M-03 | 🟡 MEDIUM | Debug LDAP logging | ✅ PATCHED | +| L-01 | 🔵 LOW | Token expiry | ✅ PATCHED | --- -## 🚀 Producție — Checklist +## 🚀 Production Deployment Checklist -**CRITICE — SETEAZĂ ÎNAINTE DE DEPLOY:** +**CRITICAL — Set these environment variables before deploy:** -- [ ] **JWT_SECRET_KEY** — Generează cu `openssl rand -hex 32` -- [ ] **ALLOWED_ORIGINS** — Setează originile reale (ex: https://inventory.example.com) -- [ ] **TLS/HTTPS** — Caddy proxy configurate cu certificat valid -- [ ] **Database backup** — SQLite data/ mappped la persistent volume -- [ ] **Logs rotation** — logs/ mappped și monitorizate +- [ ] **JWT_SECRET_KEY** — Generate with `openssl rand -hex 32` (store in secrets manager) +- [ ] **ALLOWED_ORIGINS** — Set to actual production domain(s), e.g., `https://inventory.example.com` +- [ ] **TLS/HTTPS** — Caddy proxy configured with valid SSL certificate +- [ ] **Database backup** — SQLite data/ mapped to persistent volume +- [ ] **Logs rotation** — logs/ mapped and monitored -**RECOMANDATE:** +**RECOMMENDED:** -- [ ] Setează log level → WARNING (nu DEBUG) -- [ ] Configureaza rate limiting pe alt nivel (nginx/cloudflare) pentru DDoS -- [ ] Monitorizare alertă pe 401 spikes (token expiry issues) -- [ ] Rotire periodică JWT_SECRET_KEY +- [ ] Set log level to WARNING (not DEBUG) +- [ ] Configure rate limiting at reverse proxy level (nginx/Cloudflare) for DDoS protection +- [ ] Monitor alert on 401 spikes (token expiry issues) +- [ ] Periodic JWT_SECRET_KEY rotation (quarterly minimum) --- -## 📝 Testing Local +## 🧪 Local Testing -### 1. Run Development Setup +### 1. Start Development Stack ```bash docker-compose up --build ``` @@ -136,25 +137,25 @@ docker-compose up --build ```bash curl -X POST http://localhost:8000/users/login \ -H "Content-Type: application/json" \ - -d '{"username": "Admin", "password": ""}' + -d '{"username": "Admin", "password": ""}' ``` -### 3. Test Protected Endpoint cu Token +### 3. Test Protected Endpoint with Token ```bash curl -H "Authorization: Bearer " \ http://localhost:8000/items/ ``` -### 4. Test 401 (token expired) +### 4. Test 401 Unauthorized (invalid token) ```bash -curl -H "Authorization: Bearer invalid" \ +curl -H "Authorization: Bearer invalid_token" \ http://localhost:8000/items/ -# Expect: 401 Unauthorized +# Expected: 401 Unauthorized ``` -### 5. Test Rate Limiting (extract-label) +### 5. Test Rate Limiting (extract-label endpoint) ```bash -# 11 cereri rapid — 11-a trebuie să fail cu 429 +# 11 requests rapid fire — 11th should fail with 429 for i in {1..15}; do curl -X POST -F "file=@image.jpg" \ -H "Authorization: Bearer " \ @@ -165,36 +166,54 @@ done --- -## ✅ Validări +## ✅ Validations Completed -- ✅ Backend complet securizat -- ✅ Frontend token handling complet -- ✅ Rate limiting pe AI endpoint -- ✅ CORS configurable -- ✅ Toți routers-ii au auth enforcement -- ✅ Token expiry + redirect login -- ✅ Admin role check funcțional -- ✅ LDAP injection protected +- ✅ Backend fully secured with JWT +- ✅ Frontend token handling complete +- ✅ Rate limiting on AI endpoint +- ✅ CORS configurable via environment +- ✅ All routers have authentication enforcement +- ✅ Token expiry with automatic login redirect +- ✅ Admin role checks functional +- ✅ LDAP injection protection - ✅ File upload validation -- ✅ Audit logging cu user_id din token +- ✅ Audit logging with user_id from token --- -## 🎓 Lecții Învățate +## 🎓 Key Learnings -1. **CORS cu credentials=True** — trebuie origins specifice, NU wildcard -2. **Rate limiting** — esențial pe endpoints costisitoare (AI) -3. **JWT expirare** — 8h e balanță bună între security + UX -4. **user_id din token** — elimină spoof-uri pe operații -5. **Debug logging** — PII leaks (DN-uri LDAP) dacă nu e grijă +1. **CORS with credentials=True** — requires specific origins, NOT wildcards +2. **Rate limiting** — essential on expensive endpoints (AI processing) +3. **JWT expiration** — 8h balances security vs. UX +4. **user_id from token** — eliminates operation spoofing +5. **Debug logging** — careful with PII leaks (LDAP DNs) --- -**Status:** 🚀 PRODUCTION-READY (cu caveate de config env pt prod) +## 📝 Production Environment Variables Example -**Următorii pași (OUT OF SCOPE):** -- Email verification pentru useri noi +```bash +# Set these before `docker-compose up` +export JWT_SECRET_KEY="$(openssl rand -hex 32)" +export ALLOWED_ORIGINS="https://inventory.example.com,https://api.example.com" + +docker-compose up -d +``` + +Or in `.env.production` (NOT in git): +``` +JWT_SECRET_KEY=abcdef1234567890... +ALLOWED_ORIGINS=https://inventory.example.com +``` + +--- + +**Status:** 🚀 PRODUCTION-READY (with environment configuration required) + +**Future Scope (OUT OF SCOPE):** +- Email verification for new users - 2FA/TOTP support -- OAuth2 federation (GitHub/Google) -- API key management pentru service accounts -- Audit log export/archival +- OAuth2 federation (GitHub/Google/Azure) +- API key management for service accounts +- Audit log export/archival to cold storage