Spletno naročanje v pekarni z zaupanjem v brskalnik
Majhna pekarna prodaja 12 izdelkov prek preproste spletne strani na skupnem gostovanju. Stran je dostopna na naslovu http://www.pekarna-primer.si, obrazec za naročilo pa pošlje podatke z metodo POST na naročilo.php. V obrazcu je za vsak izdelek skrito polje s ceno, na primer <input type="hidden" name="cena_3" value="3.50">; količino in e-poštni naslov preveri le JavaScript v brskalniku. Lastnik je prejšnji teden prejel naročilo 50 kg moke po 0,01 EUR na kilogram, čeprav je cena v katalogu 1,20 EUR. V datoteki script.js je zapisano tudi geslo poštnega strežnika, administrativna stran pa je na naslovu /administracija/ brez prijave. Strežnik teče na skupnem gostovanju, kjer so na voljo PHP 8, MySQL in možnost brezplačnega potrdila Let's Encrypt, ki pa ni nameščeno. Lastnik želi čim prejšnjo rešitev, ne želi pa plačevati razvijalca za celotno prenovo sistema. Dnevniki dostopa kažejo, da je bilo v enem dnevu 400 zahtevkov na naročilo.php z različnih naslovov IP.
1. Opiši pot zahtevka od klika na gumb »Naroči« do potrditve in natančno določi, kje je bil podatek o ceni spremenjen. Zakaj strežnik tega ne more zaznati?
Read the worked answer
Pot zahtevka
- Brskalnik prebere vrednosti iz obrazca, zažene JavaScript in sestavi telo zahtevka, na primer
kolicina_3=50&cena_3=0.01&email=.... - DNS pretvori www.pekarna-primer.si v naslov IP strežnika.
- TCP vzpostavi povezavo s tristopenjskim rokovanjem (SYN, SYN-ACK, ACK) na vrata 80 – pri HTTP, ne 443, ker HTTPS ni nameščen.
- HTTP zahtevek:
POST /naročilo.php HTTP/1.1, glaveHost,Content-Type: application/x-www-form-urlencoded,Content-Length, nato telo. - Strežnik zažene PHP, prebere
$_POST, pošlje potrditveno e-pošto in vrne odgovor200 OKz zahvalo.
Kje je bila cena spremenjena
Vrednost cena_3 je prišla s odjemalca. Spremeniti jo je mogoče v brskalniku (razvijalska orodja, urejanje skritega polja), s posredniškim odjemalcem ali z ukazom curl. Ker povezava ni šifrirana, jo lahko spremeni tudi nekdo na isti brezžični mreži med prenosom (napad man in the middle).
Zakaj strežnik tega ne zazna
Strežnik nima neodvisnega vira resnice: prebere natanko tisto, kar je prispelo v zahtevku. HTTP je brezstanja in vsak vnos odjemalca je nediskriminirano vhodni podatek. Edina obramba je, da strežnik ceno ponovno izračuna iz baze glede na id_izdelka, namesto da bi ji verjel.
2. Navedi tri različne zlorabe, ki jih omogoča obstoječa zasnova, in za vsako konkreten ukrep na strežniku. Zakaj »boljše preverjanje v JavaScriptu« ne zadostuje?
Read the worked answer
Tri zlorabe in ukrepi
- Ponarejanje cene. Ukrep: strežnik prebere
id_izdelkain količino, ceno pa poišče v tabeliIzdelek; poljecena_*se v celoti ignorira ali odstrani iz obrazca. - Nesmiselna količina (negativna vrednost, 10.000 kosov, decimalno število). Ukrep: pretvorba v celo število in preverjanje obsega 1–20; če pogoj ne velja, zahtevek zavrnemo s sporočilom in ne ustvarimo naročila.
- Vnos skripte v polje ime/opomba (stored XSS), ki se izvede v brskalniku administratorja. Ukrep: pri izpisu uporabiti
htmlspecialchars(), pri pisanju v bazo pripravljene stavke (prepared statements), dodati glavo Content-Security-Policy.
Dodatno: 400 zahtevkov dnevno kaže na samodejno pošiljanje – omejevanje števila zahtevkov na naslov IP in preprosta potrditvena uganka.
Zakaj JavaScript ne zadostuje
Koda JavaScript se izvaja pri uporabniku, kjer jo napadalec nadzoruje: lahko jo onemogoči, zaobide z curl ali spremeni zahtevek po tem, ko je preverjanje opravljeno. Preverjanje v brskalniku je uporabniška izkušnja (hitra povratna informacija, manj nepotrebnih zahtevkov), ne varnostna meja. Varnostna meja mora biti vedno na strežniku, ki je edini del sistema pod nadzorom lastnika.
3. Predlagaj vrstni red sanacije z obrazložitvijo, kaj vsak ukrep odpravi in koliko truda zahteva, tako da bo rešitev izvedljiva brez celotne prenove.
Read the worked answer
Vrstni red glede na razmerje med tveganjem in trudom
- Vklop HTTPS s potrdilom Let's Encrypt in preusmeritev 301 z HTTP na HTTPS, nato HSTS. Trud: nizek (nadzorna plošča gostovanja). Odpravi: prisluškovanje in spreminjanje podatkov na poti, pa tudi opozorilo »Not secure«, ki odvrača kupce. Trenutno geslo poštnega strežnika potuje po omrežju v čistem besedilu – to je najnujnejše.
- Umik gesla iz script.js in njegova zamenjava. Trud: nizek. Vsak obiskovalec lahko danes prebere geslo. Pošiljanje pošte naj poteka izključno na strežniku.
- Preverjanje na strežniku in cena iz baze (glej prejšnjo nalogo). Trud: srednji, nekaj deset vrstic PHP. Odpravi ponarejanje cen in količin.
- Zaščita /administracija/: geslo shranjeno z
password_hash(), seja po prijavi, omejitev poskusov prijave, ločena seja od javnega dela. Trud: srednji. - Dnevnik naročil in dnevne varnostne kopije baze. Trud: nizek, a omogoči analizo po incidentu.
Zakaj tak vrstni red: vsak korak je samostojen in ne zahteva prenove, prvi trije prinašajo največje zmanjšanje tveganja na enoto truda, vsi skupaj pa ne spremenijo uporabniške izkušnje za kupca. Celovita prenova (ogrodje, ločen API) je smiselna šele, ko osnovne luknje niso več odprte.