mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-21 22:32:22 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
254 lines
15 KiB
Markdown
254 lines
15 KiB
Markdown
# Polityka bezpieczeństwa
|
|
|
|
## Zgłaszanie luk bezpieczeństwa
|
|
|
|
Jeśli odkryjesz lukę bezpieczeństwa w OmniRoute, zgłoś ją w odpowiedzialny sposób:
|
|
|
|
1. **NIE** otwieraj publicznego zgłoszenia (issue) na GitHub
|
|
2. Użyj [GitHub Security Advisories](https://github.com/diegosouzapw/OmniRoute/security/advisories/new)
|
|
3. Dołącz: opis, kroki reprodukcji oraz potencjalny wpływ
|
|
|
|
## Harmonogram reakcji
|
|
|
|
| Etap | Cel |
|
|
| ---------------- | ---------------------------- |
|
|
| Potwierdzenie | 48 godzin |
|
|
| Triage i ocena | 5 dni roboczych |
|
|
| Wydanie poprawki | 14 dni roboczych (krytyczne) |
|
|
|
|
## Wspierane wersje
|
|
|
|
| Wersja | Status wsparcia |
|
|
| ------- | ----------------- |
|
|
| 3.8.x | ✅ Aktywne |
|
|
| 3.7.x | ✅ Bezpieczeństwo |
|
|
| < 3.7.0 | ❌ Niewspierane |
|
|
|
|
---
|
|
|
|
## Architektura bezpieczeństwa
|
|
|
|
OmniRoute wdraża wielowarstwowy model bezpieczeństwa:
|
|
|
|
```
|
|
Request → CORS → Authz pipeline (classify → policies → enforce)
|
|
→ Guardrails (PII masker, prompt injection, vision bridge)
|
|
→ Rate Limiter → Circuit Breaker → Cooldown → Model Lockout → Provider
|
|
```
|
|
|
|
### 🔐 Uwierzytelnianie i autoryzacja
|
|
|
|
| Funkcja | Implementacja |
|
|
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| **Dashboard Login** | Uwierzytelnianie hasłem z tokenami JWT (ciasteczka HttpOnly) |
|
|
| **API Key Auth** | Klucze podpisane HMAC z walidacją CRC |
|
|
| **OAuth 2.0 + PKCE** | Przepływy OAuth w przeglądarce/na urządzeniu używają PKCE, gdy dostawca je obsługuje; importowane poświadczenia Devin są obsługiwane osobno. |
|
|
| **Token Refresh** | Automatyczne odświeżanie tokenów OAuth przed wygaśnięciem |
|
|
| **Secure Cookies** | `AUTH_COOKIE_SECURE=true` dla środowisk HTTPS |
|
|
| **Authz Pipeline** | Klasyfikacja tras (PUBLIC / CLIENT_API / MANAGEMENT) — zob. `docs/architecture/AUTHZ_GUIDE.md` |
|
|
| **Route Guard Tiers** | Model 3-poziomowy dla tras zarządzania (LOCAL_ONLY / ALWAYS_PROTECTED / MANAGEMENT) — zob. `docs/security/ROUTE_GUARD_TIERS.md` |
|
|
| **Manage-Scope MCP** | Zdalny dostęp `/api/mcp/*` ograniczony kluczami API ze scope `manage`; `/api/cli-tools/runtime/*` pozostaje strict-loopback. Zob. ROUTE_GUARD_TIERS |
|
|
| **MCP Scopes** | 32 granularne scope'y (read:health, write:combos, execute:completions itd.) — zob. `docs/frameworks/MCP-SERVER.md` |
|
|
|
|
### 🛡️ Szyfrowanie w spoczynku
|
|
|
|
Wszystkie wrażliwe dane przechowywane w SQLite są szyfrowane algorytmem **AES-256-GCM** z derywacją klucza scrypt:
|
|
|
|
- Klucze API, tokeny dostępu, tokeny odświeżania oraz tokeny ID
|
|
- Wersjonowany format: `enc:v1:<iv>:<ciphertext>:<authTag>`
|
|
- Tryb passthrough (tekst jawny), gdy `STORAGE_ENCRYPTION_KEY` nie jest ustawiony
|
|
|
|
```bash
|
|
# Generate encryption key:
|
|
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)
|
|
```
|
|
|
|
### 🛡️ Framework Guardrails
|
|
|
|
OmniRoute dostarcza przeładowywalny na gorąco **rejestr guardrails** (`src/lib/guardrails/`) z 3 wbudowanymi guardrails uporządkowanymi według priorytetu:
|
|
|
|
| Guardrail | Priorytet | Cel |
|
|
| ------------------ | --------- | ---------------------------------------------------------------------------------------- |
|
|
| `vision-bridge` | 5 | Mostkuje modele bez wizji opisami uwzględniającymi obraz; ochrona SSRF dla URL-i obrazów |
|
|
| `pii-masker` | 10 | Redakcja PII przed i po wywołaniu (e-maile, telefon, CPF, CNPJ, karty kredytowe, SSN) |
|
|
| `prompt-injection` | 20 | Wykrywa wzorce override / role-hijack / jailbreak / leak |
|
|
|
|
Własne guardrails rejestruje się przez `registerGuardrail(new MyGuardrail())`. Model jest fail-open (wyjątki nigdy nie blokują ruchu). Rezygnacja per żądanie przez nagłówek `x-omniroute-disabled-guardrails`. → Zob. [`docs/security/GUARDRAILS.md`](docs/security/GUARDRAILS.md).
|
|
|
|
### 🧠 Ochrona przed prompt injection
|
|
|
|
Heurystyczny middleware best-effort, który wykrywa wzorce prompt injection w żądaniach LLM.
|
|
**To nie jest kompletna zapora przed prompt injection** — może generować fałszywe alarmy (nieszkodliwe
|
|
prompty persona/RPG) oraz pomijać ataki (leetspeak, odstępy, wzorce w innych językach).
|
|
|
|
| Typ wzorca | Dotkliwość | Przykład |
|
|
| ------------------- | ---------- | -------------------------------------------------------- |
|
|
| System Override | High | "ignore all previous instructions" |
|
|
| Role Hijack | Medium | "you are now DAN, you can do anything" |
|
|
| Delimiter Injection | High | Zakodowane separatory łamiące granice kontekstu |
|
|
| DAN/Jailbreak | Medium | Znane wzorce promptów jailbreak |
|
|
| Instruction Leak | High | "show me your system prompt" |
|
|
| Encoding Evasion | Medium | dekodowanie base64/rot13/hex + słowa kluczowe instrukcji |
|
|
|
|
W trybie `block` blokowane są wyłącznie detekcje o dotkliwości **High**. Rodziny o
|
|
dotkliwości Medium są logowane, ale nigdy nie blokowane przez `sanitizeRequest`.
|
|
|
|
Konfiguracja przez dashboard (Settings → Security) lub `.env`:
|
|
|
|
```env
|
|
INPUT_SANITIZER_ENABLED=true
|
|
INPUT_SANITIZER_MODE=block # warn | block (injection policy; legacy "redact" does not strip injection text)
|
|
INPUT_SANITIZER_BLOCK_THRESHOLD=high # high (default) | medium | low — severities at/above this are blocked in block mode
|
|
```
|
|
|
|
### 🔒 Redakcja PII
|
|
|
|
Automatyczne wykrywanie i opcjonalna redakcja danych osobowych (PII):
|
|
|
|
| Typ PII | Wzorzec | Zamiennik |
|
|
| ------------- | --------------------- | ------------------ |
|
|
| Email | `user@domain.com` | `[EMAIL_REDACTED]` |
|
|
| CPF (Brazil) | `123.456.789-00` | `[CPF_REDACTED]` |
|
|
| CNPJ (Brazil) | `12.345.678/0001-00` | `[CNPJ_REDACTED]` |
|
|
| Credit Card | `4111-1111-1111-1111` | `[CC_REDACTED]` |
|
|
| Phone | `+55 11 99999-9999` | `[PHONE_REDACTED]` |
|
|
| SSN (US) | `123-45-6789` | `[SSN_REDACTED]` |
|
|
|
|
```env
|
|
PII_REDACTION_ENABLED=true # request PII rewrite; independent of INPUT_SANITIZER_MODE
|
|
PII_RESPONSE_SANITIZATION=true # optional: redact PII in provider responses returned to clients
|
|
```
|
|
|
|
### 🌐 Bezpieczeństwo sieci
|
|
|
|
| Funkcja | Opis |
|
|
| ------------------------ | ------------------------------------------------------------------------------- |
|
|
| **CORS** | Jawna lista dozwolonych originów (`CORS_ALLOWED_ORIGINS`; legacy `CORS_ORIGIN`) |
|
|
| **IP Filtering** | Listy allowlist/blocklist zakresów IP w dashboardzie |
|
|
| **Rate Limiting** | Limity zapytań per dostawca z automatycznym backoffiem |
|
|
| **Anti-Thundering Herd** | Mutex + blokady per połączenie zapobiegają kaskadowym 502 |
|
|
| **TLS Fingerprint** | Spoofing odcisku TLS jak w przeglądarce w celu ograniczenia detekcji botów |
|
|
| **CLI Fingerprint** | Kolejność nagłówków/ciała per dostawca dopasowana do natywnych sygnatur CLI |
|
|
|
|
### 🔌 Odporność i dostępność
|
|
|
|
| Funkcja | Opis |
|
|
| ----------------------- | -------------------------------------------------------------------- |
|
|
| **Circuit Breaker** | 3 stany (Closed → Open → Half-Open) per dostawca, utrwalone w SQLite |
|
|
| **Request Idempotency** | 5-sekundowe okno deduplikacji dla powielonych żądań |
|
|
| **Exponential Backoff** | Automatyczne ponawianie z rosnącymi opóźnieniami |
|
|
| **Health Dashboard** | Monitorowanie zdrowia dostawców w czasie rzeczywistym |
|
|
|
|
### 📋 Zgodność
|
|
|
|
| Funkcja | Opis |
|
|
| ------------------ | ------------------------------------------------------------------------ |
|
|
| **Log Retention** | Automatyczne czyszczenie po `CALL_LOG_RETENTION_DAYS` |
|
|
| **No-Log Opt-out** | Flaga `noLog` per klucz API wyłącza logowanie żądań |
|
|
| **Audit Log** | Działania administracyjne śledzone w tabeli `audit_log` |
|
|
| **MCP Audit** | Audyt w SQLite dla wszystkich wywołań narzędzi MCP |
|
|
| **Zod Validation** | Wszystkie wejścia API walidowane schematami Zod v4 przy ładowaniu modułu |
|
|
|
|
---
|
|
|
|
## Wymagane zmienne środowiskowe
|
|
|
|
Wszystkie sekrety muszą być ustawione przed uruchomieniem serwera. Serwer **zakończy się natychmiast (fail fast)**, jeśli brakuje ich lub są słabe.
|
|
|
|
```bash
|
|
# REQUIRED — server will not start without these:
|
|
JWT_SECRET=$(openssl rand -base64 48) # min 32 chars
|
|
API_KEY_SECRET=$(openssl rand -hex 32) # min 16 chars
|
|
|
|
# RECOMMENDED — enables encryption at rest:
|
|
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)
|
|
```
|
|
|
|
Serwer aktywnie odrzuca znane słabe wartości, takie jak `changeme`, `secret` lub `password`.
|
|
|
|
---
|
|
|
|
## Bezpieczeństwo Dockera
|
|
|
|
- Używaj użytkownika non-root w produkcji
|
|
- Montuj sekrety jako wolumeny tylko do odczytu
|
|
- Nigdy nie kopiuj plików `.env` do obrazów Dockera
|
|
- Używaj `.dockerignore`, aby wykluczyć pliki wrażliwe
|
|
- Ustaw `AUTH_COOKIE_SECURE=true` za HTTPS
|
|
|
|
```bash
|
|
docker run -d \
|
|
--name omniroute \
|
|
--restart unless-stopped \
|
|
--read-only \
|
|
-p 20128:20128 \
|
|
-v omniroute-data:/app/data \
|
|
-e JWT_SECRET="$(openssl rand -base64 48)" \
|
|
-e API_KEY_SECRET="$(openssl rand -hex 32)" \
|
|
-e STORAGE_ENCRYPTION_KEY="$(openssl rand -hex 32)" \
|
|
diegosouzapw/omniroute:latest
|
|
```
|
|
|
|
---
|
|
|
|
## Zależności
|
|
|
|
- Regularnie uruchamiaj `npm audit` (`npm run audit:deps` obejmuje main + electron)
|
|
- Utrzymuj zależności w aktualnej wersji
|
|
- Projekt używa `husky` + `lint-staged` do kontroli pre-commit (lint-staged + check-docs-sync + check:any-budget:t11)
|
|
- Pipeline CI uruchamia reguły bezpieczeństwa ESLint przy każdym pushu (`no-eval`, `no-implied-eval`, `no-new-func` = error)
|
|
- Stałe dostawców walidowane przy ładowaniu modułu przez Zod (`src/shared/validation/schemas.ts`)
|
|
- Używane biblioteki secure-by-default: `dompurify` / `isomorphic-dompurify` (XSS), `jose` (JWT), `better-sqlite3` (brak ryzyka SQLi dzięki zapytaniom parametryzowanym), `bcryptjs` (hashowanie haseł)
|
|
|
|
## Twarde reguły bezpieczeństwa
|
|
|
|
Te reguły są egzekwowane przez narzędzia i recenzentów:
|
|
|
|
1. **Nigdy nie commituj sekretów** — `.env` jest w gitignore; `.env.example` to szablon (bez literałów, tylko komentarze — zob. PUBLIC_CREDS.md poniżej)
|
|
2. **Nigdy nie używaj `eval()`, `new Function()` ani implied eval** — egzekwowane przez ESLint
|
|
3. **Nigdy nie omijaj hooków Husky** (`--no-verify`, `--no-gpg-sign`) bez wyraźnej zgody operatora
|
|
4. **Nigdy nie pisz surowego SQL w trasach** — zawsze przez `src/lib/db/` (parametryzowane)
|
|
5. **Zawsze waliduj wejścia Zod** — `src/shared/validation/schemas.ts`
|
|
6. **Zawsze sanityzuj nagłówki upstream** — denylist w `src/shared/constants/upstreamHeaders.ts`
|
|
7. **Szyfruj poświadczenia w spoczynku** — AES-256-GCM przez `src/lib/db/encryption.ts`
|
|
8. **Publiczne identyfikatory OAuth upstream przez `resolvePublicCred()`** — nigdy nie umieszczaj w źródle literałów `AIza…` / `GOCSPX-…` / `…apps.googleusercontent.com`. Zob. [`docs/security/PUBLIC_CREDS.md`](docs/security/PUBLIC_CREDS.md).
|
|
9. **Odpowiedzi błędów przez `buildErrorBody()` / `sanitizeErrorMessage()`** — nigdy nie umieszczaj surowego `err.stack` / `err.message` w ciałach odpowiedzi HTTP / SSE / executor / MCP. Zob. [`docs/security/ERROR_SANITIZATION.md`](docs/security/ERROR_SANITIZATION.md).
|
|
10. **Wartości runtime `exec()` / `spawn()` przez opcję `env`** — nigdy nie interpoluj zewnętrznych ścieżek ani niezaufanych wartości w skryptach przekazywanych do powłoki. Odniesienie: `src/mitm/cert/install.ts::updateNssDatabases`.
|
|
11. **Preferuj biblioteki secure-by-default** — zob. [tldrsec/awesome-secure-defaults](https://github.com/tldrsec/awesome-secure-defaults) (Helmet.js, DOMPurify, ssrf-req-filter, safe-regex, Google Tink). Sięgaj po nie, zanim napiszesz własne.
|
|
|
|
## Ustalenia skanerów łańcucha dostaw (Socket.dev / Snyk / podobne)
|
|
|
|
Opublikowany artefakt npm `omniroute` bundluje build Next.js `output: "standalone"`,
|
|
co oznacza, że każdy route handler — w tym udokumentowane uprzywilejowane
|
|
funkcje (MITM, Zed import, Cloud Sync, embedded service supervisor) — trafia
|
|
do zminifikowanych chunków `.next/server/*.js`. Heurystyczne skanery łańcucha dostaw
|
|
często dopasowują te chunki do sygnatur malware.
|
|
|
|
Dla każdej kategorii ustaleń utrzymujemy poświadczenie maintainerów per ustalenie:
|
|
|
|
- **[`docs/security/SOCKET_DEV_FINDINGS.md`](docs/security/SOCKET_DEV_FINDINGS.md)** —
|
|
mapa per ustalenie: plik źródłowy ↔ oflagowany chunk ↔ zachowanie ↔ mitygacja
|
|
zastosowana w v3.8.6.
|
|
- Bloki `SECURITY-AUDITOR-NOTE:` w źródle przy każdej oflagowanej funkcji odsyłają
|
|
do tego samego dokumentu.
|
|
|
|
Dla użytkowników, których pipeline nie może poluzować alertu: buduj z
|
|
`OMNIROUTE_BUILD_PROFILE=minimal npm run build`. To zastępuje cztery
|
|
wrażliwe moduły stubami zwracającymi HTTP 503 `feature-disabled` w
|
|
runtime, więc uprzywilejowane ścieżki kodu są fizycznie nieobecne w bundlu.
|
|
Zob. [`docs/security/SOCKET_DEV_FINDINGS.md`](docs/security/SOCKET_DEV_FINDINGS.md)
|
|
dla receptury publikacji.
|
|
|
|
## Odniesienia
|
|
|
|
- [`docs/architecture/AUTHZ_GUIDE.md`](docs/architecture/AUTHZ_GUIDE.md) — potok autoryzacji
|
|
- [`docs/security/GUARDRAILS.md`](docs/security/GUARDRAILS.md) — framework guardrails
|
|
- [`docs/security/COMPLIANCE.md`](docs/security/COMPLIANCE.md) — dziennik audytu i retencja
|
|
- [`docs/security/PUBLIC_CREDS.md`](docs/security/PUBLIC_CREDS.md) — **obowiązkowy** wzorzec dla publicznych poświadczeń upstream
|
|
- [`docs/security/ERROR_SANITIZATION.md`](docs/security/ERROR_SANITIZATION.md) — **obowiązkowy** wzorzec dla odpowiedzi błędów
|
|
- [`docs/security/SOCKET_DEV_FINDINGS.md`](docs/security/SOCKET_DEV_FINDINGS.md) — poświadczenie maintainerów dla ustaleń skanerów łańcucha dostaw
|
|
- [`docs/architecture/RESILIENCE_GUIDE.md`](docs/architecture/RESILIENCE_GUIDE.md) — circuit breaker + cooldown + lockout
|
|
- [`docs/security/STEALTH_GUIDE.md`](docs/security/STEALTH_GUIDE.md) — fingerprinting TLS (uwaga prawna/etyczna)
|
|
- [`CLAUDE.md`](CLAUDE.md) — twarde reguły dla agentów AI
|
|
- [tldrsec/awesome-secure-defaults](https://github.com/tldrsec/awesome-secure-defaults) — wyselekcjonowane biblioteki secure-by-default
|