Minden módszernél leírjuk, hogyan működik a gyakorlatban, mikor éri meg, hol szokott elcsúszni, és hogyan épül be egy fejlesztőcsapat napi munkájába, akár AI asszisztált fejlesztésnél is. Kódpéldáink TypeScript, Node, Next.js, Postgres és Supabase környezetre készültek. A sebezhető változat mindig csak annyit mutat, amennyi a hiba megértéséhez kell, támadási recept nincs benne.
Az LLM és ágens specifikus fenyegetésekkel (prompt injekció, eszközvisszaélés, túlzott önállóság, memóriamérgezés, OWASP LLM és Agentic Top 10) az AI ügynökök és vibecoding kézikönyv foglalkozik részletesen. Ebben a kézikönyvben csak akkor kerülnek elő, amikor egy klasszikus védelem (bizalmi határ, legkisebb jogosultság, kimenet kódolás) rájuk is érvényes.
Gyorstérkép
| Helyzet | Kiindulópont |
|---|---|
| Új funkció tervezése | Fenyegetésmodellezés (négy kérdés, STRIDE, DFD) |
| Kód írása vagy review | OWASP Top 10 2025, webes alapvédelmek, ASVS L1 vagy L2 |
| Új függőség, CI módosítás | Ellátási lánc szakasz |
| Éles üzem, naplók | Naplózás és detekció |
| Valami baj történt | Incidenskezelés és a kis csapatos runbookok |
| Szervezeti kérdés, ügyfél audit | NIST CSF 2.0, CIS Controls IG1 |
| AI asszisztens által generált kód | A gyakorlati szabályok a kézikönyv végén |
1. Klasszikus gyökerek és ami belőlük ma is érvényes
A biztonsági mérnökség legtöbb mai elve egy-egy konkrét kudarcból született. A történeti áttekintés minden tételénél ott áll, mit visz tovább belőle a mai fejlesztő.
CTSS és Multics (1961 és 1969 között)
A CTSS (Compatible Time-Sharing System, MIT, Fernando Corbató csapata) az egyik első időosztásos rendszer volt, ahol több felhasználó osztozott ugyanazon a gépen. Ezzel megjelent a felhasználók egymástól való elválasztásának igénye és a jelszó. Egy 1966 körüli esetben a szövegszerkesztő ideiglenes fájljai összekeveredtek, és a rendszer a napi üdvözlő üzenet helyett a teljes jelszófájlt írta ki minden bejelentkezőnek. A hiba oka egy ártalmatlannak tűnő közös munkakönyvtár volt.
A Multics (MIT, Bell Labs, General Electric) már tervezési célként kezelte a biztonságot. Jerome Saltzer és társai itt dolgozták ki a hozzáférés vezérlési listákat, Robert Graham pedig a gyűrű (ring) architektúrát, ahol a kód jogosultsági szintekbe rendeződik, és a belső gyűrűt csak meghatározott kapukon keresztül lehet hívni. A mai CPU privilégiumszintek (kernel és user mód) és a hipervizorok elválasztása ennek a leszármazottja.
Tanulság ma.
- A közös, megosztott erőforrás (temp könyvtár, közös cache kulcs, megosztott S3 prefix) a leggyakoribb szivárgási út. Bérlőnként külön névtér kell.
- A jogosultsági szinteket kapukkal választjuk el. Egy Next.js appban a kapu a szerveroldali route handler vagy server action, a belső gyűrű az adatbázis service role kulcsa. A kliens soha nem lép be közvetlenül a belső gyűrűbe.
Ware jelentés (1970) és Anderson jelentés (1972)
Willis Ware a RAND-nál, a Defense Science Board megbízásából írta meg a Security Controls for Computer Systems jelentést. Ez mondta ki először rendszerszinten, hogy egy többfelhasználós gép biztonsága hardver, szoftver, kommunikáció, fizikai és szervezeti kérdés egyszerre, és hogy a biztonságot a tervezés elején kell beépíteni. James Anderson 1972 jelentése bevezette a referencia monitor fogalmát, egy mindig meghívott, megkerülhetetlen, kicsi és ezért ellenőrizhető komponenst, amely minden hozzáférési döntést meghoz.
Tanulság ma. A jogosultságellenőrzést egyetlen, jól tesztelt helyre tesszük, és minden út azon megy át. Postgresben ez a Row Level Security (RLS) policy, alkalmazásszinten egy authorize() függvény, amit minden adatelérés hív. Ha a jogosultsági logika húsz route handlerben szétszórva él, a huszonegyedikből kimarad.
Tiger team tesztek és a Multics Security Evaluation (1974)
A hetvenes években az amerikai légierő úgynevezett tiger teameket állított fel, amelyek engedéllyel próbálták feltörni a rendszereket. Paul Karger és Roger Schell 1974 jelentése a Multicsról azt mutatta ki, hogy még a kor legbiztonságosabbnak tervezett rendszere is több ponton áttörhető, és felvetette, hogy egy fordítóprogramba rejtett csapóajtó a forráskódban láthatatlan maradhat. A jelentés tanulsága szerint a hibakereső tesztelés soha nem bizonyítja a hiba hiányát, csak a jelenlétét.
Tanulság ma. A pentest mintavétel, nem bizonyíték. Pentest mellé kell a tervezési szintű védelem (fenyegetésmodell, mélységi védelem), különben a jelentés lezárása után a következő commit újra kinyitja a rést.
Saltzer és Schroeder nyolc elve (1975)
A The Protection of Information in Computer Systems cikk nyolc tervezési elve ma is a biztonsági review alapja.
| Elv | Jelentés | Mai megfelelő |
|---|---|---|
| Economy of mechanism | Kicsi, egyszerű védelmi mechanizmus | Egy auth könyvtár, nem saját kripto |
| Fail-safe defaults | Alapból tilt, kifejezett engedély kell | RLS bekapcsolva, policy nélkül semmi sem látszik |
| Complete mediation | Minden hozzáférés ellenőrzött | Server action elején auth, nem csak middleware-ben |
| Open design | A biztonság ne a titkos tervtől függjön | Kerckhoffs elv, nyilvános algoritmus, titkos kulcs |
| Separation of privilege | Több feltétel együtt | MFA, kétszemélyes jóváhagyás élesítéshez |
| Least privilege | Csak a szükséges jog | Szűk scope-ú tokenek, read only DB user |
| Least common mechanism | Kevés közös komponens a felhasználók között | Bérlőnkénti izoláció |
| Psychological acceptability | Kényelmes legyen, különben megkerülik | Passkey, SSO, értelmes hibaüzenet |
Thompson, Reflections on Trusting Trust (1984)
Ken Thompson Turing díjas előadása megmutatta, hogy egy fordítóprogramba olyan logika rejthető, amely a bejelentkező programba csapóajtót fordít, és saját magát is újratermeli a fordító újrafordításakor, így a forráskódból eltűnik. A következtetés az, hogy csak annak a kódnak bízhatunk meg, amit teljes egészében magunk állítottunk elő, ami gyakorlatilag lehetetlen.
Tanulság ma. Ez az ellátási lánc biztonság alapproblémája. A válaszok a reprodukálható build, a több független fél általi építés (diverse double compiling, David A. Wheeler), a build eredetigazolás (SLSA provenance) és az aláírt artefaktumok. Az xz utils eset 2024-ben ugyanezt a mintát mutatta élesben.
Morris worm (1988) és a CERT születése
Robert Tappan Morris 1988 novemberében egy önterjesztő programot indított, amely néhány óra alatt az akkori internetre kötött gépek jelentős részét megbénította. A féreg négy gyengeséget használt ki. A fingerd démonban egy határellenőrzés nélküli gets() hívást, a sendmail bekapcsolva hagyott DEBUG módját, a rsh és rexec gépek közötti bizalmi kapcsolatait és a gyenge jelszavakat. Egy hibás újrafertőzési logika miatt ugyanazt a gépet sokszor megfertőzte, ez okozta a túlterhelést.
A DARPA ezután hozta létre a Carnegie Mellon Software Engineering Institute keretében a CERT Coordination Centert, az első szervezett incidenskezelő és sérülékenység koordináló csapatot.
Tanulság ma.
- A hálózati bizalom (ez a gép a belső hálón van, tehát megbízható) a zero trust ellentéte, és a laterális mozgás fő útja.
- A debug mód és a fejlesztői végpontok élesben maradása ma is az A02 Security Misconfiguration kategória.
- Az önterjesztő kód gyorsabb, mint az emberi reakció. A 2025 szeptemberi Shai-Hulud npm féreg ugyanezt csinálta npm tokenekkel. A válasz előre megírt runbook és automatizált kulcsvisszavonás.
- Koordinált sérülékenység közzététel kell. Minden projektnek legyen
SECURITY.mdéssecurity.txtfájlja.
Cliff Stoll, The Cuckoo's Egg (1989)
Clifford Stoll csillagász a Lawrence Berkeley Laborban egy 75 centes könyvelési eltérést vizsgált, és ebből egy hónapokig tartó nyomozás lett, amely egy katonai rendszerekbe behatoló, a KGB-nek dolgozó nyugatnémet csoporthoz vezetett. Ez az első részletesen dokumentált incidenskezelési esettanulmány.
Módszerek, amelyek innen származnak.
- Apró anomália komolyan vétele. A könyvelési eltérés egy integritási jelzés volt. Ma ez a nem egyező számla, a váratlan admin bejelentkezés, a hirtelen megugró kimenő forgalom.
- Független, manipulálhatatlan napló. Stoll nyomtatókat kötött a bejövő vonalakra, így a betolakodó nem tudta törölni a nyomait. Ma ez a különálló, írás után nem módosítható (WORM) naplótár.
- Megfigyelés a lekapcsolás előtt. A támadót hagyta dolgozni, hogy megértse a célját. Ma ez a containment döntés, amit tudatosan, a kockázatot mérlegelve hozunk meg.
- Csali. Hamis, vonzó dokumentumokat helyezett el, hogy a támadót bent tartsa. Ma ez a honeytoken és a canary token.
- Napló és jegyzet minden lépésről. Stoll naplója tette lehetővé a bírósági eljárást. Ma ez az incidens idővonal.
Aleph One, Smashing the Stack for Fun and Profit (1996)
A Phrack magazinban megjelent cikk közérthetően leírta a veremalapú puffer túlcsordulást, ahol egy határellenőrzés nélkül másolt bemenet felülírja a függvény visszatérési címét. A cikk után a memóriabiztonsági hibák évtizedekig a legsúlyosabb sérülékenység osztály maradtak.
Tanulság ma. TypeScript és Node alatt ritkán írunk ilyen kódot, de a natív függőségek (képfeldolgozás, tömörítés, parserek) igen. A válaszok a memóriabiztos nyelvek (Rust, Go), a fuzzing a parsereken, és az, hogy a bizonytalan bemenetet feldolgozó natív könyvtárat sandboxban vagy külön folyamatban futtatjuk. A CISA és a Five Eyes partnerek 2023 óta kifejezetten ajánlják a memóriabiztos nyelvekre átállás ütemtervét.
Schneier, Attack Trees (1999)
Bruce Schneier a Dr. Dobb's Journalban írta le a támadási fát. A gyökér a támadó célja, a gyerekcsomópontok a hozzá vezető alternatív (VAGY) vagy együttesen szükséges (ÉS) lépések. A levelekhez költséget, szükséges tudást, valószínűséget rendelünk, és így látszik, melyik út a legolcsóbb a támadónak. A fa a fenyegetésmodellezésben lépésenként kidolgozva tér vissza.
Howard és LeBlanc, Writing Secure Code, és a Microsoft SDL (2002 és 2004 között)
2002 januárjában Bill Gates Trustworthy Computing memója leállíttatta a Windows fejlesztését, hogy a mérnökök biztonsági képzést és kódátvizsgálást végezzenek. Michael Howard és David LeBlanc Writing Secure Code könyve (2002, második kiadás 2003) lett a kötelező olvasmány. Ebből nőtt ki 2004-re a Security Development Lifecycle (SDL), amely minden termékre kötelezővé tette a képzést, a fenyegetésmodellezést, a tiltott függvények listáját, a statikus elemzést, a fuzzingot és a kiadás előtti végső biztonsági review-t.
Az SDL lépései mai formában.
| SDL fázis | Kis csapatban ma |
|---|---|
| Képzés | Ez a kézikönyv, plusz az OWASP Cheat Sheet lapok |
| Követelmények | ASVS L1 vagy L2 kiválasztott tételei a ticketben |
| Tervezés | 5 perces fenyegetésmodell minden funkcióra |
| Implementáció | Tiltott minták listája (a kézikönyv végén), linter, semgrep |
| Verifikáció | SAST, SCA, secret scan CI-ban, DAST stagingen |
| Kiadás | Deploy előtti kapu, incidens runbook kész |
| Válasz | Sérülékenység bejelentési csatorna, patch folyamat |
A STRIDE születése (1999)
Loren Kohnfelder és Praerit Garg a Microsoftnál 1999-ben írta le a STRIDE betűszót egy belső dokumentumban, hogy a fejlesztők egy emlékezhető ellenőrzőlistával gondolhassák végig, mi romolhat el. A betűk a fenyegetéstípusok kezdőbetűi (Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege). A STRIDE azóta a leggyakrabban használt fenyegetésosztályozás, mert minden betűhöz egy jól definiált védelmi tulajdonság tartozik.
2. Fenyegetésmodellezés lépésről lépésre
A fenyegetésmodellezés a tervezés közbeni strukturált gondolkodás arról, mi romolhat el. Adam Shostack Threat Modeling: Designing for Security (2014) könyve tette mérnöki gyakorlattá, a Threats: What Every Engineer Should Learn from Star Wars (2023) pedig fenyegetésosztályonként tanítja, hogyan néz ki egy-egy hiba és mi a válasz rá. A 2020-ban közösen írt Threat Modeling Manifesto összefoglalja az elveket.
Shostack négy kérdése
- Min dolgozunk? Lerajzoljuk a rendszert (DFD), a szereplőket, az adatokat és a bizalmi határokat.
- Mi romolhat el? STRIDE elemenként vagy támadási fával végigmegyünk a diagramon.
- Mit teszünk ellene? Minden fenyegetésre egy döntés születik. Mérsékeljük, elfogadjuk, áthárítjuk (például Stripe kezeli a kártyaadatot), vagy kiküszöböljük a funkció megváltoztatásával.
- Jól csináltuk? A modell és a kód egyezik-e, minden fenyegetéshez van-e ticket, teszt, döntés.
A négy kérdés azért működik, mert nem követel meg eszközt vagy szakértőt. Egy whiteboard és harminc perc elég egy közepes funkcióhoz.
A Threat Modeling Manifesto elvei röviden
A manifesztum értékeket és elveket fogalmaz meg. Az emberek és a közös munka többet ér a folyamatnál és az eszköznél, a folyamatos finomítás pedig az egyszer leadott dokumentumnál. Fontosabb megtalálni a megoldandó problémákat, mint szépen formázni a jelentést. Akkor működik a legjobban a modellezés, ha korán és gyakran csináljuk, ha kockázatkezelési döntésekhez kötődik, és ha a csapat saját nyelvén szól.
Tipikus hibák, amelyeket a manifesztum is megnevez.
- Hős modellező. Egyetlen biztonsági szakértő csinálja, a csapat nem érti és nem tartja karban.
- Tökéletes reprezentáció hajszolása. Három napig rajzolunk diagramot, fenyegetést egyet sem találunk.
- Túl korai elemzési bénultság. A modell soha nem lesz kész, ezért nem is kezdjük el.
- Lezárt dokumentum. A modell a tervezés után a fiókba kerül, és a kód elválik tőle.
Adatfolyam diagram (DFD) bizalmi határokkal
A DFD négy elemből áll.
| Elem | Jel | Példa |
|---|---|---|
| Külső entitás | Téglalap | Felhasználó, Stripe, LLM szolgáltató |
| Folyamat | Kör vagy lekerekített téglalap | Next.js route handler, edge function |
| Adattár | Két párhuzamos vonal | Postgres, Supabase Storage, Redis |
| Adatfolyam | Nyíl | HTTPS kérés, webhook, SQL lekérdezés |
A bizalmi határ szaggatott vonal ott, ahol a jogosultsági szint vagy a tulajdonos megváltozik. Minden nyíl, amely bizalmi határt keresztez, fenyegetésjelölt. A legtöbb valós hiba ezeken a nyilakon keletkezik, mert az egyik oldal feltételez valamit, amit a másik nem garantál.
A DFD rajzolás lépései.
- Felrajzoljuk a külső entitásokat (böngésző, harmadik felek).
- Felvesszük a folyamatokat abban a granularitásban, ahol eltérő jogosultsággal futnak.
- Hozzáadjuk az adattárakat, és rájuk írjuk, milyen érzékenységű adat van bennük.
- Nyilakkal összekötjük az elemeket, a nyilakon jelöljük a protokollt és a hitelesítés módját.
- Behúzzuk a bizalmi határokat.
- Megszámozzuk a határt keresztező nyilakat. Ezek mennek a STRIDE táblába.
STRIDE elemenként
| Fenyegetés | Sérülő tulajdonság | Kérdés a diagramhoz | Tipikus védelem |
|---|---|---|---|
| Spoofing (megszemélyesítés) | Hitelesség (authenticity) | Ki lehet valaki más nevében? | Erős auth, MFA, passkey, webhook aláírás, mTLS |
| Tampering (manipuláció) | Integritás | Mit lehet útközben vagy tárolva módosítani? | TLS, aláírás, HMAC, RLS, szerveroldali validáció |
| Repudiation (letagadás) | Letagadhatatlanság | Ki tagadhatja le, hogy megtette? | Audit napló, aláírt események, időbélyeg |
| Information disclosure | Bizalmasság | Mi szivároghat ki és kinek? | Titkosítás, hozzáférés szabályozás, hibaüzenet szűkítés |
| Denial of service | Rendelkezésre állás | Mi teríthető le olcsón? | Rate limit, kvóta, timeout, költségkorlát |
| Elevation of privilege | Jogosultsági izoláció | Ki szerezhet több jogot? | Legkisebb jogosultság, szerveroldali authz, sandbox |
A Star Wars könyv a hat klasszikus kategória mellé hármat tesz, amelyeket érdemes a listán tartani.
- Kiszámíthatóság és véletlenszerűség. Tippelhető azonosítók, gyenge véletlenszám, kiszámítható reset tokenek. Védelem a
crypto.randomUUID()éscrypto.randomBytes(), sosemMath.random(). - Parsing és memóriasérülés. Minden parser bizalmi határ. Védelem a szigorú séma (zod), a méretkorlát és a memóriabiztos parser.
- Kill chain. A fenyegetések láncba fűződnek. Egy kis információszivárgás (belső azonosító) és egy kis authz hiba együtt teljes adatlopás.
Támadási fa (attack tree) készítése
- A gyökérbe a támadó konkrét célja kerül, például más bérlő számláinak letöltése.
- Ezt alternatív utakra bontjuk (VAGY). Közvetlen DB hozzáférés, API authz hiba, ellopott session, belső munkatárs.
- Ahol egy út több feltételt igényel, azokat ÉS kapcsolattal kötjük. Például ellopott session ÉS hiányzó újrahitelesítés az exportnál.
- A levelekhez költséget és valószínűséget írunk (alacsony, közepes, magas).
- Megkeressük a legolcsóbb utat, és ott kezdjük a védekezést.
- A fát verziókezelt szövegként tároljuk (Mermaid vagy egyszerű behúzott lista), hogy a PR-ban együtt változzon a kóddal.
CÉL: Más bérlő számláinak letöltése
├── VAGY: API objektumszintű authz hiba (BOLA) [olcsó, valószínű]
│ └── /api/invoices/:id nem ellenőrzi a tenant_id-t
├── VAGY: RLS kikapcsolva egy új táblán [olcsó, közepes]
├── VAGY: service_role kulcs a kliens bundle-ben [olcsó, ha megtörténik végzetes]
└── VAGY: Session lopás
├── ÉS: XSS a jegyzet mezőben
└── ÉS: export újrahitelesítés nélkül
PASTA röviden
A PASTA (Process for Attack Simulation and Threat Analysis, Tony UcedaVélez és Marco Morana, 2015) hétlépéses, kockázat központú módszer. Az üzleti célokból indul, a technikai hatókörön, az alkalmazás felbontásán, a fenyegetéselemzésen, a sérülékenységelemzésen és a támadásszimuláción keresztül jut el a kockázat és hatás elemzéséig. Nagyobb szervezetben és szabályozott környezetben (pénzügy, egészségügy) hasznos, ahol a biztonsági döntést üzleti kockázati nyelvre kell fordítani. Kis csapatnak a négy kérdés és a STRIDE általában elég, a PASTA első lépését (mi az üzleti kár, ha ez elromlik) viszont érdemes átvenni.
Mikor csináljunk fenyegetésmodellt
| Esemény | Mélység |
|---|---|
| Új termék vagy nagy architektúra döntés | Teljes DFD, STRIDE tábla, támadási fa a fő célokra, 1 és 3 óra között |
| Új funkció, ami bizalmi határt érint (auth, fizetés, fájl, külső API, LLM) | 15 és 30 perc közötti négy kérdéses kör |
| Bármilyen kisebb változtatás | 5 perces modell (a kézikönyv végén) |
| Incidens után | A modell frissítése azzal, ami kimaradt |
Kidolgozott példa, egy SaaS app (Next.js, Supabase, Stripe, LLM)
Rendszer. Egy B2B jegyzetelő és összefoglaló SaaS. A felhasználó bejelentkezik (Supabase Auth), szervezetekbe (tenant) tartozik, dokumentumokat tölt fel, amelyeket egy LLM összefoglal. Előfizetést Stripe Checkouton vásárol, a Stripe webhook frissíti az előfizetési állapotot.
1. kérdés, min dolgozunk. A DFD szövegesen.
[Böngésző] --(1) HTTPS, session cookie--> (Next.js app, Vercel)
||======================= BIZALMI HATÁR: internet / szerver ==============||
(Next.js) --(2) anon kulcs + user JWT--> [Supabase Postgres, RLS]
(Next.js szerver) --(3) service_role kulcs--> [Supabase Postgres] (csak admin műveletek)
[Böngésző] --(4) signed upload URL--> [Supabase Storage]
(Next.js) --(5) dokumentum szöveg--> [LLM szolgáltató API]
[Stripe] --(6) webhook, aláírt--> (Supabase edge function: stripe-webhook)
(edge function) --(7) service_role--> [Postgres: subscriptions]
(Next.js) --(8) Checkout session létrehozás, secret key--> [Stripe API]
||======================= BIZALMI HATÁR: tenant A / tenant B ============||
2. kérdés, mi romolhat el. STRIDE a határt keresztező nyilakon.
| # | Nyíl | STRIDE | Fenyegetés | Döntés és védelem |
|---|---|---|---|---|
| T1 | (1) | S | Session lopás XSS-sel | HttpOnly, Secure, SameSite=Lax cookie, szigorú CSP, React autoescape, dangerouslySetInnerHTML tiltva |
| T2 | (1) | T, E | Server action hívás jogosultság nélkül | Minden server action elején getUser() és tenant ellenőrzés, middleware nem elég |
| T3 | (2) | I, E | Más tenant adatainak olvasása | RLS minden táblán, policy tenant_id és tagság alapján, teszt, ami két tenanttal ellenőriz |
| T4 | (3) | E | service_role kulcs kiszivárog a kliensbe | Kulcs csak server-only modulban, nincs NEXT_PUBLIC_ előtag, gitleaks a CI-ban |
| T5 | (4) | T, D | Rosszindulatú vagy óriási fájl feltöltése | Méret és MIME korlát a signed URL-en, tartalom alapú típusellenőrzés, külön bucket, nem futtatható domain |
| T6 | (5) | I | Érzékeny adat megy az LLM szolgáltatóhoz | Adatfeldolgozói szerződés, zero retention beállítás, PII szűrés, tenant opt-in |
| T7 | (5) | E | Prompt injekció a feltöltött dokumentumban | Részletesen az AI ügynökök és vibecoding kézikönyvben. Alapszabály, hogy az LLM kimenete nem kap eszközt és nem kerül escape nélkül HTML-be |
| T8 | (6) | S, T | Hamis webhook, ingyenes előfizetés | Stripe aláírás ellenőrzés a nyers törzsön, esemény ID idempotencia, előfizetés állapot lekérése a Stripe API-ból |
| T9 | (8) | T | A kliens küldi az árat | Ár csak szerveroldali price_id alapján, a kliens csak csomagnevet választ |
| T10 | (1), (5) | D | Költségrobbanás LLM hívásokkal | Felhasználónkénti és tenantonkénti kvóta, token bucket rate limit, napi költségplafon riasztással |
| T11 | (1) | R | Felhasználó letagadja, hogy törölt egy dokumentumot | Audit napló a törlésről (ki, mikor, mit, honnan), append only tábla |
| T12 | (2) | E | Felhasználó saját magát adminná teszi profilfrissítéssel | Mass assignment védelem, a role mező nem írható RLS-ből, külön admin útvonal |
3. kérdés, mit teszünk ellene. Minden sorból ticket lesz, a ticket hivatkozik a T számra, és a hozzá tartozó teszt neve is tartalmazza (például rls_tenant_isolation_T3.test.ts). Az elfogadott kockázatok (például T6 maradék kockázata) dátummal és felelőssel az elfogadott kockázatok nyilvántartásába kerülnek.
4. kérdés, jól csináltuk. A PR template egy jelölőnégyzetet kap. Érint-e a változtatás bizalmi határt, és ha igen, frissült-e a modell. Negyedévente egyszer a csapat végigmegy a táblán, és megnézi, minden védelemhez van-e automatikus teszt.
A T2 és T3 fenyegetés kódszinten, sebezhető és javított változatban így néz ki.
// SEBEZHETŐ: T2 és T3. A server action csak azt nézi, be van-e lépve valaki.
'use server';
export async function deleteDocument(id: string) {
const supabase = createAdminClient(); // service_role, megkerüli az RLS-t
await supabase.from('documents').delete().eq('id', id);
}
// JAVÍTOTT: felhasználói kliens (RLS érvényes), explicit tagságellenőrzés, audit.
'use server';
import 'server-only';
import { z } from 'zod';
const Input = z.object({ id: z.string().uuid() });
export async function deleteDocument(raw: unknown) {
const { id } = Input.parse(raw);
const supabase = await createServerClient(); // a user JWT-jével fut
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new AuthError();
const { data: doc } = await supabase
.from('documents').select('id, tenant_id').eq('id', id).single();
if (!doc) throw new NotFoundError(); // RLS miatt idegen doksi nem is látszik
const { error } = await supabase.from('documents').delete().eq('id', id);
if (error) throw error;
await audit('document.delete', { actor: user.id, tenant: doc.tenant_id, target: id });
}
-- RLS a documents táblán. Alapból tilt, a policy engedélyez.
alter table documents enable row level security;
create policy "tag olvashatja a sajat tenant dokumentumait"
on documents for select
using (
exists (
select 1 from memberships m
where m.tenant_id = documents.tenant_id
and m.user_id = (select auth.uid())
)
);
create policy "tag torolhet a sajat tenantjaban"
on documents for delete
using (
exists (
select 1 from memberships m
where m.tenant_id = documents.tenant_id
and m.user_id = (select auth.uid())
and m.role in ('owner', 'editor')
)
);
3. OWASP Top 10 2025
A 2025-ös kiadás (véglegesítve 2025 végén) két új kategóriát hozott, és a nevekben a tünet helyett a gyökérokra helyezte a hangsúlyt. Az SSRF önálló kategóriaként megszűnt, az A01 része lett. A lista a 2026 októberi állapotot tükrözi. Ha egy projekt auditba vagy ügyfél elé kerül, a hivatkozás előtt az owasp.org/Top10 oldalon ellenőrizzük az aktuális szöveget.
| # | Kategória | Változás 2021-hez képest |
|---|---|---|
| A01 | Broken Access Control | Változatlanul első, magában foglalja az SSRF-et |
| A02 | Security Misconfiguration | Az 5. helyről feljött |
| A03 | Software Supply Chain Failures | Új név és bővült tartalom (korábban Vulnerable and Outdated Components) |
| A04 | Cryptographic Failures | A 2. helyről lejjebb |
| A05 | Injection | A 3. helyről lejjebb, az XSS is ide tartozik |
| A06 | Insecure Design | A 4. helyről lejjebb |
| A07 | Authentication Failures | Rövidebb név, azonos terület |
| A08 | Software or Data Integrity Failures | Hasonló, a build ellátási lánc része az A03-ba került |
| A09 | Security Logging and Alerting Failures | A Monitoring helyett Alerting, a riasztás a hangsúly |
| A10 | Mishandling of Exceptional Conditions | Új, hibakezelés, fail open, kivételes állapotok |
A01 Broken Access Control
Mi ez. A felhasználó olyan adathoz vagy funkcióhoz fér hozzá, amihez nincs joga. Ide tartozik az objektumszintű (IDOR, BOLA), a funkciószintű (admin végpont jogosultság nélkül), a CORS hiba, a JWT manipuláció és az SSRF.
// SEBEZHETŐ: az URL-ben jövő azonosítóra bízza magát.
export async function GET(_: Request, { params }: { params: { id: string } }) {
const invoice = await db.invoice.findUnique({ where: { id: params.id } });
return Response.json(invoice);
}
// JAVÍTOTT: az objektumot a felhasználó jogosultsági körén belül keressük.
export async function GET(_: Request, { params }: { params: { id: string } }) {
const user = await requireUser();
const invoice = await db.invoice.findFirst({
where: { id: params.id, tenant: { members: { some: { userId: user.id } } } },
});
if (!invoice) return new Response('Not found', { status: 404 });
return Response.json(invoice);
}
Védelem.
- Alapból tilt (deny by default), és az engedélyezés a szerveren történik.
- A jogosultsági döntés egy helyen él (RLS policy vagy központi
authorize()). - Next.js alatt a middleware nem jogosultsági határ. A 2025 márciusi CVE-2025-29927 megmutatta, hogy egy belső fejléc manipulálásával a middleware megkerülhető volt. Az ellenőrzést az adatelérés mellé tesszük (route handler, server action, data access layer).
- Az objektumazonosító lehet UUID, de a véletlen azonosító nem jogosultsági kontroll.
- Az SSRF elleni védekezést a webes alapvédelmeknél részletezzük.
Tesztelés. Két felhasználó, két tenant fixture. Minden végpontra automatikus teszt, ami A felhasználóval B erőforrását kéri, és 404-et vagy 403-at vár. Supabase alatt a pgTAP vagy egy egyszerű integrációs teszt két JWT-vel.
A02 Security Misconfiguration
Mi ez. Rossz alapértelmezés, bekapcsolva hagyott debug, nyilvános bucket, kikapcsolt RLS, hiányzó security header, túl bőbeszédű hibaüzenet, alapértelmezett jelszó.
// SEBEZHETŐ: a teljes hibát és stack trace-t visszaküldi.
catch (e) { return Response.json({ error: String(e), stack: (e as Error).stack }, { status: 500 }); }
// JAVÍTOTT: belül részletes napló korrelációs azonosítóval, kifelé általános üzenet.
catch (e) {
const ref = crypto.randomUUID();
logger.error({ ref, err: e }, 'invoice export failed');
return Response.json({ error: 'Belső hiba', ref }, { status: 500 });
}
Védelem. Infrastruktúra kódként (Terraform, Supabase migrációk), környezetenként azonos konfiguráció, a Supabase Security Advisor rendszeres futtatása (jelzi az RLS nélküli táblákat, a security definer nézeteket, a mutable search_path függvényeket), security headerek middleware-ben, X-Powered-By kikapcsolva (poweredByHeader: false a next.config-ban).
Tesztelés. Konfiguráció szkenner (Supabase advisor, checkov vagy trivy config az IaC-ra), ZAP baseline scan a headerekre, egy CI teszt, ami ellenőrzi, hogy minden public sémabeli táblán be van-e kapcsolva az RLS.
-- CI ellenőrzés: RLS nélküli táblák listája. Üres eredmény a cél.
select schemaname, tablename
from pg_tables
where schemaname = 'public' and rowsecurity = false;
A03 Software Supply Chain Failures
Mi ez. Sérülékeny, elavult, kompromittált vagy hamis függőség, megbízhatatlan build folyamat, ellopott publikálási token. A részletekre az ellátási lánc biztonságánál visszatérünk.
Védelem röviden. Lockfile és npm ci, SCA a CI-ban, Dependabot vagy Renovate, GitHub Actions SHA pinning, trusted publishing, SBOM.
Tesztelés. npm audit --omit=dev, osv-scanner, a lockfile változásainak review-ja minden PR-ban.
A04 Cryptographic Failures
Mi ez. Titkosítás hiánya érzékeny adatnál, gyenge algoritmus (MD5, SHA1 jelszóhoz), saját kripto, rossz véletlenszám, hardkódolt kulcs, TLS ellenőrzés kikapcsolva.
// SEBEZHETŐ: gyors hash jelszóra, kiszámítható token.
const hash = createHash('sha256').update(password).digest('hex');
const resetToken = Math.random().toString(36).slice(2);
// JAVÍTOTT: lassú, sózott jelszó hash és kriptográfiailag erős token.
import { hash, verify } from '@node-rs/argon2';
const pwHash = await hash(password); // Argon2id, alapértelmezett paraméterek
const resetToken = randomBytes(32).toString('base64url');
await db.reset.create({ data: { tokenHash: sha256(resetToken), expiresAt: in15min() } });
Védelem. Jelszóhoz Argon2id, scrypt vagy bcrypt (vagy hagyjuk a Supabase Auth-ra). Szimmetrikus titkosításhoz AES-256-GCM vagy a libsodium. A tokeneket hash-elve tároljuk. TLS 1.2 vagy 1.3 mindenhol, HSTS. A kulcsok KMS-ben vagy secret managerben, rotációs tervvel. A poszt kvantum átállásra (NIST FIPS 203, 204, 205, 2024) a nagy szolgáltatók TLS szinten már felkészültek, saját kódban a kripto agilitás (cserélhető algoritmus) a feladat.
Tesztelés. Semgrep szabályok a Math.random, createHash('md5'), rejectUnauthorized: false mintákra, testssl.sh vagy SSL Labs a TLS-re.
A05 Injection
Mi ez. Megbízhatatlan adat értelmezőhöz jut (SQL, NoSQL, OS shell, LDAP, template, HTML és JavaScript a böngészőben), és ott kódként fut. Az XSS 2021 óta ebbe a kategóriába tartozik.
// SEBEZHETŐ: string összefűzés SQL-ben.
const rows = await sql.unsafe(`select * from users where email = '${email}'`);
// JAVÍTOTT: paraméterezett lekérdezés (postgres.js tagged template).
const rows = await sql`select * from users where email = ${email}`;
// SEBEZHETŐ: shell parancs felhasználói bemenettel.
exec(`convert ${file} out.png`);
// JAVÍTOTT: argumentumtömb, shell nélkül, előtte allowlist validáció.
execFile('convert', [safePath(file), 'out.png']);
Supabase alatt a supabase.rpc() paraméterei biztonságosak, de egy plpgsql függvényen belüli execute format('... %s', input) újra nyitja a rést. Ott %L (literál) vagy %I (azonosító) kell, vagy execute ... using.
Védelem. Paraméterezés, ORM vagy query builder, kimenet kódolás a célkontextus szerint, allowlist validáció (zod séma), a dinamikus azonosítók (oszlopnév, rendezés) allowlistből.
Tesztelés. Semgrep (javascript.lang.security, typescript.react.security szabálycsomagok), DAST stagingen, unit teszt rosszindulatú bemenetekkel a validátorra.
A06 Insecure Design
Mi ez. A hiba a tervben van, a kód hibátlanul valósítja meg. Például a jelszó visszaállítás biztonsági kérdéssel, a korlátlan kupon beváltás, az ár a kliensről, a többlépcsős folyamat, ahol a lépések kihagyhatók.
// SEBEZHETŐ TERV: a kliens mondja meg az árat.
const session = await stripe.checkout.sessions.create({
line_items: [{ price_data: { currency: 'huf', unit_amount: body.amount, product_data: { name: body.plan } }, quantity: 1 }],
mode: 'payment', success_url, cancel_url,
});
// JAVÍTOTT TERV: a szerver allowlistből választ árat, a kliens csak csomagot jelöl.
const PRICES = { pro: process.env.STRIPE_PRICE_PRO!, team: process.env.STRIPE_PRICE_TEAM! } as const;
const plan = z.enum(['pro', 'team']).parse(body.plan);
const session = await stripe.checkout.sessions.create({
line_items: [{ price: PRICES[plan], quantity: 1 }],
mode: 'subscription', customer: await customerIdFor(user), success_url, cancel_url,
}, { idempotencyKey: `checkout:${user.id}:${plan}:${today()}` });
Védelem. Fenyegetésmodell, visszaélési esetek (abuse case) a user story mellé, állapotgépek a többlépcsős folyamatokra, üzleti limitek (kvóta, sebesség, összeghatár).
Tesztelés. Abuse case tesztek (mi van, ha kétszer küldi, ha kihagy egy lépést, ha párhuzamosan küldi), versenyhelyzet teszt párhuzamos kérésekkel.
A07 Authentication Failures
Mi ez. Credential stuffing elleni védelem hiánya, gyenge jelszó politika, session fixáció, hosszú életű token visszavonás nélkül, MFA hiánya, felhasználó felsorolás a hibaüzenetből.
Védelem.
- Saját auth helyett bevált szolgáltató (Supabase Auth, Auth.js, Clerk) vagy jól ismert könyvtár.
- Passkey (WebAuthn) vagy TOTP MFA, admin fiókokon kötelezően.
- A NIST SP 800-63B szerint a hossz számít, nem a bonyolultsági szabály. Kiszivárgott jelszó lista ellenőrzés (HIBP k-anonymity API), nincs kötelező periodikus csere.
- Egységes hibaüzenet és azonos válaszidő (érvénytelen email vagy jelszó).
- Rate limit és fokozatos késleltetés bejelentkezésre, felhasználónként és IP-nként.
- Session ID csere bejelentkezéskor, kijelentkezéskor szerveroldali érvénytelenítés.
- Supabase alatt szerveren
auth.getUser()(ellenőrzi a tokent az auth szerveren vagy a JWKS-sel), és nem a cookie-ból olvasott, ellenőrizetlengetSession()eredmény a jogosultsági döntés alapja.
Tesztelés. Automatikus teszt a felsorolásra (két eltérő hibaüzenet tilos), rate limit teszt, ZAP authenticated scan.
A08 Software or Data Integrity Failures
Mi ez. Integritásellenőrzés nélkül elfogadott kód vagy adat. Aláíratlan webhook, CDN-ről betöltött script SRI nélkül, nem biztonságos deszerializáció, automatikus frissítés aláírás nélkül, cache mérgezés.
// SEBEZHETŐ: Stripe webhook aláírás nélkül, JSON-ba parse-olt törzzsel.
export async function POST(req: Request) {
const event = await req.json();
if (event.type === 'checkout.session.completed') await activate(event.data.object.customer);
return new Response('ok');
}
// JAVÍTOTT: Supabase edge function, nyers törzs, aláírás és idempotencia.
import Stripe from 'npm:stripe@17';
const stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!);
const whsec = Deno.env.get('STRIPE_WEBHOOK_SECRET')!;
Deno.serve(async (req) => {
const sig = req.headers.get('stripe-signature');
const body = await req.text(); // nyers törzs kell az aláíráshoz
let event: Stripe.Event;
try {
event = await stripe.webhooks.constructEventAsync(body, sig!, whsec);
} catch {
return new Response('invalid signature', { status: 400 });
}
const { error } = await admin.from('stripe_events').insert({ id: event.id }); // unique PK
if (error?.code === '23505') return new Response('duplicate', { status: 200 });
await handle(event); // az állapotot a Stripe API-ból kérjük le újra
return new Response('ok');
});
Ennek az edge functionnek a verify_jwt = false beállítás kell (a Stripe nem küld Supabase JWT-t), ezért a hitelesítést itt az aláírás adja. Ez egy tudatos kivétel, amit a konfigurációban kommenttel jelölünk.
Védelem. Aláírás ellenőrzés minden bejövő integráción, SRI (integrity attribútum) külső scripteken, deszerializáláskor séma validáció, aláírt artefaktumok.
Tesztelés. Teszt, ami aláíratlan és lejárt időbélyegű webhookot küld és 400-at vár.
A09 Security Logging and Alerting Failures
Mi ez. A biztonsági esemény nem kerül naplóba, a napló nem jut el senkihez, vagy a riasztás annyira zajos, hogy senki nem nézi. Az átnevezés jelzi, hogy a napló riasztás nélkül keveset ér. A részletekre a naplózásnál visszatérünk.
Tesztelés. Évente legalább egy gyakorlat, ahol szándékosan kiváltunk egy eseményt (sikertelen admin login sorozat) és mérjük, mennyi idő alatt jut el emberhez.
A10 Mishandling of Exceptional Conditions
Mi ez. A rendszer váratlan állapotban (hiba, timeout, null, erőforrás kimerülés, részleges siker) bizonytalan vagy nyitott állapotba kerül. Tipikus a fail open, ahol egy hibát elnyelő catch engedélyez. Ide tartozik a félbeszakadt tranzakció, ami fél állapotot hagy, és a hibaüzenetből szivárgó belső információ is.
// SEBEZHETŐ: fail open. Ha a jogosultsági szolgáltatás elérhetetlen, mindent enged.
async function canExport(userId: string) {
try { return await authz.check(userId, 'export'); }
catch { return true; }
}
// JAVÍTOTT: fail closed, naplózva, időkorláttal.
async function canExport(userId: string): Promise<boolean> {
try {
return await withTimeout(authz.check(userId, 'export'), 2000);
} catch (e) {
logger.warn({ userId, err: e }, 'authz check failed, denying');
return false;
}
}
// SEBEZHETŐ: két külön írás, a második hibája fél állapotot hagy (kredit levonva, munka nem indult).
await db.credits.decrement(user.id, cost);
await queue.enqueue(job);
// JAVÍTOTT: egy tranzakció és outbox minta. A sor felvétele ugyanabban a tranzakcióban történik.
await db.$transaction(async (tx) => {
await tx.credits.decrement(user.id, cost);
await tx.outbox.create({ data: { type: 'job.start', payload: job } });
});
Védelem. Fail closed alapértelmezés, explicit timeout minden külső hívásra, tranzakciók és idempotencia, globális hibakezelő, ami nem szivárogtat, erőforráskorlát (méret, idő, memória, rekurziós mélység).
Tesztelés. Hibainjektálás (a függőség timeoutol, 500-at ad, üres választ ad), chaos teszt stagingen, a catch blokkok review-ja.
4. OWASP ASVS 5.0, API Security Top 10 és a Cheat Sheet Series
ASVS 5.0 (2025 május)
Az Application Security Verification Standard a Top 10-zel szemben követelménylista. A Top 10 tudatosító dokumentum, az ASVS ellenőrizhető tételekből áll, ezért szerződésbe, ticketbe, pentest hatókörbe írható. Az 5.0.0 verzió 2025 májusában jelent meg, nagyjából 350 követelményt tartalmaz 17 fejezetben, és teljesen átszámozta a korábbi 4.0.3 tételeket.
| Fejezet | Terület |
|---|---|
| V1 | Encoding and Sanitization |
| V2 | Validation and Business Logic |
| V3 | Web Frontend Security |
| V4 | API and Web Service |
| V5 | File Handling |
| V6 | Authentication |
| V7 | Session Management |
| V8 | Authorization |
| V9 | Self-contained Tokens (JWT és társai) |
| V10 | OAuth and OIDC |
| V11 | Cryptography |
| V12 | Secure Communication |
| V13 | Configuration |
| V14 | Data Protection |
| V15 | Secure Coding and Architecture |
| V16 | Security Logging and Error Handling |
| V17 | WebRTC |
Szintek.
| Szint | Kinek | Gyakorlatban |
|---|---|---|
| L1 | Minden alkalmazás, alacsony kockázat | Az első védelmi vonal, a legolcsóbban megvalósítható és legtöbbet érő tételek |
| L2 | Érzékeny adatot kezelő üzleti app (a legtöbb B2B SaaS) | Az ajánlott alapszint, ide tartozik a tételek nagyobb része |
| L3 | Kritikus rendszer (egészségügy, pénzügy, infrastruktúra) | Mélyebb tervezési és verifikációs követelmények |
A szintek kumulatívak, az L2 tartalmazza az L1-et.
Használat követelménylistaként lépésről lépésre.
- Célszintet választunk a fenyegetésmodell és az adatérzékenység alapján. Egy Supabase alapú B2B SaaS-nél ez L2.
- Kihúzzuk a releváns fejezeteket. WebRTC nélkül a V17 kimarad, saját OAuth szerver nélkül a V10 jó része is.
- A tételeket verziózott azonosítóval hivatkozzuk (például
v5.0.0-8.2.1), mert a régi és új számozás nem keverhető. - Minden tételhez rögzítjük, hol és hogyan teljesül (kód hely, konfiguráció, teszt), vagy miért nem releváns.
- Az új funkció ticketjébe a releváns ASVS tételek kerülnek elfogadási kritériumként.
- A pentest hatókörét az ASVS szint és fejezetek szerint adjuk meg, így a jelentés összevethető.
Tipikus hiba. Az egész ASVS-t egyszerre próbáljuk teljesíteni, és a táblázat soha nem készül el. Jobb kezdés az L1 a V6, V7, V8 fejezetekből, mert ott keletkezik a legtöbb valós kár.
OWASP API Security Top 10 (2023)
A REST és GraphQL API-k sajátos hibáit gyűjti. Egy Next.js plus Supabase app minden route handlere és a PostgREST felület is API.
| # | Kategória | Mit jelent egy SaaS-ben | Védelem |
|---|---|---|---|
| API1 | Broken Object Level Authorization | Más tenant objektuma ID alapján elérhető | RLS, tenant szűrés minden lekérdezésben |
| API2 | Broken Authentication | Gyenge token kezelés, hiányzó rate limit | Bevált auth, rövid életű token, MFA |
| API3 | Broken Object Property Level Authorization | Túl sok mező a válaszban, vagy írható role mező | Explicit select lista, DTO, írási allowlist |
| API4 | Unrestricted Resource Consumption | Lapozás nélküli lista, korlátlan fájl, LLM költség | Limit, lapozás, kvóta, timeout |
| API5 | Broken Function Level Authorization | Admin végpont sima felhasználónak | Szerepkör ellenőrzés a funkció szintjén |
| API6 | Unrestricted Access to Sensitive Business Flows | Kupon, regisztráció, foglalás tömeges automatizálása | Üzleti rate limit, bot észlelés, kvóta |
| API7 | Server Side Request Forgery | URL előnézet belső címre | Allowlist, DNS ellenőrzés, egress szűrés |
| API8 | Security Misconfiguration | Nyitott CORS, debug végpont | Szigorú CORS, header, konfiguráció review |
| API9 | Improper Inventory Management | Elfelejtett v1 vagy staging API élesen | API leltár, régi verziók kikapcsolása |
| API10 | Unsafe Consumption of APIs | Harmadik fél válaszát vakon elfogadjuk | Validáció és timeout a bejövő harmadik fél adatra is |
// SEBEZHETŐ: API3. A teljes kérés törzset beírja a profilba, így a role is írható.
await supabase.from('profiles').update(await req.json()).eq('id', user.id);
// JAVÍTOTT: írási allowlist séma, és az RLS sem engedi a role oszlopot.
const ProfileUpdate = z.object({ display_name: z.string().max(80), avatar_url: z.string().url().optional() }).strict();
await supabase.from('profiles').update(ProfileUpdate.parse(await req.json())).eq('id', user.id);
-- Oszlopszintű védelem: a hitelesített szerepkör csak a megengedett oszlopokat frissítheti.
revoke update on profiles from authenticated;
grant update (display_name, avatar_url) on profiles to authenticated;
Cheat Sheet Series, a legfontosabb lapok
Az OWASP Cheat Sheet Series (cheatsheetseries.owasp.org) témánként tömör, gyakorlati útmutató. Egy webes SaaS-hez ezeket érdemes ismerni.
| Lap | Mikor hasznos |
|---|---|
| Authentication, Password Storage, Multifactor Authentication | Auth folyamat, jelszó tárolás |
| Session Management | Cookie beállítás, session élettartam |
| Authorization, Insecure Direct Object Reference Prevention | Jogosultsági modell, BOLA |
| Cross Site Scripting Prevention, DOM based XSS Prevention | Bármi, ami HTML-t renderel |
| Content Security Policy | CSP bevezetés |
| Cross-Site Request Forgery Prevention | Cookie alapú auth mellett |
| Server Side Request Forgery Prevention | URL-t fogadó funkció |
| SQL Injection Prevention, Query Parameterization | Nyers SQL írásakor |
| File Upload | Feltöltés |
| Input Validation, Mass Assignment | Bejövő adat kezelése |
| Logging, Logging Vocabulary | Naplózás tervezése |
| Secrets Management | Kulcskezelés |
| REST Security, GraphQL | API tervezés |
| Deserialization | Nem JSON vagy objektum visszaállítás |
| HTTP Headers, HTTP Strict Transport Security | Header konfiguráció |
| NPM Security, Software Supply Chain Security | Függőségkezelés |
| Threat Modeling | Modellezés kezdése |
5. Webes alapvédelmek részletesen
XSS típusai és a CSP
| Típus | Hol keletkezik | Példa SaaS-ben |
|---|---|---|
| Reflected | A szerver a kérésből visszatükröz | Keresési kifejezés a találati oldalon kódolás nélkül |
| Stored | Tárolt adat renderelődik másnak | Jegyzet, kommentár, profil név |
| DOM based | Kliens JS ír a DOM-ba nem biztonságos forrásból | location.hash értéke innerHTML-be |
| Mutation XSS | A sanitizer és a böngésző parsere eltérően értelmez | Saját regex alapú HTML tisztító |
A React és a Next.js alapból kódolja a JSX-be írt szöveget. A rés ott nyílik, ahol ezt megkerüljük.
// SEBEZHETŐ: felhasználói vagy LLM által generált HTML közvetlenül.
<div dangerouslySetInnerHTML={{ __html: note.body }} />
<a href={user.website}>Weboldal</a> {/* javascript: séma is lehet */}
// JAVÍTOTT: sanitizálás egy bevált könyvtárral, URL séma allowlist.
import DOMPurify from 'isomorphic-dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(note.body, { USE_PROFILES: { html: true } }) }} />
const safeHref = (u: string) => { try { const x = new URL(u); return ['https:', 'http:'].includes(x.protocol) ? x.href : '#'; } catch { return '#'; } };
<a href={safeHref(user.website)} rel="noopener noreferrer">Weboldal</a>
Markdown renderelésnél (például LLM kimenet) a react-markdown alapból nem renderel nyers HTML-t. Ezt nem kapcsoljuk be rehype-raw-val sanitizálás nélkül.
Content Security Policy. A CSP a második védelmi vonal. Ha mégis bejut egy script, a böngésző nem futtatja. A modern, nonce alapú szigorú CSP mintája Next.js middleware-ben.
// middleware.ts: nonce alapú szigorú CSP.
export function middleware(req: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const csp = [
`default-src 'self'`,
`script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`,
`style-src 'self' 'nonce-${nonce}'`,
`img-src 'self' data: https://*.supabase.co`,
`connect-src 'self' https://*.supabase.co https://api.stripe.com`,
`frame-src https://js.stripe.com https://checkout.stripe.com`,
`object-src 'none'`, `base-uri 'none'`, `frame-ancestors 'none'`, `form-action 'self'`,
`upgrade-insecure-requests`,
].join('; ');
const headers = new Headers(req.headers);
headers.set('x-nonce', nonce);
const res = NextResponse.next({ request: { headers } });
res.headers.set('Content-Security-Policy', csp);
return res;
}
CSP bevezetés lépései.
- A szabály
Content-Security-Policy-Report-Onlymódban indul egy riport végponttal (report-to). - Egy-két hétig gyűjtjük a sértéseket, és az inline scripteket nonce-ra javítjuk.
- Élesre kapcsoljuk, a riportolás bekapcsolva marad.
- A script-src nem kap
'unsafe-inline'és'unsafe-eval'értéket. Ha egy könyvtár igényli, mást keresünk helyette. - Opcionálisan a Trusted Types (
require-trusted-types-for 'script') a DOM XSS ellen.
CSRF és SameSite
A CSRF akkor él, ha a böngésző automatikusan csatolja a hitelesítő cookie-t egy idegen oldalról indított kéréshez.
| Védelem | Mit ad | Megjegyzés |
|---|---|---|
SameSite=Lax cookie | Idegen oldalról jövő POST nem viszi a cookie-t | Modern böngésző alapértelmezés, de explicit beállítjuk |
SameSite=Strict | Semmilyen cross site navigáció nem viszi | Kényelmetlen, külső linkről kijelentkezettnek látszik |
| Anti CSRF token (synchronizer vagy double submit) | Független a cookie viselkedéstől | Klasszikus űrlapoknál |
Origin és Sec-Fetch-Site ellenőrzés | Olcsó, megbízható modern böngészőben | Next.js server actions beépítetten ellenőrzi az Origin és Host egyezést |
| Bearer token a header-ben cookie helyett | Nincs automatikus csatolás | Viszont a token tárolása XSS kockázat |
A GET kérés soha nem változtat állapotot. A Next.js server actions POST-ot használ és összeveti az Origin fejlécet a hosttal. Reverse proxy mögött a serverActions.allowedOrigins beállítást szűkre vesszük.
CORS helyes beállítása
A CORS nem védelem, hanem a same origin policy kontrollált lazítása. A hiba mindig a túl tág engedély.
// SEBEZHETŐ: visszatükrözi a kérő origint és engedi a cookie-t.
res.headers.set('Access-Control-Allow-Origin', req.headers.get('origin') ?? '*');
res.headers.set('Access-Control-Allow-Credentials', 'true');
// JAVÍTOTT: explicit allowlist, Vary fejléc, credentials csak ahol kell.
const ALLOWED = new Set(['https://app.pelda.hu', 'https://admin.pelda.hu']);
const origin = req.headers.get('origin');
if (origin && ALLOWED.has(origin)) {
res.headers.set('Access-Control-Allow-Origin', origin);
res.headers.set('Access-Control-Allow-Credentials', 'true');
res.headers.set('Vary', 'Origin');
}
Szabályok. A * credentials mellett nem működik és nem is kell. Regexszel vagy végződés alapján nem illesztünk (endsWith('pelda.hu') átengedi a gonoszpelda.hu címet). A null origint nem engedjük. Supabase edge functionnél a CORS fejlécet mi állítjuk be, a sablonban szereplő * csak publikus, cookie nélküli végpontra jó.
SSRF védekezés
Az SSRF akkor keletkezik, ha a szerver a felhasználó által megadott URL-t kéri le (link előnézet, webhook cél, kép importálás, PDF generálás URL-ből). A támadó belső címet ad meg, és a szerver a saját hálózati pozíciójából éri el, például a felhő metaadat szolgáltatást.
// SEBEZHETŐ: bármilyen URL-t lekér.
const html = await fetch(body.url).then((r) => r.text());
// JAVÍTOTT: séma és port allowlist, DNS feloldás után IP ellenőrzés, átirányítás kézzel, timeout, méretkorlát.
import { lookup } from 'node:dns/promises';
import ipaddr from 'ipaddr.js';
async function safeFetch(raw: string) {
const url = new URL(raw);
if (url.protocol !== 'https:' || (url.port && url.port !== '443')) throw new Error('blocked');
const addrs = await lookup(url.hostname, { all: true });
for (const { address } of addrs) {
if (ipaddr.parse(address).range() !== 'unicast') throw new Error('blocked'); // privát, loopback, link local tiltva
}
const res = await fetch(url, { redirect: 'manual', signal: AbortSignal.timeout(5000) });
if (res.status >= 300 && res.status < 400) throw new Error('redirect not followed');
return readLimited(res, 2_000_000);
}
A fenti kód csökkenti, de nem zárja ki a DNS rebinding kockázatot, mert az ellenőrzés és a kapcsolódás két külön feloldás. Erősebb megoldás, ha a kapcsolat a már ellenőrzött IP-re épül (egyedi lookup az HTTP agentben), vagy ha a kimenő kéréseket egy egress proxy (például Smokescreen) végzi, ami hálózati szinten tiltja a belső tartományokat. Felhőben az IMDSv2 kötelezővé tétele (AWS) is csökkenti a kárt.
Nyílt átirányítás
// SEBEZHETŐ: login után bárhová visszairányít.
redirect(searchParams.get('next') ?? '/');
// JAVÍTOTT: csak saját, relatív útvonal.
function safeNext(n: string | null) {
if (!n || !n.startsWith('/') || n.startsWith('//') || n.startsWith('/\\')) return '/';
return n;
}
redirect(safeNext(searchParams.get('next')));
A nyílt átirányítás phishinghez és OAuth token lopáshoz vezet. Az OAuth redirect URI-t mindig pontos egyezéssel regisztráljuk a szolgáltatónál (Supabase Auth URL allowlist), wildcard nélkül.
Fájlfeltöltés biztonsága
| Kockázat | Védelem |
|---|---|
| Futtatható tartalom (HTML, SVG scripttel) a saját domainen | Külön, cookie nélküli domainről szolgáljuk ki, Content-Disposition: attachment, X-Content-Type-Options: nosniff |
| Hamis kiterjesztés | Tartalom alapú típusfelismerés (magic bytes, file-type), allowlist |
| Óriási fájl, tömörítési bomba | Méretkorlát a signed URL-en és a feldolgozásnál, kibontási korlát |
| Útvonal manipuláció a fájlnévben | Saját generált név (UUID), az eredeti név csak metaadat |
| Kártevő | Víruskeresés aszinkron (ClamAV vagy szolgáltatói scan), karantén bucket |
| Más tenant fájlja | Storage RLS policy a tenant prefixre |
| Képfeldolgozó könyvtár sérülékenysége | Sandbox vagy külön worker, frissített sharp és libvips |
-- Supabase Storage: csak a saját tenant mappájába írhat a tag.
create policy "tenant upload"
on storage.objects for insert to authenticated
with check (
bucket_id = 'uploads'
and (storage.foldername(name))[1] in (
select tenant_id::text from memberships where user_id = (select auth.uid())
)
);
Deszerializáció
A JSON.parse önmagában adatot ad vissza, de ha az eredményt vakon objektumokba olvasztjuk, prototype pollution keletkezhet (__proto__ kulcs egy mély merge-ben). Más formátumoknál (YAML teljes sémával, node-serialize, Java vagy PHP natív szerializáció, pickle) a deszerializáció kódfuttatást is jelenthet. 2025 decemberében a React Server Components Flight protokolljában talált kritikus sérülékenység (CVE-2025-55182) azt mutatta, hogy egy keretrendszer saját szerializációs formátuma is ilyen bizalmi határ, és a javítást gyorsan telepíteni kellett minden érintett Next.js verzión.
// SEBEZHETŐ: mély merge ellenőrizetlen bemenettel.
const settings = merge(defaults, JSON.parse(body));
// JAVÍTOTT: séma validáció, ismeretlen kulcsok elutasítva, prototípus nélküli objektum.
const Settings = z.object({ theme: z.enum(['light', 'dark']), locale: z.string().max(10) }).strict();
const settings = { ...defaults, ...Settings.parse(JSON.parse(body)) };
YAML-nál yaml csomag alapértelmezett, biztonságos sémája, és soha nem használunk olyan formátumot, ami osztálypéldányt állít vissza megbízhatatlan forrásból. A keretrendszer biztonsági frissítéseire külön riasztás kell (GitHub security advisory feliratkozás a next és react csomagokra).
Security headerek listája
| Header | Ajánlott érték | Mit véd |
|---|---|---|
Content-Security-Policy | Nonce alapú, a fenti minta szerint | XSS, adatszivárgás, clickjacking (frame-ancestors) |
Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | SSL stripping |
X-Content-Type-Options | nosniff | MIME szaglás |
X-Frame-Options | DENY (régi böngészőknek, a CSP mellé) | Clickjacking |
Referrer-Policy | strict-origin-when-cross-origin vagy no-referrer | URL-ben lévő adat szivárgása |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Böngésző API visszaélés |
Cross-Origin-Opener-Policy | same-origin | Cross window támadások, XS leak |
Cross-Origin-Resource-Policy | same-origin vagy same-site | Erőforrás beágyazás idegen oldalon |
Cross-Origin-Embedder-Policy | require-corp (ha kell izoláció) | Spectre jellegű szivárgás |
Cache-Control | no-store érzékeny válaszokon | Megosztott cache-ben maradó adat |
X-Powered-By | Eltávolítva | Felderítés |
Rate limiting algoritmusai
| Algoritmus | Működés | Előny | Hátrány |
|---|---|---|---|
| Fixed window | Számláló időablakonként | Egyszerű, olcsó | Az ablakhatáron dupla burst |
| Sliding log | Minden kérés időbélyege | Pontos | Memóriaigényes |
| Sliding window counter | Két ablak súlyozott átlaga | Jó közelítés, olcsó | Közelítés |
| Token bucket | Vödör tokenekkel, fix ütemben töltődik | Burst engedhető, átlag korlátos | Két paraméter hangolása |
| Leaky bucket | Sor fix kifolyási sebességgel | Egyenletes kimenet | Burst késleltetve |
| GCRA | Token bucket időbélyeggel, egy értékkel | Hatékony, Redisben atomikus | Nehezebben érthető |
Kulcsválasztás. Bejelentkezésnél felhasználónév és IP külön-külön. API-nál felhasználó vagy API kulcs, nem IP (NAT mögött sokan osztoznak). Drága műveletnél (LLM, export) tenant szintű kvóta is. Serverless környezetben a számláló külső tárban kell legyen (Upstash Redis, Postgres), mert a példányok nem osztoznak memórián.
// Token bucket Upstash Ratelimit könyvtárral, felhasználónként.
import { Ratelimit } from '@upstash/ratelimit';
const limiter = new Ratelimit({ redis, limiter: Ratelimit.tokenBucket(10, '1 m', 20) });
const { success, reset } = await limiter.limit(`summarize:${user.id}`);
if (!success) return new Response('Too Many Requests', { status: 429, headers: { 'Retry-After': String(Math.ceil((reset - Date.now()) / 1000)) } });
6. Ellátási lánc biztonság
A modern webapp kódjának túlnyomó része függőség. A támadók ezért egyre gyakrabban a függőséget, a build folyamatot vagy a publikálási jogot támadják. Thompson 1984-es kérdése ma minden npm install alkalmával felmerül.
SLSA szintek
A SLSA (Supply chain Levels for Software Artifacts, slsa.dev) a build integritásának lépcsőzetes keretrendszere. Az 1.x specifikáció build trackje az alábbi szinteket határozza meg, a frissebb kiadások ezt forrás (source) trackkel egészítik ki, ami a verziókezelő védelmére vonatkozik.
| Szint | Követelmény | Mit véd |
|---|---|---|
| Build L0 | Nincs garancia | Semmit |
| Build L1 | Létezik provenance (ki, mit, miből épített) | Hibák és tévedések felderítése |
| Build L2 | Hosztolt build platform aláírja a provenance-t | Build utáni manipuláció |
| Build L3 | Megerősített, izolált build, a titkok nem érhetők el a build lépésekből | Build közbeni manipuláció |
Kis projektben. A GitHub Actions hosztolt runner és a actions/attest-build-provenance vagy az npm --provenance publikálás (trusted publishing OIDC-vel) gyakorlatilag L2-t ad, a reusable workflow alapú izolált build közelít az L3-hoz.
SBOM (CycloneDX, SPDX)
A Software Bill of Materials a szoftver összetevőinek gépi úton olvasható listája verziókkal és licencekkel. Két fő formátum létezik. A CycloneDX (OWASP, biztonsági fókuszú, VEX támogatással) és az SPDX (Linux Foundation, ISO/IEC 5962 szabvány, licenc fókuszú eredettel).
# SBOM generálás és szkennelés kis projektben
npx @cyclonedx/cyclonedx-npm --output-file sbom.cdx.json
osv-scanner scan --sbom=sbom.cdx.json
Az SBOM akkor ér valamit, ha egy új CVE megjelenésekor percek alatt megmondjuk belőle, érintett-e a termék. Ehhez minden kiadáshoz tároljuk, és az EU Cyber Resilience Act (CRA) jelentési kötelezettségei 2026 szeptemberétől erre építenek a digitális elemeket tartalmazó termékeknél.
Sigstore
A Sigstore (cosign, Fulcio, Rekor) kulcs nélküli aláírást ad. A fejlesztő vagy a CI OIDC identitással rövid életű tanúsítványt kap, aláír, és az aláírás egy nyilvános átláthatósági naplóba kerül. Így nem kell hosszú életű aláíró kulcsot őrizni. Az npm provenance, a PyPI attestations és a GitHub artifact attestations mind erre épül.
# Konténer kép aláírása és ellenőrzése CI identitással
cosign sign ghcr.io/ceg/app@sha256:...
cosign verify ghcr.io/ceg/app@sha256:... \
--certificate-identity-regexp 'https://github.com/ceg/app/.github/workflows/release.yml@.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Lockfile fegyelem
- A
package-lock.json(vagypnpm-lock.yaml) verziókezelt, és CI-bannpm cifut, ami eltérés esetén hibát dob. - A lockfile változását a PR-ban review-zuk. Egy feature PR-ban váratlanul felbukkanó új tranzitív függőség gyanús.
npm config set ignore-scripts truevagy pnpm alatt az install scriptek alapértelmezett tiltása, csak a szükséges csomagoknál engedélyezve (onlyBuiltDependencies). A 2025-ös npm férgek install scripten keresztül terjedtek.- Frissítés késleltetéssel. A Renovate
minimumReleaseAge(például 3 nap) vagy a pnpmminimumReleaseAgebeállítás kiszűri a publikálás után órákon belül visszavont kompromittált verziókat.
Dependency confusion, typosquatting, slopsquatting
| Támadás | Mechanizmus | Védelem |
|---|---|---|
| Dependency confusion | Belső csomagnév a nyilvános registryben magasabb verzióval | Scoped csomagok (@ceg/), registry hozzárendelés scope-onként .npmrc-ben, a scope lefoglalása a nyilvános registryben |
| Typosquatting | Elgépelt név (expres, lodahs) | Telepítés előtti név ellenőrzés, allowlist, SCA reputáció jelzés (Socket) |
| Slopsquatting | Az LLM által kitalált, nem létező csomagnév, amit a támadó előre regisztrál | Minden AI által javasolt csomagot ellenőrzünk a registryben (kor, letöltésszám, karbantartó, repó), mielőtt telepítjük |
| Account takeover | Karbantartó fiókjának feltörése phishinggel | Phishing álló MFA, trusted publishing, granulált és lejáró tokenek |
| Protestware, sabotage | Karbantartó szándékosan árt | Verzió rögzítés, frissítés késleltetés, diff review kritikus csomagoknál |
A slopsquatting kifejezést Seth Larson (Python Software Foundation) használta először. Kutatások szerint a kódgeneráló modellek javaslatainak jelentős része nem létező csomagra mutat, és ezek a nevek ismétlődnek, tehát előre regisztrálhatók. AI asszisztált fejlesztésben ebből közvetlen csapatszabály következik, a kézikönyv végén részletezve.
2025 szeptemberében egy célzott phishing kampány népszerű npm csomagok (köztük a chalk és a debug) karbantartójának fiókját vette át, és pár órára kártékony verziók jelentek meg. Ugyanebben a hónapban a Shai-Hulud féreg ellopott npm tokenekkel önmagát publikálta újabb csomagokba. Mindkét esetben a gyorsan frissítő, install scripteket futtató projektek sérültek leginkább.
Az xz utils backdoor (2024) tanulsága
2024 márciusában Andres Freund, a Microsoft mérnöke egy szokatlan, fél másodperces SSH bejelentkezési késleltetés miatt kezdett nyomozni, és felfedezte, hogy az xz tömörítő könyvtár két kiadásába hátsó ajtót rejtettek (CVE-2024-3094). Egy Jia Tan nevű közreműködő két éven át építette a bizalmat, a túlterhelt egyedüli karbantartóra kívülről nyomást gyakoroltak, végül társkarbantartói jogot kapott. A kártékony kód a git repóban nem volt olvasható formában. A kiadási tarballban lévő build script és bináris tesztfájlok illesztették be fordításkor, és bizonyos disztribúciókban az sshd-n keresztül hatott.
Tanulságok mérnöki szabályként.
- A kiadási artefaktum nem azonos a forrással. Lehetőleg a git tagből építünk, és a tarball és a repó közötti eltérést automatikusan ellenőrizzük.
- Reprodukálható build. Ha két független build bitre azonos eredményt ad, a rejtett beavatkozás feltűnik.
- A teljesítmény anomália biztonsági jelzés. Freund egy benchmark közben vette észre. Ugyanaz a figyelem, mint Stoll 75 centjénél.
- A karbantartói egészség biztonsági tényező. Az egyszemélyes, kiégett projekt a legkönnyebb célpont. A kritikus függőségeinket ezért támogatjuk (OpenSSF, pénz, review munka), és figyeljük a karbantartó változását.
- Bináris tesztadat a repóban gyanús terület. Review nélkül nem kerülhet be.
- Gyors visszaállíthatóság. A disztribúciók órák alatt visszaléptek egy korábbi verzióra. Ehhez verziórögzítés és ismert jó állapot kell.
GitHub Actions biztonság
# SEBEZHETŐ: tagre hivatkozó action, széles jogosultság, pull_request_target kódkivétellel.
on: pull_request_target
permissions: write-all
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { ref: ${{ github.event.pull_request.head.sha }} } # idegen kód titkokkal
- uses: some-org/changed-files@v45
- run: npm install && npm test
env: { NPM_TOKEN: ${{ secrets.NPM_TOKEN }} }
# JAVÍTOTT: pull_request trigger, minimális jogosultság, SHA pinning, titkok nélkül.
on: pull_request
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with: { persist-credentials: false }
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with: { node-version: 22, cache: npm }
- run: npm ci --ignore-scripts
- run: npm test
A fenti SHA értékek mintaként szerepelnek, élesben a Dependabot vagy a pinact eszköz frissíti őket.
Szabályok.
- SHA pinning. A tag áthelyezhető. 2025 márciusában a
tj-actions/changed-filesaction összes tagjét egy kompromittált verzióra irányították át, és több ezer repó CI naplójába kerültek titkok (CVE-2025-30066). A teljes commit SHA-ra rögzített hivatkozás ez ellen véd. pull_request_target. A célrepó jogosultságaival és titkaival fut, ezért idegen forkból jövő kódot soha nem veszünk ki és futtatunk benne. Ha címkézésre vagy kommentre kell, kódkivétel nélkül használjuk.permissions. Workflow szintencontents: read, job szinten csak a szükséges bővítés. A repó alapértelmezett token jogosultságát read only-ra állítjuk.- Script injekció. A
${{ github.event.issue.title }}jellegű, támadó által írt mezők ne kerüljenek közvetlenül arunblokkba. Környezeti változón keresztül adjuk át. - OIDC hosszú életű felhő kulcs helyett.
id-token: writeés szerepkör feltételezés AWS, GCP, Azure felé, és npm trusted publishing. - Self hosted runner nyilvános repóban nem fut.
- Ellenőrzés.
zizmorvagyactionlinta workflow fájlokra, OpenSSF Scorecard a repóra.
7. Mélységi védelem, zero trust, közös felelősség
Mélységi védelem (defense in depth)
Egyetlen kontroll sem tökéletes, ezért egymástól független rétegeket építünk, hogy egy réteg hibája ne vezessen azonnal kárhoz. A rétegek akkor érnek valamit, ha tényleg függetlenek. Ha mindegyik ugyanarra a feltevésre épül (a JWT érvényes), egyetlen hiba mindet átüti.
| Réteg | Példa a SaaS-ben |
|---|---|
| Perem | Vercel vagy Cloudflare WAF, DDoS védelem, bot szűrés |
| Kliens | CSP, Trusted Types, SameSite cookie |
| Alkalmazás | Validáció, server action authz, rate limit |
| Adat | RLS, oszlopszintű grant, titkosítás, backup |
| Identitás | MFA, rövid életű token, legkisebb jogosultság |
| Detekció | Audit napló, riasztás, anomália figyelés |
| Helyreállítás | Point in time recovery, kulcsrotáció runbook |
Zero trust (NIST SP 800-207) és BeyondCorp
A NIST SP 800-207 (2020) szerint a hálózati helyzet önmagában nem ad bizalmat. Minden hozzáférési kérést a kérő identitása, eszközállapota és a kontextus alapján, erőforrásonként és munkamenetenként bírálunk el. Az architektúra központi elemei a policy decision point (PDP), amely dönt, és a policy enforcement point (PEP), amely végrehajt.
A Google BeyondCorp (2014 óta publikált cikksorozat) ennek ipari megvalósítása. A belső alkalmazások nem VPN mögött vannak, hanem egy identity aware proxy mögött, amely a felhasználó és az eszköz állapota alapján enged be.
Kis csapatra fordítva.
- Az admin felületek és belső eszközök SSO mögött (Google Workspace, Microsoft Entra), MFA-val, IP alapú engedélyezés helyett.
- Szolgáltatások között is hitelesítés (aláírt JWT, mTLS), a belső hálózati elérés nem elég.
- Supabase alatt a service role kulcs a belső gyűrű. Csak szerveren él, és ahol lehet, helyette szűk jogú Postgres szerepkört vagy security definer függvényt használunk, explicit
search_pathbeállítással. - Eszközállapot. Céges gépeken lemeztitkosítás, automatikus frissítés, képernyőzár.
Felhő közös felelősségi modell
| Réteg | IaaS (AWS EC2) | PaaS (Vercel, Supabase) | SaaS (Stripe) |
|---|---|---|---|
| Fizikai, hálózat, hipervizor | Szolgáltató | Szolgáltató | Szolgáltató |
| Operációs rendszer, patch | Ügyfél | Szolgáltató | Szolgáltató |
| Runtime, adatbázis motor | Ügyfél | Szolgáltató | Szolgáltató |
| Alkalmazás kód | Ügyfél | Ügyfél | Szolgáltató |
| Konfiguráció (RLS, bucket policy, CORS) | Ügyfél | Ügyfél | Ügyfél (webhook, kulcsok) |
| Identitás, kulcsok, hozzáférés | Ügyfél | Ügyfél | Ügyfél |
| Adat besorolás, backup stratégia | Ügyfél | Ügyfél (PITR bekapcsolása) | Ügyfél |
A leggyakoribb felhős incidens a jól működő szolgáltatás rosszul beállított ügyféloldali része. Kikapcsolt RLS, publikus bucket, kiszivárgott kulcs. A Supabase dokumentációja ezt kifejezetten az ügyfél felelősségeként írja le.
8. Támadói modellek a védekezéshez
Lockheed Martin Cyber Kill Chain (2011)
Hutchins, Cloppert és Amin 2011-es cikke a katonai célzási láncot vitte át a behatolásokra. A hét fázis a felderítés, a fegyverkezés, a kézbesítés, a kihasználás, a telepítés, a vezérlő csatorna (command and control) és a cél végrehajtása. A gondolat lényege, hogy a védőnek elég egy láncszemet eltörni, ezért minden fázisra érdemes legalább egy észlelő vagy blokkoló kontrollt tervezni.
| Fázis | Webes SaaS megfelelő | Észlelés vagy blokkolás |
|---|---|---|
| Felderítés | Végpont felsorolás, subdomain keresés | Szokatlan 404 arány riasztás, API leltár |
| Fegyverkezés | Kihasználó kérés készítése | Nem látjuk, ezért itt a patch a válasz |
| Kézbesítés | Phishing a fejlesztőnek, rosszindulatú csomag | Phishing álló MFA, SCA |
| Kihasználás | Injekció, authz hiba | WAF, validáció, RLS |
| Telepítés | Webshell, új admin felhasználó, perzisztens token | Audit napló új adminra, fájlintegritás |
| Command and control | Kimenő kapcsolat ismeretlen hosztra | Egress szűrés, DNS napló |
| Cél | Adatexport, titkosítás | Export mennyiség riasztás, backup |
MITRE ATT&CK
Az ATT&CK (attack.mitre.org) valós incidensekből összegyűjtött tudásbázis a támadói taktikákról (miért) és technikákról (hogyan). Az Enterprise mátrix 14 taktikája a felderítés (Reconnaissance), az erőforrás fejlesztés, a kezdeti hozzáférés, a végrehajtás, a perzisztencia, a jogosultság emelés, a védelem kijátszás, a hitelesítő adat szerzés, a környezet feltérképezés (Discovery), a laterális mozgás, a gyűjtés, a vezérlő csatorna, a kiszivárogtatás és a hatás (Impact). Minden technikának azonosítója van (például T1078 Valid Accounts, T1190 Exploit Public-Facing Application, T1552 Unsecured Credentials).
Használat detekciós szabályokhoz lépésről lépésre.
- Kiválasztunk 5 és 10 közötti technikát, amelyek a mi rendszerünkre a legvalószínűbbek. Egy SaaS-nél jellemzően T1078 (érvényes fiók visszaélés), T1190, T1552 (kódban vagy CI-ban hagyott titok), T1098 (fiók manipuláció, például új admin), T1530 (adat felhő tárolóból), T1567 (kiszivárogtatás webszolgáltatásra).
- Minden technikához leírjuk, milyen naplóforrás látná (auth napló, audit tábla, Storage napló, GitHub audit log).
- Ha nincs ilyen forrás, az a következő naplózási feladat.
- Detekciós szabályt írunk, lehetőleg Sigma formátumban, ami több SIEM-re fordítható.
- A szabályt szándékos, ártalmatlan kiváltással teszteljük (Atomic Red Team jellegű teszt), és mérjük, megjelenik-e a riasztás.
- Lefedettségi táblát vezetünk (ATT&CK Navigator), amelyen látszanak a vakfoltok.
# Sigma jellegű szabály: új admin szerepkör kiosztása munkaidőn kívül (T1098).
title: Admin szerepkor kiosztas munkaidon kivul
logsource: { product: app, service: audit }
detection:
selection: { action: 'membership.role_change', new_role: 'owner' }
timeframe_filter: { hour|lt: 7 }
condition: selection and timeframe_filter
level: high
tags: [attack.persistence, attack.t1098]
A MITRE D3FEND a védekező technikák párja, és az ATT&CK technikákhoz rendel ellenintézkedéseket.
9. Naplózás és detekció
Mit naplózzunk (OWASP Logging Cheat Sheet alapján)
| Esemény | Mezők |
|---|---|
| Bejelentkezés siker és hiba, MFA esemény | Felhasználó, IP, user agent, eredmény, módszer |
| Jelszó, email, MFA változás, fiók helyreállítás | Ki, kié, honnan |
| Jogosultság változás (szerepkör, tagság, API kulcs) | Végrehajtó, célpont, régi és új érték |
| Authz elutasítás (403, RLS által üres eredmény gyanús mintában) | Felhasználó, erőforrás, művelet |
| Validációs hiba a bizalmi határon | Végpont, hibatípus, minta nélkül |
| Érzékeny adat elérés, export, tömeges letöltés | Ki, mennyit, milyen szűrővel |
| Admin és támogatói műveletek, impersonation | Ki, kinek a nevében, indoklás |
| Konfiguráció és kulcs változás | Ki, mit, mikor |
| Fizetési események, webhook ellenőrzés hibája | Esemény ID, eredmény |
| Rate limit és kvóta túllépés | Kulcs, végpont |
Amit soha nem naplózunk. Jelszó, session token, API kulcs, teljes kártyaszám, egészségügyi vagy egyéb különleges adat, teljes kérés törzs érzékeny végponton. A PII-t (email, IP) minimalizáljuk, és megőrzési időt rendelünk hozzá a GDPR szerint.
Formátum. Strukturált JSON (pino Node alatt), egységes mezőnevek (az OWASP Logging Vocabulary eseménynevei jó kiindulás, például authn_login_fail, authz_fail, user_updated), UTC időbélyeg, korrelációs azonosító, ami a kéréstől a háttér munkáig követhető. A naplóinjekció ellen a felhasználói értékeket mezőként, nem összefűzött szövegként írjuk.
// SEBEZHETŐ: szöveg összefűzés (sortörés injekció) és token a naplóban.
console.log(`login failed for ${email} token=${req.headers.get('authorization')}`);
// JAVÍTOTT: strukturált, minimalizált, redaktált.
const logger = pino({ redact: ['req.headers.authorization', 'req.headers.cookie', '*.password'] });
logger.warn({ event: 'authn_login_fail', user: hashEmail(email), ip, ua, reqId }, 'login failed');
Audit napló
Az audit napló a letagadhatatlanság eszköze (a STRIDE R betűje), ezért más szabályok vonatkoznak rá, mint az alkalmazás naplóra.
create table audit_log (
id bigint generated always as identity primary key,
at timestamptz not null default now(),
actor uuid, tenant_id uuid, action text not null,
target text, ip inet, meta jsonb not null default '{}'
);
alter table audit_log enable row level security;
-- Az alkalmazás csak beszúrhat, módosítani és törölni senki nem tud.
revoke update, delete, truncate on audit_log from authenticated, anon, service_role;
create policy "tenant admin olvashatja" on audit_log for select
using (tenant_id in (select tenant_id from memberships where user_id = (select auth.uid()) and role = 'owner'));
Az írást security definer függvényen vagy szerveroldali kódon keresztül végezzük, és a napló másolatát rendszeresen egy külön fiókba vagy WORM tárolóba exportáljuk, hogy egy adatbázis szintű kompromittálás se törölhesse.
Riasztás
A riasztás három szabálya.
- Minden riasztás akcióra vezet. Ha egy riasztásra a válasz rendszeresen az, hogy nem kell semmit tenni, a szabályt hangoljuk vagy töröljük.
- Tünetre riasztunk, nem minden okra. Sok sikertelen login egy fiókra, új admin, tömeges export, kiugró költség, ismeretlen országból admin login.
- Van gazdája. Kis csapatban egy ügyeleti rotáció vagy legalább egy megnevezett felelős, és egy csatorna, ahová a riasztás befut (például dedikált Slack csatorna plus telefonos értesítés a kritikusakra).
Kezdő riasztáskészlet egy SaaS-hez.
| Riasztás | Küszöb (kiindulás) |
|---|---|
| Sikertelen login egy fiókra | 10 darab 10 perc alatt |
| Új owner vagy admin szerepkör | Minden esetben |
| Service role kulcs használata ismeretlen IP-ről | Minden esetben, ha a szolgáltató naplózza |
| Export vagy letöltés mennyiség | 5-szöröse a felhasználó 30 napos átlagának |
| LLM vagy felhő költség | Napi plafon 80 százaléka |
| Webhook aláírás hiba | 5 darab 10 perc alatt |
| Secret scanning találat (GitHub push protection) | Minden esetben |
| RLS nélküli tábla éles sémában | Minden esetben |
10. Incidenskezelés
NIST SP 800-61 3. revízió (2025 április)
A 2025 áprilisában véglegesített 3. revízió lecserélte a 2012-es Computer Security Incident Handling Guide-ot, és az incidenskezelést a CSF 2.0 profiljaként írja le. A korábbi négyfázisú életciklus (felkészülés, észlelés és elemzés, elszigetelés, felszámolás és helyreállítás, utólagos tevékenység) helyett a CSF 2.0 hat funkciója szervezi a tevékenységeket. A Govern, Identify és Protect a felkészülést fedi, a Detect, Respond és Recover a kezelést, és az egész egy folyamatos fejlesztési hurok, ahol a tanulságok minden funkcióba visszacsatolódnak. A részletes, gyorsan változó technikai útmutatás kikerült a dokumentumból, és a NIST online forrásaiban él tovább.
| CSF 2.0 funkció | Incidenskezelési tartalom kis csapatban |
|---|---|
| Govern | Ki dönt, ki kommunikál, ki értesíti a hatóságot, kapcsolattartó lista, jogi és biztosítói kapcsolat |
| Identify | Eszközleltár, adatleltár (hol van személyes adat), kockázatok, tanulságok beépítése |
| Protect | MFA, legkisebb jogosultság, backup, a runbookok gyakorlása |
| Detect | Naplók, riasztások, külső bejelentés csatorna (security.txt) |
| Respond | Triázs, elszigetelés, felszámolás, kommunikáció, bizonyíték megőrzés |
| Recover | Visszaállítás, ellenőrzés, ügyfél tájékoztatás, utólagos elemzés |
Általános incidens folyamat kis csapatra
- Észlelés és bejelentés. Bárki bejelentheti egy közös csatornán. A bejelentőt soha nem hibáztatjuk.
- Incidens vezető kijelölése. Egy ember dönt és koordinál, egy másik dokumentál. A vezető nem feltétlenül a legtapasztaltabb, hanem aki éppen tud fókuszálni.
- Idővonal napló nyitása. Minden lépés UTC időbélyeggel egy közös dokumentumba.
- Súlyosság besorolás. Érint-e személyes adatot, ügyféladatot, fizetést, rendelkezésre állást.
- Elszigetelés. A kár terjedésének megállítása (kulcs visszavonás, fiók zárolás, funkció lekapcsolás feature flaggel).
- Bizonyíték megőrzés. Naplók exportja a törlés vagy rotáció előtt.
- Felszámolás és helyreállítás. A gyökérok javítása, tiszta állapotból visszaállítás.
- Kommunikáció. Belső, ügyfél, hatóság, a szükséges határidőkön belül.
- Utólagos elemzés (blameless postmortem). 5 munkanapon belül, akciópontokkal és felelősökkel.
Runbook, kiszivárgott kulcs vagy titok
Kiváltó. GitHub secret scanning riasztás, gitleaks találat, a kulcs megjelent egy naplóban, képernyőképen vagy nyilvános repóban.
- Visszavonás azonnal, vizsgálat utána. A kulcsot rotáljuk a szolgáltatónál (Stripe dashboard, Supabase API keys, felhő IAM). Supabase alatt az új típusú secret kulcsok egyenként visszavonhatók. A régi JWT alapú service role kulcsnál a JWT secret rotációja minden munkamenetet érvénytelenít, ezt tudatosan vállaljuk.
- Az új kulcs telepítése a secret managerbe és a deploy környezetbe, újratelepítés.
- A régi kulcs használatának vizsgálata a szolgáltató naplóiban a kiszivárgás időpontjától (Stripe request log, Supabase API és Postgres napló, CloudTrail).
- Eltávolítás a git történetből (
git filter-repo) csak a visszavonás után, mert a fork és a cache már őrizheti. A visszavonás a védelem, a törlés csak higiénia. - Kár felmérése. Ha a kulccsal adathoz fértek hozzá, az adatszivárgás runbook indul.
- Gyökérok. Miért kerülhetett ki (hiányzó
.gitignore,NEXT_PUBLIC_előtag, debug napló), és mi akadályozza meg legközelebb (push protection, pre-commit gitleaks).
Runbook, feltört felhasználói vagy admin fiók
- Munkamenetek visszavonása. Supabase alatt az admin API-val a felhasználó kijelentkeztetése, refresh tokenek érvénytelenítése, szükség esetén a fiók tiltása (
ban_duration). - Jelszó és MFA visszaállítás egy ellenőrzött csatornán, a támadó által hozzáadott MFA eszközök és API kulcsok törlése.
- Perzisztencia keresése. Új tagok, meghívók, szerepkör változások, webhook célok, OAuth alkalmazások, email továbbítás az audit naplóban a kompromittálás kezdete óta.
- Hatókör. Milyen adatot látott vagy exportált a fiók az adott időszakban.
- Admin fióknál a teljes kulcsrotáció és a CI titkok ellenőrzése is.
- Ügyfél tájékoztatás és szükség esetén az adatszivárgás runbook.
Runbook, adatszivárgás és a 72 órás GDPR bejelentés
Az adatvédelmi oldal részletei az Adatbiztonság és adatvédelem kézikönyvben szerepelnek, itt az incidenskezelési menetrend a fókusz. A GDPR 33. cikke szerint az adatkezelő a személyes adatokat érintő adatvédelmi incidenst indokolatlan késedelem nélkül, lehetőleg a tudomásszerzéstől számított 72 órán belül bejelenti a felügyeleti hatóságnak (Magyarországon a NAIH). Kivétel, ha az incidens valószínűleg nem jár kockázattal az érintettek jogaira. A 34. cikk szerint magas kockázat esetén az érintetteket is értesíteni kell. Adatfeldolgozóként (például B2B SaaS az ügyfél adataival) az adatkezelőt kell késedelem nélkül értesíteni, és a szerződés általában rövidebb határidőt ír elő.
| Idő a tudomásszerzéstől | Teendő |
|---|---|
| 0 és 4 óra között | Elszigetelés, incidens vezető, idővonal, bizonyíték megőrzés, jogi kapcsolattartó bevonása |
| 4 és 24 óra között | Hatókör becslés (milyen adat, hány érintett, mely ügyfelek), adatfeldolgozóként az adatkezelő ügyfelek értesítése |
| 24 és 48 óra között | Kockázatértékelés az érintettekre, bejelentés vázlat (az incidens jellege, érintettek és rekordok köre, valószínű következmények, intézkedések, kapcsolattartó) |
| 72 órán belül | Bejelentés a NAIH felé. Ha nem minden információ ismert, részletekben is beadható, a késés okát indokolni kell |
| Utána | Érintettek értesítése magas kockázatnál, belső incidens nyilvántartás vezetése akkor is, ha nem kellett bejelenteni |
A 72 óra a tudomásszerzéstől, nem a vizsgálat lezárásától számít. Ezért a runbookban előre kitöltött bejelentés sablon, a hatóság elérhetősége és a döntéshozó neve szerepel. Ha a szervezet a NIS2 hatálya alá tartozik, ott 24 órás korai figyelmeztetés és 72 órás bejelentés az irányadó a nemzeti szabályozás szerint.
11. Google, Building Secure and Reliable Systems (2020)
A könyv fő állítása, hogy a biztonság és a megbízhatóság ugyanannak a rendszertulajdonságnak két arca. Mindkettő a nehezen előre látható hibák és a rossz szándékú vagy hibázó emberek elleni tervezés. Az alábbi táblázat a legfontosabb módszereket kis csapatra fordítja.
| Módszer | Lényeg | Alkalmazás kis projektben |
|---|---|---|
| Least privilege | Minden ember és szolgáltatás csak a feladatához szükséges jogot kapja, időben korlátozva | Éles DB-hez nincs állandó emberi írási jog, helyette migráció és ideiglenes jog |
| Zero touch prod | Éles rendszerhez ember nem nyúl közvetlenül, csak automatizált, review-zott eszközön keresztül | Minden éles változás PR és CI útján, a dashboardos kézi átírás kivétel |
| Multi party authorization (MPA) | Érzékeny művelethez második ember jóváhagyása kell | Branch protection kötelező review-val, éles adatbázis törléshez két ember |
| Breakglass | Vészhelyzeti hozzáférés, ami mindig naplózott és riaszt | Lezárt admin fiók, használata azonnali riasztással és utólagos review-val |
| Design for understandability | Az érthető rendszer biztonságosabb, mert a hibát észre lehet venni | Egy helyen élő authz, kevés speciális eset, jól elnevezett invariánsok |
| Design for recovery | Feltételezzük, hogy baj lesz, és a helyreállítás útja előre megvan | PITR bekapcsolva, kipróbált visszaállítás, kulcsrotáció runbook, verziózott konfig |
| Blast radius csökkentés | Egy hiba vagy kompromittálás kis területet érintsen | Tenantonkénti izoláció, környezetenként külön kulcs és projekt, szűk scope-ú tokenek, feature flag lekapcsoláshoz |
| Graceful degradation, DoS tűrés | Túlterheléskor a lényeg működjön | Rate limit, sorba állítás, nem kritikus funkciók lekapcsolhatósága |
| Biztonságos alapértelmezésű API | A könnyű út legyen a biztonságos út | createServerClient a kódbázis alapja, az admin kliens nehezen elérhető, külön modulban |
Tipikus hiba. A backup létezik, de soha senki nem próbálta visszaállítani. A design for recovery a visszaállítás gyakorlásával kezdődik, legalább negyedévente egy staging környezetbe.
12. Biztonsági tesztelés
| Módszer | Mit talál | Mikor fut | Eszköz kis projektben |
|---|---|---|---|
| SAST | Veszélyes kódminták a forrásban | Minden PR | Semgrep (p/typescript, p/nextjs, p/secrets csomagok), CodeQL nyilvános repón |
| SCA | Ismert sérülékenység a függőségekben | Minden PR és naponta | npm audit --omit=dev, osv-scanner, Dependabot vagy Renovate, Socket a csomag reputációra |
| Secret scanning | Kódba vagy történetbe került titok | Pre-commit és PR | gitleaks, GitHub push protection |
| IaC és konfiguráció | Rossz felhő és konténer beállítás | PR | trivy config, checkov, Supabase Security Advisor |
| CI workflow scan | Veszélyes GitHub Actions minták | PR | zizmor, actionlint |
| DAST | Futó alkalmazás sérülékenységei kívülről | Staging deploy után | OWASP ZAP baseline vagy full scan, nuclei sablonok |
| Fuzzing | Parser és határeset hibák | Kritikus parsereken folyamatosan | fast-check property based teszt, Jazzer.js |
| Authz teszt | BOLA, BFLA, tenant szivárgás | Minden PR | Saját integrációs teszt két tenanttal |
| Pentest | Láncolt, üzleti logikai hibák | Évente és nagy változás után | Külső cég, ASVS alapú hatókörrel |
| Bug bounty | Folyamatos külső szemek | Érett termék, kapacitás a válaszra | Előbb VDP (bejelentési csatorna), utána fizetős program |
Minimális CI biztonsági pipeline
name: security
on: [pull_request]
permissions: { contents: read }
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<sha> # v4
with: { fetch-depth: 0, persist-credentials: false }
- name: Secret scan
uses: gitleaks/gitleaks-action@<sha> # v2
- name: SAST
run: pipx run semgrep scan --config p/typescript --config p/nextjs --config p/secrets --error
- name: SCA
run: |
npm ci --ignore-scripts
npm audit --omit=dev --audit-level=high
go run github.com/google/osv-scanner/v2/cmd/osv-scanner@latest scan source -r .
- name: Workflow scan
run: pipx run zizmor .github/workflows
# Staging DAST, deploy után
dast:
runs-on: ubuntu-latest
steps:
- uses: zaproxy/action-baseline@<sha> # v0.14
with: { target: 'https://staging.pelda.hu', fail_action: true }
Tipikus hibák.
- Zajos SAST, amit mindenki figyelmen kívül hagy. Kevés, magas megbízhatóságú szabállyal kezdünk, és csak a blokkoló hibák törik a buildet.
npm auditdev függőségekre. A fejlesztői eszközök hibái zajt adnak, az--omit=devszűr.- DAST éles rendszeren. Adatot írhat, terhelést okoz. Stagingen futtatjuk, élesen csak passzív baseline.
- Pentest ASVS hatókör nélkül. A jelentés nem hasonlítható össze évről évre.
- Bug bounty túl korán. Ha nincs kapacitás a bejelentések kezelésére, a program árt. Egy
security.txtés egy dedikált email cím előbb kell.
13. NIST CSF 2.0 és CIS Controls v8.1 IG1 kis szervezetre
NIST Cybersecurity Framework 2.0 (2024 február)
A CSF 2.0 hat funkciója kis szervezetre fordítva, a NIST kisvállalati gyorsútmutatóinak szellemében.
| Funkció | Kérdés | Kis szervezetben konkrétan |
|---|---|---|
| Govern (új 2.0-ban) | Ki felel, mi a kockázati étvágy, milyen szabályok kötnek? | Egy megnevezett biztonsági felelős, egyoldalas biztonsági politika, beszállítói lista (Supabase, Vercel, Stripe, LLM), GDPR szerepek |
| Identify | Mink van és mi a fontos? | Eszköz, fiók, SaaS és adatleltár, kockázatlista a fenyegetésmodellből |
| Protect | Hogyan védjük? | MFA mindenhol, jelszókezelő, frissítések, legkisebb jogosultság, titkosítás, backup, képzés |
| Detect | Hogyan vesszük észre? | Riasztások, naplók, secret scanning, külső bejelentés csatorna |
| Respond | Mit teszünk, ha baj van? | Runbookok, kapcsolattartó lista, kommunikációs sablonok |
| Recover | Hogyan állunk talpra? | Kipróbált visszaállítás, ügyfél kommunikáció, tanulságok |
A CSF 2.0 profilokkal (jelenlegi és cél állapot) és szintekkel (Tier 1 és 4 között) dolgozik. Kis szervezetnek elég egy táblázat a hat funkcióval, a jelenlegi és a cél állapottal, és a következő negyedév három legfontosabb lépésével.
CIS Controls v8.1 (2024) és az IG1
A CIS Controls 18 kontrollcsaládból álló, priorizált védelmi lista. Az implementációs csoportok (IG1, IG2, IG3) a szervezet méretéhez és kockázatához igazodnak. Az IG1 az alapvető kiberhigiénia, a v8.1-ben 56 safeguard, amit minden szervezetnek érdemes teljesítenie. A v8.1 a CSF 2.0-hoz igazodva Govern jellegű safeguardokat is kiemel.
Az IG1 lényege fejlesztő cégre fordítva.
| CIS kontroll | IG1 lényeg | Gyakorlatban |
|---|---|---|
| 1 Eszközleltár | Minden gép ismert | Lista a céges laptopokról |
| 2 Szoftverleltár | Engedélyezett szoftverek | SaaS lista, SBOM a termékről |
| 3 Adatvédelem | Adatleltár, kezelés, törlés | Hol van személyes adat, megőrzési idő |
| 4 Biztonságos konfiguráció | Alapbeállítások, képernyőzár, tűzfal | MDM vagy ellenőrzőlista, lemeztitkosítás |
| 5 Fiókkezelés | Fiókleltár, egyedi jelszavak, inaktív fiókok tiltása | Kilépéskor azonnali fiókzárás minden SaaS-ben |
| 6 Hozzáférés kezelés | MFA, hozzáférés adása és elvétele folyamattal | MFA kötelező GitHub, Supabase, Vercel, Stripe, Google fiókon |
| 7 Sérülékenység kezelés | Patch folyamat | Automatikus OS frissítés, Dependabot |
| 8 Napló kezelés | Naplózás bekapcsolva és megőrizve | Audit log a SaaS eszközökben bekapcsolva |
| 9 Email és böngésző védelem | Támogatott böngésző, DNS szűrés | SPF, DKIM, DMARC a domainre |
| 10 Kártevő védelem | Védelem minden gépen | Beépített védelem bekapcsolva, frissítve |
| 11 Adat helyreállítás | Automatikus, védett backup, teszt | PITR, offsite másolat, negyedéves visszaállítás teszt |
| 14 Biztonsági tudatosság | Képzés | Phishing és titokkezelési képzés évente |
| 15 Szolgáltató kezelés | Beszállítói leltár | DPA a beszállítókkal, SOC 2 jelentések begyűjtése |
| 17 Incidens válasz | Felelős, kapcsolattartók, bejelentési folyamat | A fenti runbookok |
A kimaradó kontrollok (12 hálózati infrastruktúra, 13 hálózati monitorozás, 16 alkalmazásbiztonság, 18 pentest) az IG2 és IG3 szinten hangsúlyosabbak, de egy szoftvercégnél a 16-os (alkalmazásbiztonság) az IG1 mellett is a fő terep, és ezt a kézikönyv többi része fedi.
A gyakorlatban
Az alábbi szabályok minden fejlesztési munkamenetre érvényesek, külön kérés nélkül, akár ember írja a kódot, akár egy kódgeneráló modell. Céljuk, hogy a kód első változata is a biztonságos alapértelmezést kövesse, és a kockázatos döntés láthatóvá váljon.
5 perces fenyegetésmodell minden új funkciónál
Kódírás előtt a fejlesztő röviden, a ticketben vagy a PR leírásban megválaszol négy kérdést. AI asszisztált fejlesztésnél ugyanezt az asszisztens válaszától is elvárjuk, mielőtt kódot generál.
- Min dolgozunk. Egy mondat a funkcióról és a bizalmi határokról, amelyeket keresztez (böngésző és szerver, felhasználó és tenant, saját rendszer és harmadik fél, kód és LLM).
- Mi romolhat el. STRIDE gyorskör a határt keresztező adatfolyamokra. Legalább az S, I és E betű sorra kerül, a kiszámíthatóság és a parsing kérdésével együtt.
- Mit teszünk ellene. Fenyegetésenként egy konkrét kontroll, ami bekerül a kódba vagy a teendők listájába.
- Mit nem csinálunk meg most. Az elfogadott vagy elhalasztott kockázatok kimondva, hogy a felelős (tech lead, termékgazda) tudatosan dönthessen róluk.
Ha a funkció auth, fizetés, fájl, URL lekérés, külső webhook, admin jogosultság vagy LLM eszközhívás területét érinti, a modell mélyebb, 15 perces változata készül el, és erről a csapat vezetője is tud.
Tiltott minták a kódban
| Minta | Helyette |
|---|---|
String összefűzés SQL-ben, sql.unsafe, execute format('%s') | Paraméterezés, %L és %I, using |
dangerouslySetInnerHTML sanitizálás nélkül, rehype-raw | DOMPurify, alapértelmezett markdown renderelés |
Math.random() tokenhez, azonosítóhoz | crypto.randomUUID(), randomBytes() |
Service role vagy secret kulcs kliens oldali kódban, NEXT_PUBLIC_ előtaggal | server-only modul, környezeti változó csak szerveren |
| Új tábla RLS nélkül | enable row level security és policy ugyanabban a migrációban |
| Authz csak middleware-ben | Ellenőrzés az adatelérés mellett |
catch { return true } vagy elnyelt hiba jogosultsági döntésnél | Fail closed, naplózott hiba |
CORS origin visszatükrözés, * credentials mellett | Explicit allowlist |
fetch(userUrl) ellenőrzés nélkül | SSRF védett lekérő |
redirect(searchParams.next) | Relatív útvonal allowlist |
| Webhook aláírás ellenőrzés nélkül | Aláírás, nyers törzs, idempotencia |
| Kliens által küldött ár, szerepkör, tenant azonosító | Szerveroldali forrás |
exec shell stringgel | execFile argumentumtömbbel |
| Titok, token, jelszó a naplóban | Redakció |
GitHub Action taggel, pull_request_target kódkivétellel, write-all | SHA pin, pull_request, minimális permissions |
A lista akkor működik igazán, ha nem csak review közben él. Semgrep szabályként vagy linter konfigurációként a CI-ban, AI asszisztált fejlesztésnél pedig a projekt szintű utasítások között is szerepel, így a generált kód első változata sem tartalmazza ezeket a mintákat.
Függőség hozzáadás szabálya (slopsquatting ellen)
Új csomag bevezetése előtt a csapat ellenőrzi, hogy a csomag létezik a registryben, és megnézi a korát, a heti letöltésszámát, a karbantartót és a forrásrepót (npm view <csomag> time.created repository maintainers). Fiatal, kevés letöltésű vagy egy ismert csomag elgépelésére emlékeztető nevű csomag nem kerül telepítésre, helyette jelzés és emberi review következik. Egy AI asszisztens által javasolt vagy emlékezetből felidézett csomagnév önmagában nem számít ellenőrzöttnek. Ahol a standard könyvtár vagy egy már meglévő függőség megoldja a feladatot, nem hozunk be újat.
Biztonsági review checklist
Minden bizalmi határt érintő változtatás végén a szerző (ember vagy AI asszisztens) végigmegy ezen a listán, és a PR leírásban röviden jelzi az eredményt.
- Authn. Minden új végpont és server action ellenőrzi a felhasználót szerveroldalon (
auth.getUser()), nem a kliens állítására épít. - Authz. Az objektum elérés a felhasználó tenantjára szűkül. Van-e teszt, ami másik tenanttal próbálkozik.
- RLS. Új tábla, nézet, függvény esetén RLS policy,
security invokernézet, security definer függvénynél fixsearch_path. - Validáció. Minden bejövő adat zod sémán megy át
.strict()módban, méret és típuskorláttal. - Kimenet. HTML kontextusban nincs nyers beillesztés, URL-eknél séma allowlist.
- Titkok. Nincs hardkódolt kulcs, nincs
NEXT_PUBLIC_előtagú titok, a.env.examplefrissült értékek nélkül. - Hibakezelés. Fail closed, kifelé nem szivárog stack trace, minden külső hívásnak van timeoutja.
- Erőforráskorlát. Lapozás, méretkorlát, rate limit és kvóta a drága műveleteken.
- Integritás. Bejövő webhook aláírása ellenőrzött, idempotens feldolgozás.
- Naplózás. A biztonsági esemény naplózódik strukturáltan, érzékeny adat nélkül, audit napló a jogosultság és törlés műveleteknél.
- Függőségek. Új csomag ellenőrizve, lockfile frissült, install script nincs indokolatlanul engedélyezve.
- Headerek és CORS. Nem lazult a CSP, a CORS allowlist szűk maradt.
- LLM. Ha az LLM kimenete HTML-be, SQL-be, shellbe vagy eszközhívásba kerül, az AI ügynökök és vibecoding kézikönyv szabályai érvényesek.
Deploy előtti kapu
Élesítés előtt az alábbi kapuk futnak, automatikusan a CI-ban vagy kézi ellenőrzéssel. Ha bármelyik bukik, nincs deploy, és a bukás oka dokumentálva visszakerül a csapathoz.
| Kapu | Parancs vagy ellenőrzés | Bukás feltétele |
|---|---|---|
| Titkok | gitleaks detect --redact | Bármilyen találat |
| SAST | semgrep scan --config p/typescript --config p/nextjs --error | Magas súlyosságú találat |
| Függőségek | npm audit --omit=dev --audit-level=high, osv-scanner scan source -r . | Magas vagy kritikus, javítás elérhető |
| RLS | select tablename from pg_tables where schemaname='public' and not rowsecurity és Supabase advisor | Nem üres eredmény, hiba szintű advisor jelzés |
| Authz tesztek | A két tenantos integrációs tesztcsomag | Bármilyen bukás |
| Migráció | A migráció review-zva, visszaállítási út ismert | Destruktív lépés terv nélkül |
| Headerek | ZAP baseline vagy curl -I ellenőrzés stagingen | Hiányzó CSP, HSTS, nosniff |
| CI workflow | zizmor .github/workflows | Magas súlyosságú találat |
| Helyreállítás | PITR bekapcsolva, utolsó visszaállítási teszt dátuma ismert | Nincs backup vagy sosem tesztelték |
Csapatszabályok
- Biztonságos alapértelmezés. Két megoldás közül a biztonságosabb készül el, és ha az kényelmetlenebb, egy mondatos indoklás kíséri.
- Kockázatos kérés. Ha egy üzleti igény vagy fejlesztői ötlet a fenti tiltott minták egyikét kívánná (RLS kikapcsolása, service role kulcs a kliensben), a kockázat a biztonságos változattal együtt a döntéshozó elé kerül. Tudatosan vállalt kockázatos út esetén a döntést kommentben és a PR leírásban dokumentáljuk, felelőssel.
- Titkokkal való bánásmód. Valódi kulcs nem kerül kódba, chatbe, promptba vagy naplóba. Kiszivárgott titok észlelésekor a kiszivárgott kulcs runbook indul, első lépésként a visszavonással.
- Incidens gyanú. Ha munka közben incidensre utaló jel bukkan fel (ismeretlen admin, gyanús commit, nem várt kimenő kapcsolat), a munka megáll, a jelet bejelentjük, és az incidens folyamat első lépései indulnak. Csendes javítgatás nincs, és ez az AI asszisztenssel végzett munkára is vonatkozik.
- Frissesség. Szabványra (OWASP, ASVS, NIST, CIS) hivatkozás előtt, ha a projekt auditba vagy ügyfél elé kerül, ellenőrizzük az aktuális verziót, mert a listák rendszeresen változnak.
- Arányosság. Egy hétvégi prototípusnál az 5 perces modell és a tiltott minták listája elég. Személyes adatot, fizetést vagy több tenantot kezelő rendszernél az ASVS L2, a teljes checklist és a deploy kapu kötelező.
Állapot 2026 októberében. A szöveg szakmai összefoglaló, nem jogi tanácsadás, a szabványok és jogszabályok aktuális szövegét a kiadótól érdemes ellenőrizni.
Források
- Willis H. Ware (szerk.), Security Controls for Computer Systems, RAND, Defense Science Board jelentés, 1970.
- James P. Anderson, Computer Security Technology Planning Study, 1972.
- Paul A. Karger, Roger R. Schell, Multics Security Evaluation: Vulnerability Analysis, 1974.
- Jerome H. Saltzer, Michael D. Schroeder, The Protection of Information in Computer Systems, 1975.
- Ken Thompson, Reflections on Trusting Trust, Turing díjas előadás, 1984.
- Clifford Stoll, The Cuckoo's Egg, 1989.
- Aleph One, Smashing the Stack for Fun and Profit, Phrack, 1996.
- Bruce Schneier, Attack Trees, Dr. Dobb's Journal, 1999.
- Michael Howard, David LeBlanc, Writing Secure Code, 2. kiadás, Microsoft Press, 2003.
- Microsoft Security Development Lifecycle (SDL).
- Adam Shostack, Threat Modeling: Designing for Security, Wiley, 2014.
- Adam Shostack, Threats: What Every Engineer Should Learn from Star Wars, Wiley, 2023.
- Threat Modeling Manifesto, 2020 (threatmodelingmanifesto.org).
- Tony UcedaVélez, Marco M. Morana, Risk Centric Threat Modeling (PASTA), Wiley, 2015.
- David A. Wheeler, Countering Trusting Trust through Diverse Double-Compiling, 2005.
- Eric M. Hutchins, Michael J. Cloppert, Rohan M. Amin, Intelligence-Driven Computer Network Defense (Cyber Kill Chain), Lockheed Martin, 2011.
- Heather Adkins és társai, Building Secure and Reliable Systems, Google, O'Reilly, 2020.
- OWASP Top 10 2025 (owasp.org/Top10).
- OWASP Application Security Verification Standard 5.0, 2025.
- OWASP API Security Top 10, 2023.
- OWASP Cheat Sheet Series (cheatsheetseries.owasp.org), köztük a Logging és Logging Vocabulary lap.
- NIST SP 800-207, Zero Trust Architecture, 2020.
- NIST SP 800-63B, Digital Identity Guidelines, Authentication and Lifecycle Management.
- NIST SP 800-61 Rev. 3, Incident Response Recommendations and Considerations for Cybersecurity Risk Management, 2025.
- NIST Cybersecurity Framework 2.0, 2024.
- NIST FIPS 203, 204, 205 (poszt kvantum kriptográfia), 2024.
- CIS Critical Security Controls v8.1, 2024.
- SLSA, Supply chain Levels for Software Artifacts (slsa.dev).
- CycloneDX (OWASP) és SPDX (ISO/IEC 5962) SBOM formátumok.
- Sigstore projekt (sigstore.dev).
- MITRE ATT&CK (attack.mitre.org) és MITRE D3FEND.
- Google BeyondCorp cikksorozat, 2014 óta.
- CISA és partnerei, The Case for Memory Safe Roadmaps, 2023.
- Az Európai Parlament és a Tanács (EU) 2016/679 rendelete (GDPR), 33. és 34. cikk.
- Az Európai Parlament és a Tanács (EU) 2024/2847 rendelete (Cyber Resilience Act).
- Az Európai Parlament és a Tanács (EU) 2022/2555 irányelve (NIS2).
- CVE-2024-3094 (xz utils), CVE-2025-29927 (Next.js middleware), CVE-2025-30066 (tj-actions/changed-files), CVE-2025-55182 (React Server Components).