Web aplikacija je za većinu tvrtki najizloženiji dio sustava. Dostupna je s interneta svima, pa je i prva meta napadača. Za razliku od interne mreže koju štiti vatrozid, web aplikacija postoji upravo zato da bude javno dostupna. Svaki obrazac, polje za pretragu, API poziv i parametar u adresi potencijalni je ulaz. Zbog toga su ranjivosti web aplikacija godinama među najčešćim uzrocima curenja podataka, a napadač ne mora probiti mrežu ni ukrasti uređaj. Dovoljno mu je da nađe propust u samoj aplikaciji.
Ovaj tekst gleda na sigurnost web aplikacija iz obrambene perspektive. Ne objašnjava kako se aplikacija napada ni kako se testira, nego kako se gradi i održava tako da bude otporna. To je posao razvojnog tima, arhitekta i osobe odgovorne za sigurnost, a ne nešto što se kupuje na kraju projekta. Za reguliranu hrvatsku tvrtku iz financija, zdravstva, kritične infrastrukture ili SaaS-a sigurna aplikacija nije samo tehničko pitanje. Kroz nju teku osobni podaci i poslovna logika, pa je curenje izravna povreda po GDPR-u i propust u mjerama koje traže NIS2 i DORA. Sigurnost ugrađena u dizajn jeftinija je i učinkovitija od naknadnog krpanja, a redovito testiranje samo je provjera da je posao dobro odrađen.
Ovo je obrambeni dio našeg pregleda sigurnosti aplikacija. Napadačku stranu, kako se aplikacija testira iz perspektive napadača, pokriva penetracijsko testiranje web aplikacija. Izgradnju i jačanje aplikacija pružamo kroz sigurnost aplikacija i clouda.
Zašto je obrana drugačiji posao od provjere
Postoje dvije odvojene discipline. Prva je izgradnja sigurnosti: arhitekt i razvojni tim donose odluke o tome kako se provjeravaju ovlasti, kako se obrađuje unos i kako se čuvaju lozinke. Druga je provjera te sigurnosti: tester nastupa kao napadač i traži propuste u onome što je izgrađeno. Te dvije discipline se nadopunjuju, ali nisu zamjena jedna za drugu. Aplikacija koja nije sigurno građena neće postati sigurna jer je netko testira, a najbolji test samo potvrđuje stanje, ne mijenja ga.
Najčešća pogreška je tretirati sigurnost kao završnu provjeru pred lansiranje. Tada je kasno. Ako se kontrola pristupa ne nalazi u temeljnoj arhitekturi, ne dodaje se naknadno jednim ispravkom, nego traži preradu na desecima mjesta. Po našem iskustvu trošak ispravka raste što se kasnije propust otkrije, a stvarna procjena ovisi o opsegu. Zato obrana mora početi pri dizajnu, a tekst koji slijedi prolazi kroz glavne stupove te obrane.
Sigurnost kroz dizajn i modeliranje prijetnji
Sigurnost kroz dizajn znači da se o prijetnjama razmišlja prije nego se napiše prva linija koda. Alat za to je modeliranje prijetnji, na engleskom threat modeling. Tim sjedne nad nacrt aplikacije i postavi nekoliko pitanja. Koje podatke aplikacija čuva i tko ih smije vidjeti. Kuda ti podaci teku. Gdje su granice povjerenja, primjerice između preglednika i poslužitelja ili između aplikacije i baze. Što napadač dobiva ako probije svaku od tih granica.
Iz tih pitanja izlazi popis prijetnji i odluka kako se svaka adresira. Modeliranje prijetnji ne traži skupi alat ni mjesece rada. Za većinu aplikacija dovoljan je nacrt arhitekture, sat ili dva s razvojnim timom i zapisan popis odluka. Vrijednost je u tome što se rizik vidi dok je još jeftino mijenjati ga. Aplikacija dizajnirana s ovim pitanjima na umu izbjegava cijele kategorije propusta, dok aplikacija građena bez njih nakuplja dug koji se plaća kasnije.
Stup prvi: kontrola pristupa i autorizacija
Slaba kontrola pristupa godinama je rizik broj jedan na OWASP Top 10.1 Nastaje kad aplikacija provjeri da je korisnik prijavljen, ali ne provjeri da li smije vidjeti baš taj podatak ili izvesti baš tu radnju. Autentifikacija odgovara na pitanje tko je korisnik, autorizacija na pitanje što smije. Greška je obično u drugom.
Konkretan primjer. Korisnik otvori svoj račun na adresi koja sadrži broj 1042. Ako promijeni broj u 1043 i aplikacija mu vrati tuđi račun bez provjere vlasništva, kontrola pristupa je slomljena. Obrana je da poslužitelj pri svakom pozivu, za svaki objekt, provjeri ima li prijavljeni korisnik pravo na baš taj objekt i baš tu radnju. Provjera mora biti na poslužitelju, nikad samo u sučelju, jer sučelje napadač zaobiđe. Dobra praksa je zabraniti sve po zadanom i izričito dopustiti samo ono što je potrebno, te ovlasti voditi kroz uloge umjesto da se provjere prepisuju na svakoj ruti.
Stup drugi: autentifikacija i upravljanje sesijama
Autentifikacija mora preživjeti pokušaje preuzimanja računa. To znači snažne lozinke pohranjene kao hash s modernim algoritmom poput bcrypta, argona ili scrypta, nikad u čistom obliku ni kao obični hash bez soli. Znači i dvofaktorsku autentifikaciju na svim osjetljivim računima, ograničenje broja pokušaja prijave da se spriječi pogađanje lozinki, i zaštitu procesa oporavka lozinke koji je čest slabi bok.
Sesija je ono što povezuje prijavljenog korisnika sa svakim sljedećim zahtjevom. Identifikator sesije mora biti nepredvidljiv, prenosi se preko sigurnog kolačića s oznakama HttpOnly i Secure, i mora se promijeniti nakon prijave da se spriječi fiksacija sesije. Sesija mora isteći nakon razdoblja neaktivnosti i mora se moći opozvati pri odjavi ili sumnji na kompromitaciju. Tokeni koji se koriste umjesto sesija moraju imati kratak rok valjanosti i mehanizam obnove, da ukradeni token brzo postane bezvrijedan.
Stup treći: validacija unosa i obrana od injekcije
Injekcija nastaje kad nepouzdani unos završi u upitu prema bazi, naredbi operativnog sustava ili u stranici koju vidi drugi korisnik. SQL injekcija mijenja upit prema bazi i može otkriti ili izbrisati podatke. Cross-site scripting, XSS, ubacuje skriptu u stranicu koju izvršava preglednik žrtve. Oba propusta dijele isti uzrok: aplikacija je pomiješala podatke i naredbe.
Obrana ima dva sloja. Prvi je validacija unosa, gdje aplikacija provjeri da je unos onoga oblika koji očekuje i odbije sve ostalo, po načelu dopusti poznato dobro umjesto blokiraj poznato loše. Drugi i važniji sloj odnosi se na način korištenja podatka. Protiv SQL injekcije koriste se parametrizirani upiti koji odvajaju podatke od naredbe. Protiv XSS-a koristi se kodiranje izlaza ovisno o kontekstu u koji podatak ide, uz sigurnosno zaglavlje Content Security Policy. Validacija sama po sebi nije dovoljna, jer aplikacija mora i sigurno koristiti podatak na svakom mjestu gdje ga ispisuje ili izvršava.
Stup četvrti: sigurna konfiguracija, zaglavlja i HTTPS
Pogrešna konfiguracija je čest i lako izbježiv propust. Obuhvaća zadane lozinke koje nitko nije promijenio, administrativna sučelja otvorena prema internetu, detaljne poruke o greškama koje napadaču otkrivaju verzije i strukturu sustava, i otvorene direktorije koji ne bi smjeli biti dostupni. Obrana je dosljedan, učvršćen postav za sve okoline, uklanjanje svega što nije potrebno i različite tajne za razvoj i produkciju.
Sav promet mora ići preko HTTPS-a, uz zaglavlje HTTP Strict Transport Security koje preglednik prisiljava da uvijek koristi šifriranu vezu. Uz to se postavlja skup sigurnosnih zaglavlja koji preglednik koristi kao dodatni sloj obrane. Sljedeća tablica povezuje glavne rizike s obrambenim mjerama kroz sve stupove.
| Rizik | Obrambena mjera |
|---|---|
| Slaba kontrola pristupa | Provjera ovlasti na poslužitelju pri svakom pozivu, zabrana po zadanom, uloge. |
| Preuzimanje računa | Hash lozinki, MFA, ograničenje pokušaja, sigurne sesije. |
| SQL injekcija | Parametrizirani upiti koji odvajaju podatke od naredbe. |
| Cross-site scripting (XSS) | Kodiranje izlaza po kontekstu i Content Security Policy. |
| Pogrešna konfiguracija | Učvršćen postav, uklanjanje nepotrebnog, različite tajne po okolini. |
| Presretanje prometa | HTTPS svuda uz HSTS i ispravna sigurnosna zaglavlja. |
| Ranjive komponente | Popis ovisnosti, redovito ažuriranje i praćenje poznatih ranjivosti. |
| Tihi napadi | Bilježenje i nadzor sigurnosnih događaja s upozorenjima. |
Stup peti: ranjive komponente i lanac opskrbe
Moderna web aplikacija sastavljena je većinom od tuđeg koda: okviri, knjižnice i komponente otvorenog koda. Svaka od njih može imati javno objavljenu ranjivost. Napadač ne treba tražiti propust u vašem kodu ako zna ranjivost u verziji knjižnice koju koristite. Korištenje komponenti s poznatim ranjivostima zato je zaseban rizik na OWASP Top 10.1
Obrana počiva na vidljivosti i disciplini. Tim mora imati popis svih ovisnosti, na engleskom Software Bill of Materials, i alat koji automatski uspoređuje taj popis s bazama poznatih ranjivosti pri svakom buildu. Ovisnosti se uzimaju iz pouzdanih izvora, fiksiraju na poznate verzije i redovito ažuriraju. Ovo je jedna od onih mjera koje se najlakše automatiziraju i ugrade u razvojni proces, što nas vodi do sljedeće teme.
Stup šesti: bilježenje i nadzor
Aplikacija mora bilježiti sigurnosno važne događaje: prijave, neuspjele prijave, promjene ovlasti, pristup osjetljivim podacima i pogreške koje upućuju na napad. Bez tih zapisa napad prolazi nevidljivo i tek se mnogo kasnije otkrije da je netko mjesecima imao pristup. Zapisi se moraju slati na središnje mjesto izvan same aplikacije, gdje ih napadač ne može obrisati, i moraju pokrenuti upozorenje na sumnjive obrasce.
Bilježenje ne smije zabilježiti lozinke, tokene ni cijele osobne podatke, jer tada sam zapis postaje meta. Cilj je imati dovoljno tragova da se incident može rekonstruirati, povezati s planom odgovora na incidente i prijaviti regulatoru u rokovima koje traže GDPR i NIS2. Aplikacija koja ne bilježi ništa ne može dokazati ni što se dogodilo ni da se ništa nije dogodilo.
Kako se sigurnost ugrađuje u razvoj
Svi navedeni stupovi imaju zajedničku nit: najjeftinije ih je ugraditi rano i dosljedno, kroz cijeli razvojni ciklus. Taj pristup zove se DevSecOps, ugradnja sigurnosti u razvoj umjesto naknadne provjere. Sljedeći koraci opisuju kako tvrtka podiže razinu sigurnosti aplikacije od dizajna do produkcije.
- 01Modelirajte prijetnje pri dizajnuPrije razvoja prođite kroz arhitekturu i popišite prijetnje, tokove podataka i granice povjerenja, te zapišite kako se svaka adresira.
- 02Postavite sigurne temeljeOdaberite okvir i biblioteke koje rješavaju autentifikaciju, sesije i kodiranje izlaza, da se kritične kontrole ne pišu ručno na svakom mjestu.
- 03Automatizirajte provjere u cjevovoduUgradite skeniranje koda, provjeru ovisnosti i statičnu analizu u svaki build, tako da propusti padnu prije spajanja koda.
- 04Učvrstite konfiguraciju i zaglavljaStandardizirajte sigurnu konfiguraciju, HTTPS, sigurnosna zaglavlja i upravljanje tajnama za sve okoline.
- 05Uvedite bilježenje i nadzorBilježite sigurnosne događaje na središnje mjesto i postavite upozorenja na sumnjive obrasce.
- 06Provjerite testiranjemNakon izgradnje naručite penetracijsko testiranje da neovisno potvrdite stanje, i ponovite ga nakon većih promjena.
Izgradnja i provjera: dvije strane iste medalje
Izgradnja sigurnosti i njezina provjera pentestom razlikuju se po cilju i izvođaču. Izgradnja je trajan posao razvojnog tima koji odlučuje kako aplikacija radi. Provjera je periodičan, neovisan pogled koji traži ono što je tim previdio. Automatski alati za skeniranje hvataju dio propusta, ali greške u logici i kontroli pristupa traže ljudsku procjenu, što je razlika koju objašnjava procjena ranjivosti naspram pentesta.
Zdrav proces kombinira oboje. Tim gradi po stupovima opisanim gore, automatizirane provjere hvataju česte greške rano, a neovisni penetracijski test prije lansiranja i nakon većih promjena potvrđuje da obrana stvarno drži. Test bez dobre izgradnje samo nabraja propuste koje je trebalo izbjeći. Izgradnja bez testa je nada da je sve dobro odrađeno. Tek zajedno daju aplikaciju kojoj se može vjerovati.
Aplikacija ne postaje sigurna jer je netko testira. Test samo potvrđuje koliko je dobro izgrađena.
Usklađenost: GDPR, NIS2 i DORA
Sigurnost web aplikacija izravno dotiče regulatorne obveze. Curenje osobnih podataka kroz slabu kontrolu pristupa ili injekciju povreda je po GDPR-u, koju u pravilu treba prijaviti AZOP-u u roku od 72 sata, uz mogućnost znatnih kazni. Sigurnost razvoja i mjere zaštite podataka nisu dobrovoljne, nego dio zakonske obveze za svakoga tko obrađuje osobne podatke.
Za regulirane subjekte pod NIS2, prenesenim u Hrvatskoj kroz Zakon o kibernetičkoj sigurnosti, sigurnost aplikacija dio je obveznih mjera upravljanja rizicima. Financijske institucije pod DORA-om, Uredbom (EU) 2022/2554, moraju osigurati otpornost ključnih sustava, a web aplikacije su gotovo uvijek dio toga. Sigurnost ugrađena u dizajn, primjerice prema NIST okviru za siguran razvoj softvera,2 i redovito testiranje zajedno čine dokaz o usklađenosti.
Kako Raptoric pomaže
Pomažemo razvojnim timovima ugraditi sigurnost u dizajn i razvoj aplikacije, od modeliranja prijetnji preko kontrole pristupa i sigurne konfiguracije do bilježenja, te neovisno provjeravamo rezultat testiranjem. Sve to pružamo kroz sigurnost aplikacija i clouda, uz povezanu sigurnost API-ja za aplikacije koje se oslanjaju na API sloj. Po našem iskustvu opseg posla ovisi o veličini i složenosti aplikacije, a stvarna procjena ovisi o opsegu. Dogovorite uvodni razgovor.
