Skip to content

Latest commit

 

History

History
300 lines (247 loc) · 27.8 KB

ROUTE_GUARD_TIERS.md

File metadata and controls

300 lines (247 loc) · 27.8 KB

Route Guard Tiers (Bosanski)

🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW


Pregled

Sve rute OmniRoute API-ja za upravljanje klasificirane su u jedan od tri nivoa zaštite. Klasifikacija je statična, definirana u src/server/authz/routeGuard.ts i procjenjuje se prije izvršavanja bilo koje druge grane autentifikacije.

Nivoi

Nivo 1 — LOCAL_ONLY

Provedeno od strane: isLocalOnlyPath(path) → provjera loopback hosta Zaobilaženje: Nema podrazumijevano. Usko izuzeće za putanje u LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES kada zahtjev nosi važeći API ključ sa manage opsegom (pogledajte Izuzeće za opseg upravljanja).

Ove rute pokreću podređene procese ili izvršavaju runtime kod. Izlaganje istih saobraćaju koji nije loopback omogućilo bi napadaču koji je dobio važeći JWT (npr. putem Cloudflared/Ngrok tunela) da pokrene stvaranje procesa — poznatu CVE klasu (GHSA-fhh6-4qxv-rpqj).

Šta je GHSA-fhh6-4qxv-rpqj (klasa napada): server za upravljanje/agenta izlaže krajnju tačku koja pokreće podproces (npm install, node, pretraživač, proxy, git, tar, …). Ako je ta krajnja tačka dostupna sa vanjskog hosta — jer je operator postavio OmniRoute iza nginx/Cloudflare/Tailscale tunela i JWT je procurio, ili je autentifikacija bila pogrešno konfigurisana — napadač pretvara "pozivanje API-ja" u "izvršavanje komande na hostu" (daljinsko izvršavanje koda). OmniRoute ovo sprečava provođenjem bezuslovne provjere loopback hosta, prije bilo kakve provjere autentifikacije, na svakoj ruti koja može pokrenuti proces: procurjeli token preko tunela i dalje ne može doći do pokretanja.

Potpuni LOCAL_ONLY skup. Autoritetni izvor su LOCAL_ONLY_API_PREFIXES / LOCAL_ONLY_API_PATTERNS u src/server/authz/routeGuard.ts; tabela ispod odražava trenutno stanje. check-route-guard-membership kapija nabraja svaki route.ts pod prefiksima koji mogu pokrenuti procese i ne uspijeva CI ako bilo koji nije klasifikovan kao samo-lokalni.

Prefix / pattern Zašto je samo lokalno
/api/mcp/ MCP server — pokreće stdio mostove + SSE rukovaoce
/api/cli-tools/runtime/ CLI okruženje za izvršavanje alata — izvršava proizvoljni kod dodataka
/api/cli-tools/{omp,letta,grok-build,forge,jcode,qwen}-settings Pisci postavki po alatu koji mogu mijenjati binarne datoteke/konfiguraciju alata na hostu
/api/cli-tools/{claude,cline,codewhale,codex,crush,deepseek-tui,droid,kilo,openclaw,pi,smelt}-settings Isto pokretanje getCliRuntimeStatus() kao i šest gore navedenih srodnih (GHSA-35fw-cv32-2373)
/api/cli-tools/{all-statuses,status,detect} CLI sonde za inventar — pokreću command -v / --version po alatu (GHSA-35fw-cv32-2373)
/api/cli-tools/antigravity-mitm Kontrola Antigravity MITM proxyja (pokreće/usmjerava sistemski proxy)
/api/modality-bridge/video/ Stroga trusted-loopback Video Bridge runtime sonda i interni most za ekstrakciju
/api/services/ Ugrađene usluge (9Router / CLIProxy / Bifrost / Mux / Dario) — npm install + pokretanje
/dashboard/providers/services/ Reverzni proxy za korisnička sučelja ugrađenih usluga
/api/tunnels/cloudflared Instalira/pokreće cloudflared binarnu datoteku
/api/tunnels/tailscale/{install,enable,disable,login,start-daemon} Instalira/kontrolira tailscaled na hostu
/api/copilot/ Neautentificirani LLM drajver — samo CLI po defaultu
/api/tools/agent-bridge/ AgentBridge — pokreće MITM server + DNS izmjene
/api/tools/traffic-inspector/ Inspektor prometa — http-proxy slušatelj + sistemski proxy
/api/settings/mitm Omogućava MITM presretanje (stanje proxyja na nivou sistema)
/api/issue-agent/ Agent za probleme — pokreće lokalne alate protiv repozitorija
/api/plugins/, /api/plugins Dodaci — učitavaju/izvršavaju se putem worker_threads + child_process
/api/middleware/ Korisnički middleware — učitava/izvršava operatorski kod unutar procesa
/api/system/version Automatsko ažuriranje (samo POST; GET/HEAD/OPTIONS izuzeti) — pokreće git checkout + npm install
/api/db-backups/exportAll Pokreće tar za arhivu izvoza
/api/local/ Lokalni pokretači jednim klikom (Redis danas) — pokreće podman/docker
/api/headroom/start, /api/headroom/stop Životni ciklus Headroom proxyja — pokreće python CLI / signalizira PID
/api/jobs, /api/jobs/ Kontrola pokretača poslova — izvršava zakazani rad na strani hosta
/api/oauth/cursor/auto-import execFile("which", ["cursor"]) prije uvoza vjerodajnica
/api/oauth/kiro/auto-import Čita Kiro CLI datoteke vjerodajnica sa hosta
/api/skills/collect/ Prikupljanje vještina — detektira/instalira lokalne alate
/api/skills/install, /api/skills/executions Registracija + izvršavanje rukovaoca vještinama — doseže pokretanje sandbox kontejnera (GHSA-jx89)
/api/discovery/ Lokalne sonde za otkrivanje mreže/provajdera
/api/vnc-session (VNC_ROUTE_PREFIX) Pokreće preglednik s grafičkim sučeljem + VNC sesiju za interaktivne prijave
/api/acp/agents ACP — otkriva i pokreće lokalne binarne datoteke CLI agenta
/api/resilience/connections JSON otpornosti po računu (hlađenje, prekid, zaključavanje). HTML nadzorne ploče nije samo lokalni.
/api/providers/cursor/agent-availability Provjera poticaja za instalaciju nadzorne ploče — pokreće cursor-agent status --format json
/api/providers/{id}/login (regex) Pokreće Playwright Chromium s grafičkim sučeljem za prijavu putem web kolačića
/api/providers/volcengine-plan/connect (regex) Ručni tok s grafičkim sučeljem + automatska prijava telefonom/SMS-om bazirana na sesiji (pokreće Playwright)
/api/providers/{id}/refresh-cursor (regex) Ručno obnavljanje Cursor sesije — potiče cursor-agent
/api/providers/{id}/chatgpt-web-codex-doctor (regex) Dijagnosticira lokalnu instalaciju Codex CLI-ja (pokreće binarnu datoteku)

Odgovor na kršenje: 403 LOCAL_ONLY

Izuzeće opsega upravljanja

Podskup LOCAL_ONLY putanja MOŽE biti dostupan i izvan loopbacka ako i samo ako zahtjev nosi Authorization: Bearer <api-key> čiji metapodaci uključuju opseg manage (ili admin). Izuzeće je eksplicitno ograničeno po putanji putem LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES, tako da zadana vrijednost za bilo koju novu LOCAL_ONLY putanju ostaje strogi loopback. Neautentificirani zahtjevi i zahtjevi s ključevima koji nemaju manage opseg i dalje se odbijaju s 403 LOCAL_ONLY.

Danas je jedini prefiks koji se može zaobići /api/mcp/. /api/cli-tools/runtime/ i /api/services/ su namjerno isključeni jer mogu pokrenuti proizvoljne podprocese (npm install, node), što je točno klasa CVE-a koju LOCAL_ONLY sloj sprječava.

#7895 — mcp:connect uski opseg: izuzeće za /api/mcp/ TAKOĐER prihvaća Bearer ključ koji sadrži uski mcp:connect opseg (src/shared/constants/managementScopes.ts::MCP_CONNECT_SCOPE), provjeren putem hasMcpConnectOrManageScope() u src/server/authz/policies/management.ts. Ovo je ograničeno SAMO na /api/mcp/ — mcp:connect ne daje ništa na bilo kojoj drugoj ruti upravljanja (uključujući svaki drugi LOCAL_ONLY prefiks za zaobilaženje, ako se ikada doda), i namjerno je isključeno iz MANAGEMENT_API_KEY_SCOPES. Ključ koji sadrži manage/admin i dalje prolazi izuzeće točno kao i prije; mcp:connect je alternativa s nižim privilegijama za udaljene pozivatelje samo za MCP koji ne bi trebali trebati širok pristup upravljanju.

Zahtjev Putanja Rezultat
Izvan loopbacka, bez Bearer ključa /api/mcp/* 403 LOCAL_ONLY
Izvan loopbacka, Bearer ključ s opsegom manage /api/mcp/* Dozvoljeno
Izvan loopbacka, Bearer ključ s opsegom mcp:connect /api/mcp/* Dozvoljeno
Izvan loopbacka, Bearer ključ bez manage/mcp:connect /api/mcp/* 403 LOCAL_ONLY
Izvan loopbacka, Bearer ključ s opsegom mcp:connect /api/cli-tools/runtime/* 403 LOCAL_ONLY
Izvan loopbacka, Bearer ključ s opsegom manage /api/cli-tools/runtime/* 403 LOCAL_ONLY
Loopback, bilo koji/bez Bearer ključa bilo koji LOCAL_ONLY Dozvoljeno (provjera prolazi)

Upute za operatera i revizija

Ako pokrećete OmniRoute iza obrnutog proxyja ili tunela (nginx, Caddy, Cloudflare Tunnel, Tailscale, Ngrok), provjera loopbacka i dalje štiti gore navedene rute koje mogu pokrenuti procese — zahtjev čija klijentska adresa nije loopback odbija se s 403 LOCAL_ONLY prije pokretanja autentifikacije, tako da procurjeli JWT ne može doći do pokretanja procesa. Dvije odgovornosti operatera ostaju:

  • Nemojte "popravljati" 403 krivotvorenjem klijentske IP adrese kao loopback. Postavljanje X-Forwarded-For: 127.0.0.1, ili proxy koji prepisuje izvornu adresu na loopback, ponovno otvara točno onu klasu RCE-a koju ovaj sloj zatvara. Izložite nadzornu ploču/API putem proxyja — nikada rute koje mogu pokrenuti procese.
  • Održavajte zaobilaženje opsega upravljanja minimalnim. Samo /api/mcp/ se može zaobići, i to samo s API ključem s opsegom manage. SPAWN_CAPABLE_PREFIXES se nikada ne mogu dodati na listu zaobilaženja — zod shema ih odbija, a isLocalOnlyBypassableByManageScope ih odbija u runtimeu (dubinska obrana), što nadzorna ploča podrazumijeva pod "ne može se učiniti zaobilaznim". Rute s dinamičkim segmentima i statičkim putanjama koje mogu pokrenuti procese pod /api/providers/ (npr. /login, /refresh-cursor) pokrivene su regex-baziranim SPAWN_CAPABLE_PATTERNS / SPAWN_CAPABLE_PATTERN_ANCESTORS pratiocem u src/shared/constants/spawnCapablePrefixes.ts, a ne ravnim SPAWN_CAPABLE_PREFIXES nizom — ravni niz bi morao pokriti cijeli /api/providers/ prefiks da bi ih uhvatio, preširoko proširujući stablo ruta koje udaljene nadzorne ploče legitimno koriste za CRUD pružatelja.

Revizija pristupa — za provjeru da ništa izvan hosta ne doseže ove rute:

  • Otvorite Inventar autorizacije na /dashboard/settings/security: prikazuje listu prefiksa LOCAL_ONLY uživo, koji prefiksi se mogu zaobići, i skup sposobnih za pokretanje u vrijeme kompilacije ("ne mogu se učiniti zaobilaznim").
  • Pretražite svoje reverse-proxy / pristupne logove za gore navedene prefikse uparene sa klijentskom adresom koja nije loopback. Svaki takav pogodak koji je vratio 200 umjesto 403 LOCAL_ONLY znači da proxy maskira stvarnu IP adresu klijenta — popravite proxy.
  • 403 LOCAL_ONLY u OmniRoute logovima za jednu od ovih putanja je čuvar koji radi kako je predviđeno, a ne greška koju treba potisnuti.

Nivo 2 — ALWAYS_PROTECTED

Nametnuto od: isAlwaysProtectedPath(path) → preskače requireLogin=false zaobilaženje Zaobilaženje: Nema kada je requireLogin=false; JWT uvijek potreban

Ove rute su destruktivne ili nepovratne. Dozvoljavanje istih u instalaciji "bez lozinke" značilo bi da bi svako na istoj LAN mreži mogao obrisati bazu podataka ili ugasiti proces servera.

Putanja Razlog
/api/shutdown Prekida proces servera
/api/settings/database Izvoz, uvoz i brisanje baze podataka
/api/db-backups Pristup arhivi potpune sigurnosne kopije baze podataka
/api/settings/export-json Izvozi kompletan blob postavki (uključujući tajne)
/api/settings/import-json Zamjenjuje kompletan blob postavki
/api/providers/health-autopilot/actions Izvršava autopilot akcije sanacije
/api/settings/obsidian Kreira višekratne WebDAV akreditive za bilo koji korijen trezora

Odgovor na kršenje: 401 Authentication required

/api/settings/obsidian pokriva svoj /webdav podređeni: POST usmjerava WebDAV datotečnu uslugu — koju poslužuje prilagođeni Node sloj prije Next.js-a, izvan ovog cjevovoda — na korijen koji odabere pozivatelj i vraća svježe kreirane Basic akreditive, DELETE ih rotira, a roditeljski POST pohranjuje Obsidian REST API token. GHSA-62vw je samo maskirao GET otkrivanje lozinke; izdavanje je još uvijek bilo na nivou otvorenog kvara (GHSA-7pq4-8pvv-rx7r). enableObsidianVaultSync() dodatno odbija trezor koji je, nalazi se unutar, ili sadrži direktorij podataka.

Bootstrap svježe instalacije je samo loopback — od stvarnog peer-a, a ne Host

Bez konfigurirane administratorske lozinke (i bez INITIAL_PASSWORD), isAuthRequired() u src/shared/utils/apiAuth.ts drži anonimni bootstrap otvoren samo za loopback peer-ove. Loopback se određuje iz pouzdanih peer signala, redom: stvarni TCP peer sa tokenom (PEER_IP_HEADER + VIA_PROXY_HEADER, što politika vidi), vlastita presuda cjevovoda AUTHZ_HEADER_PEER_LOCALITY (što rukovatelji ruta vide, pouzdano samo dok je OMNIROUTE_PEER_STAMP_TOKEN postavljen), ili stvarni socket peer za direktne pozivatelje. Host / nextUrl.hostname se nikada ne konsultuju, a pisanje prve lozinke (POST /api/settings/require-login) je pod istim ograničenjem, a ne otvoreno za svakog mrežnog peer-a (GHSA-7pq4-8pvv-rx7r). managementPolicy eksplicitno prosljeđuje svoju vlastitu peerContext presudu, tako da ORIGINALNI (prije uklanjanja) zaglavlja zahtjeva nikada ne odlučuju o tome.

Nivo 3 — MANAGEMENT (podrazumijevano)

Sve ostale rute za upravljanje. Autentifikacija je potrebna osim ako requireLogin=false nije konfigurisan. CLI tokeni mogu autentifikovati ove rute (loopback + validan HMAC).

Redoslijed evaluacije

managementPolicy.evaluate(ctx)
  1. isLocalOnlyPath(path)?
     → povratna petlja                                  → nastavi dalje
     → nije povratna petlja, Bearer s opsegom manage
        I isLocalOnlyBypassableByManageScope             → dozvoli (management_key)
     → u suprotnom                                       → odbij 403 LOCAL_ONLY
  2. isInternalModelSyncRequest(ctx)?
     → dozvoli (system)
  3. hasValidCliToken(headers)?
     → dozvoli (cli) [povratna petlja + HMAC provjera pomoću timingSafeEqual]
  4. isAlwaysProtectedPath(path) ili requireLogin=true?
     → isDashboardSessionAuthenticated?
        → dozvoli (dashboard_session)
     → Bearer s opsegom manage na putanji koju nije moguće zaobići?
        → dozvoli (management_key)
     → odbij 401/403
  5. requireLogin=false?
     → dozvoli (anonymous)

Grana s opsegom manage iz koraka 1 jedina je autentificirana putanja koja može zadovoljiti LOCAL_ONLY rutu; način otkaza autentifikacijskog pozadinskog sistema vraća 503 (ne 403), tako da istekla baza podataka ne dovede neprimjetno do prelaska na „odbij“.

Dodavanje nove rute koja može pokretati procese

  1. Dodajte prefiks putanje u LOCAL_ONLY_API_PREFIXES u src/server/authz/routeGuard.ts
  2. Dodajte test u tests/unit/authz/routeGuard.test.ts koji potvrđuje da isLocalOnlyPath() vraća true za novi prefiks
  3. Nikada ne preskačite ovaj korak — pogledajte strogo pravilo br. 15 u CLAUDE.md
  4. Odlučite: pripada li ova ruta TAKOĐER u LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES? Zadani odgovor je ne. Uključite je samo kada je rutu sigurno izložiti imaocu opsega manage (tj. NE pokreće proizvoljni kod kojim upravlja korisnik).

Dodavanje putanje koju je moguće zaobići pomoću opsega manage

  1. Potvrdite da ruta ne izvršava kod ili naredbe koje je dostavio korisnik. Ako ih izvršava, zaustavite se — ovaj izuzetak nije odgovarajući alat.
  2. Dodajte prefiks u LOCAL_ONLY_MANAGE_SCOPE_BYPASS_PREFIXES u src/server/authz/routeGuard.ts
  3. Dodajte pokrivenost u tests/unit/authz/management-policy.test.ts za sva četiri oblika zahtjeva: bez Bearer tokena (403), Bearer s opsegom manage (dozvoli), Bearer bez opsega manage (403) i regresijski test po prefiksu kojim se potvrđuje da /api/cli-tools/runtime/* ostaje strogo ograničen na povratnu petlju čak i uz Bearer s opsegom manage.

Datoteke

Datoteka Namjena
src/server/authz/routeGuard.ts Konstante i pomoćne funkcije
src/server/authz/policies/management.ts Logika evaluacije
tests/unit/authz/routeGuard.test.ts Jedinični testovi pomoćnika nivoa
tests/unit/authz/management-policy.test.ts Jedinični testovi za evaluate()

Dokumentovanje sigurnosnih nivoa u OpenAPI-ju

Prilikom dodavanja nove rute u docs/openapi.yaml, primijenite odgovarajuće proširenje dobavljača ako je ruta klasificirana u routeGuard.ts:

Klasifikacija u routeGuard.ts YAML anotacija Provođenje
LOCAL_ONLY_API_PREFIXES x-loopback-only: true Bezuslovno blokirano izvan povratne petlje
ALWAYS_PROTECTED_API_PATHS x-always-protected: true Autentifikacija je obavezna čak i uz requireLogin=false
Interna admin/debug ruta x-internal: true Zadano skriveno iz /dashboard/api-endpoints
Nijedna (javni / standardni pristup uz autentifikaciju) (anotacija nije potrebna) Standardni pristup kojim upravlja requireLogin

Validacija

Dvije skripte osiguravaju dosljednost između YAML anotacija i routeGuard.ts:

  • scripts/check/check-openapi-coverage.mjs — neuspješno se završava ako je pokrivenost < 99%
  • scripts/check/check-openapi-security-tiers.mjs — neuspješno se završava ako anotacije x-loopback-only ili x-always-protected odstupaju od konstanti definiranih u vrijeme prevođenja

Obje skripte pokreću se u pre-commit kuki i u CI-ju.

Pravilo za lažno pozitivne rezultate

Ako je x-always-protected ili x-loopback-only anotiran na ruti koja NIJE u konstanti u routeGuard.ts, skripta za pokrivenost završava se neuspješno. Rješenje je uvijek uskladiti YAML s onim što routeGuard.ts zaista provodi — a ne dodavati rute u routeGuard.ts bez istovremene implementacije logike provođenja.


Pogledajte također

  • docs/security/CLI_TOKEN.md — token ID-a uređaja za CLI
  • docs/architecture/AUTHZ_GUIDE.md — kompletan proces autorizacije
  • docs/frameworks/MCP-SERVER.md — transporti i opsezi MCP servera