Bezbednost web aplikacija: osnove
Web aplikaciju koristi mnogo ljudi – a neki od njih pokušavaju da je zloupotrebe. Ova lekcija objašnjava najčešće napade i osnovna pravila zaštite: HTTPS, čuvanje lozinki, proveru podataka i zašto se nikada ne veruje onome što stigne iz pregledača.
Kako da učiš: svaki primer isprobaj u pregledaču ili komandnoj liniji i uradi vežbe iz lekcije. Primeri su u HTML-u, JavaScript-u i Python-u; za većinu je dovoljan pregledač, a za Python primere instaliran Python 3.
HTTPS i sertifikati
Bez HTTPS-a podaci putuju kao razglednica – svako na putu (npr. u javnoj Wi-Fi mreži) može da ih pročita. HTTPS ih šifruje protokolom TLS i dokazuje da je server pravi:
- server ima sertifikat koji je potpisalo poverljivo telo (npr. besplatni Let's Encrypt);
- pregledač proverava sertifikat i prikazuje katanac; ako nešto ne valja – upozorenje preko cele strane;
- katanac znači da je veza sigurna, a ne da je sajt pošten – i lažni sajtovi imaju HTTPS.
Lozinke se ne čuvaju – čuva se heš
Ispravna aplikacija ne zna tvoju lozinku. U bazi čuva heš: rezultat jednosmerne funkcije iz koje se lozinka ne može vratiti. Pri prijavi se heš upisane lozinke poredi sa sačuvanim.
import hashlib, os
def napravi_hes(lozinka, so=None):
so = so or os.urandom(16) # slučajna "so" za svakog korisnika
h = hashlib.pbkdf2_hmac("sha256", lozinka.encode(), so, 200_000)
return so, h
so, sacuvan = napravi_hes("tajna123") # pri registraciji: u bazu idu so i heš
_, provera = napravi_hes("tajna123", so) # pri prijavi: isti postupak sa istom solju
print(provera == sacuvan) # True – lozinka je ispravna
_, pogresna = napravi_hes("tajna124", so)
print(pogresna == sacuvan) # False
„So“ (salt) obezbeđuje da dva korisnika sa istom lozinkom imaju različit heš, a mnogo ponavljanja (200 000) usporava napadača koji pogađa lozinke. Framework-ovi (Django, ASP.NET Core Identity) ovo rade sami – ne treba pisati svoje.
Najčešći napadi
| Napad | Šta napadač radi | Zaštita |
|---|---|---|
| SQL injekcija | u polje forme upiše deo SQL komande (npr. ' OR '1'='1) koji promeni upit nad bazom | parametrizovani upiti / ORM – nikada ne spajati tekst korisnika u SQL |
| XSS (ubacivanje skripte) | u komentar upiše <script> koji se izvrši kod drugih korisnika i ukrade im kolačić | „escape“ korisničkog teksta pre prikaza (šabloni to rade automatski), zaglavlje CSP |
| CSRF | lažna stranica natera tvoj pregledač da pošalje zahtev sajtu na kome si prijavljen/a | CSRF token u formama, kolačići sa SameSite |
| pogađanje lozinki | automatski isprobava hiljade lozinki | ograničenje broja pokušaja, jake lozinke, dvofaktorska prijava |
| phishing | lažna stranica koja izgleda kao prava i traži lozinku | proveri adresu, menadžer lozinki, dvofaktorska prijava |
Spisak najvažnijih rizika web aplikacija redovno objavljuje organizacija OWASP (Top 10).
Primer: SQL injekcija i ispravan upit
import sqlite3
baza = sqlite3.connect(":memory:")
baza.execute("CREATE TABLE korisnici (ime TEXT, lozinka_hes TEXT)")
baza.execute("INSERT INTO korisnici VALUES ('ana', 'x1'), ('marko', 'x2')")
unos = "nepostojeci' OR '1'='1" # zlonamerni unos iz forme
# POGREŠNO: tekst korisnika postaje deo SQL komande
upit = f"SELECT ime FROM korisnici WHERE ime = '{unos}'"
print("ranjivo:", baza.execute(upit).fetchall())
# ISPRAVNO: parametar (?) – baza ga tretira samo kao podatak
print("bezbedno:", baza.execute("SELECT ime FROM korisnici WHERE ime = ?", (unos,)).fetchall())
Ranjivi upit je vratio sve korisnike, jer je uslov postao „ime = 'nepostojeci' ILI 1 = 1“, a to je uvek tačno. Parametrizovani upit traži korisnika baš sa tim (čudnim) imenom – i ne nalazi ga.
Pravila za svakog programera
- Ne veruj ulazu. Sve što dolazi iz pregledača (forme, URL, kolačići, zaglavlja) može biti izmenjeno – proveri na serveru.
- Najmanja prava. Korisnik i program dobijaju samo onoliko pristupa koliko im treba.
- Tajne van koda. Lozinke baze i API ključevi idu u podešavanja servera (promenljive okruženja), ne u kod na GitHub-u.
- Ažuriraj. Framework-ovi i biblioteke redovno dobijaju bezbednosne zakrpe.
- Koristi gotova rešenja. Prijava, heširanje i zaštita formi već postoje u framework-u – ne izmišljaj svoje.
- Katanac (HTTPS) štiti vezu, ali ne garantuje da je sajt pošten.
- Nikada ne spajaj tekst korisnika u SQL upit ili HTML bez obrade.
- Probaj napade samo na sopstvenoj aplikaciji na svom računaru – na tuđim sajtovima je to zabranjeno i kažnjivo.
Proveri znanje
Otvori kviz
Bezbednost web aplikacija
1. Šta aplikacija čuva u bazi umesto lozinke?
2. Kako se sprečava SQL injekcija?
3. Šta znači katanac u adresnoj liniji?
