Skip to content

OWASP Top 10 Analysis

Aleksandar Bosnjak edited this page Sep 26, 2016 · 1 revision

OWASP Top 10 Analysis

10. Unvalidated Redirects and Forwards

U web aplikacijama je često potrebna mogućnost dinamničke redirekcije korisnika u zavisnosti od podataka koje je uneo u aplikaciju. Da razjasnimo, dinamička redirekcija podrazumeva da je klijent uneo URL kao parametar unutar requesta aplikaciji. Kada aplikacija primi request, korisnik je redirektovan na URL naznačen u requestu. Na primer:

http://www.primer.com/redirect?url=http://www.primer_neki_drugi_sajt.com/reklame

Request od gore bi redirektovao korisnika na http://www.primer_neki_drugi_sajt.com/reklame . Ovde bi bezbednosni problem bio taj da se iskoristi poznata marka organizacije da bi se phish-ovao korisnik i prevario da poseti nebezbedan sajt, u nasem slucaju http://www.primer_neki_drugi_sajt.com/reklame

Ukoliko nemamo neki custom helper koji bi nam pomogao da se izborimo sa ovim, ili whitelist, sledeci pristup bi bio u redu:

 begin
   if path = URI.parse(params[:url]).path
     redirect_to path
   end
 rescue URI::InvalidURIError
   redirect_to '/'
 end

Ukoliko baš moramo da match-ujemo input korisnika sa listom odobrenih sajtova ili TLD-ova sa regularnim izrazima, common sense bi bio da iskoristimo neku biblioteku kao što je URI.parse da bi dobili host-a i njegovu vrednost provukli kroz regularan izraz. Ukoliko ti regularni nisu napisani kako treba, postoji šansa da napadač zaobiđe validaciju (ali to nije security issue Rails-a).

Primer:

   require ‘uri’
   host = URI.parse(“#{params[:url]}”).host
   validation_routine(host) if host
   def validation_routine(host)
       # regexp po kojem validiramo
       # takođe bi bilo dobro uporediti sa nekim whitelist-om
   end

Takođe, redirekcija bez provere parametra bi mogla da dovede do XSS-a.

Primer:

   redirect_to params[:to]
   
   http://primer.com/redirect?to[status]=200&to[protocol]=javascript:alert(0)//

Tako da bi očigledno rešenje za ovu ranjivost bilo da se TLD-ovi definišu statički, ili mapiraju na hash.

Primer:

   OKEJ_URL_OVI = {
       ‘okej_url_1’ => “https://www.primer.com/fine_pare”,
       ‘okej_url_2’ => “https://www.primer_2.com/okej_url”
   }

  def redirect
      url = OKEJ_URL_OVI[“#{params[:url]}”]
      redirect_to url if url
  end

9. Using Components With Known Vulnerabilities

U 92 gem-a koja koristimo u api-ju pronadjeno je 10 ranjivosti:

Oznaka Gem Kategorija Izvor Ozbiljnost
CVE-2015-7581 rails (4.2.4) Resource Management NIST NVD Severe
CVE-2015-1820 / OSVDB-119878 rest-client (1.6.7) Session Setting GitHub Severe
CVE-2015-7576 rails (4.2.4) Other NIST NVD Moderate
CVE-2015-7577 rails (4.2.4) Other NIST NVD Severe
CVE-2015-7578 rails-html-sanitizer (1.0.3) Cross-Site Scripting NIST NVD Moderate
CVE-2016-2098 rails (4.2.4) Attribute Restriction NIST NVD Critical
CVE-2016-0753 rails (4.2.4) Input Validation NIST NVD Severe
CVE-2015-3448 / OSVDB-117461 rest-client (1.6.7) Information Disclosure NIST NVD Moderate
CVE-2016-0751 rails (4.2.4) Resource Management NIST NVD Severe
CVE-2016-0752 rails (4.2.4) File Access NIST NVD Severe

8. Cross-Site Request Forgery

Rails ima ugrađenu podršku za CSRF tokene. Da bi se ona omogućila potrebno je u Application controller-u uraditi sledeće:

   class ApplicationController < ActionController::Base
       protect_from_forgery

Iako Rails već poseduje gore navedenu podršku za CSRF tokene, zbog toga što je naša aplikacija samo API koristimo devise_token_auth u bekendu i ng-token-auth.

7. Missing Function Level Access Control

U Railsu se ovo obično dešava ukoliko filteri na nivou kontrolera nisu podešeni kako treba. Na primer, ukoliko neko ko nije ulogovan ne sme da pristupi određenim akcijama kontrolera, a nije setovan odgovarajuci filter, doći će do toga da korisnik bez prava pristupa pristupi određenim akcijama kojima ne bi trebao da ima pristup.

Primer jednog filtera:

before_filter :authenticate_user!

Ovaj filter možemo iskoristiti na dva načina:

  • Zaštititi celu aplikaciju tako što će se on postaviti u ApplicationController i skipovati ga samo tamo gde je potrebno
  • Stavljati ga u svaki kontroler i skipovati akcije koje ne zelimo da zastitimo.

Takođe, ukoliko radimo na aplikaciji koja ima više tipova korisnika (admin i običan korisnik) moramo se osigurati da tip korisnika koji je nižeg nivoa nema pristupa akcijama i metodama korisnika višeg nivoa. To možemo sprečiti proverom tipa korisnika uz pomoć npr CanCanCan gem-a.

6. Sensitive Data Exposure

U okviru razmatranog sistema, pod osetljive podatke spadaju:

  • računi poslovih parnetra/razmatranog preduzeća
  • spisak transakcija(porudžbina/potražnje) između posmatranog preduzeća i poslovnih partnera
  • spisak faktura, koje primamo ili koje izdajemo

Pošto razmatrani sistem mrežno komunicira sa eksternim entitetima kao što su banka i poslovni partneri, kako neko ne bi prisluškivao(sniffing) poverljive podatke koje smo naveli, potrebno je enkriptovati komunikaciju. Komunikacija između eksternog entiteta i našeg preduzeća implementirana je preko HTTPS protokola, čime se garantuje tajnost informacija, i nemogućnost da se cipher-text pretvori u plain-text u nekom razumnom vremenu. Međutim kako smo spomenuli u analizi pod brojem 5. debugging mode na glavnom back-end-u aplikacije nije isključen i korisnik ima mogućnosti da vidi spisak svih ruta, gde je uz pojedine akcije u mogućnosti da dođe do nama važnih poverljivih podataka. Primer otkrivanja takvih podataka je predstavljen u 2 koraka:

  1. Korisnik šalje zahtev http://localhost:3000/neki_nepostojeci_url kako bi dobio informacije o svim rutama koje aplikacija podržava.

  2. Sada je samo neophodno uočiti rute koje vode ka resursima od interesa, i u zavisnosti od toga poslati novi zahtev. Npr. ako želimo da imamo spisak svih ulaznih faktura izdatih od strane poslovnih partnera poslaćemo get zahtev sa web browser-om na URL https://localhost:3001/api/input_invoices gde ćemo dobiti spisak svih izdatih faktura u JSON formatu.

5. Security Misconfiguration

Podešavanje samog servera je nekada dostupno developer-u npr. ukoliko imamo pristup računaru na kom je pokrenut server tada je neophodno proći kroz dobro poznate check-list-e. Pošto je server pokrenut na Ubuntu 15.0, neophodno je ispoštovati određene procedure. Lynis je alat za proveravanje sigurnostih postavki sistema. Pokrenuta je pretraga operativnog sistema sa ./lynis audit system, gde su dobijeni odgovarajući rezultati. Detaljnija analiza sistema koji je deploy-ovan na heroku nije omogućena pošto je heroku PaaS, pa je korišćen online alat SSL Server, gde su dobijeni sledeći [rezultati] (https://www.ssllabs.com/ssltest/analyze.html?d=receipt-yourself.herokuapp.com).

Lako se može uočiti da debugging mode nije isključen što daje uvid napadaču u unutrašnju strukturu sistema. Test nalozi sa standardnim kredencijalima tipa admin/admin ili admin/1234 ili slično ne postoje u sistemu. Onemogućen je pristup izlistavanja sadržaja direktorijuma(standardno file-system pretraživanje), zbog definisanih pravila pristupa resursima pomenutih u analizi pod 4. Aplikacija neće raditi sa stream-ovanjem pa bi bilo poželjno isključiti UserDatagram Protocol zbog potecijalnog DDOS napada.

Koristiti Principle of Least Privilege što znači da treba isključiti sve funkcionalnosti po default-u, a uključiti samo one koje su nam neophodne. Ukoliko nismo sigurni, pustimo sistem da funkcioniše, pa ćemo kroz samo funkcionisanje sistema biti u mogućnosti da zaključimo koje su nam funkcionalnosi vitane za pravilan rad sistema.

4. Insecure Direct Object References

Rails po defaultu koristi RESTFul URI strukturu za pristup resursima, definisanu u datoteci conf/routes.rb. Zbog konfiguracije pristupa resursa(definisanjem ruta u prethodno navedenoj datoteci) onemogućen je direktan pristup resursima koji nisu opisani rutama. Dakle onemogućen je direktni pristup datotekama npr: https://localhost:3001/config/routes.rb ili navigacija putem file system-a https://localhost:3001/../some_file.dat.

Konkretno svi korisnici ovog sistema pripadaju istoj grupi korisnika(sa istim pravima pristupa i modifikacije). Međutim ukoliko bi se u sistem uvelo više uloga putem RBAC-a, pored zaštite na UI(da korisnik u zavisnosti od tipa uloge tj. prava u sistemu, vidi samo za njega relevantne stvari). Zaštita na UI treba da se pravi tako da oni delovi UI koji ne pripadaju korisniku u zavisnosti od njegovih privilegija, budu direktno izbačeni iz DOM stabla. Taj efekat se dobija korišćenjem <div ng-if="expression">admin rights...</div>, ukoliko bi koristili umesto ng-if, ng-show na taj način bi se lako mogao prikazati i taj UI sadržaj, i samim tim omogućiti korisniku da izvršava nedozvoljene operacije nad sistemom. Kao dodatna sigurnost, neophodno je uraditi double-check tako što će u kontrolere biti ubačen dodatni mehanizam zaštite koji će određivati da li će se kontroler izvršavati u zavisnosti od tipa korisnika na sesiji, ili neće. CanCanCan je primer biblioteke koja štiti kontrolere od neovlašćenog pristupa.

3. Cross-Site Scripting

Prevencija CSS-a je podržana u Rails-u od verzije 3.0. Kada se određeni string prikazuje u view delu aplikacije, on biva automatski sanitiziran. Naravno, postoje slučajevi kada se ovo može zaobići, a obično je greška programera!

  <%= raw @product.name %>   
  <%= @product.name.html_safe %> # ovo je primer kako ne treba raditi!
  <%= content_tag @product.name %>

Ovo se dešava kada želimo klijentu da omogućimo "Rich text editing", tj. kada klijentu omogućimu da unosi HTML tagove unutar input polja. Da bismo podržali ovaj feature, i ostavili mogućnost korisnicima da unose HTML sadržaj, trebali bismo to omogućiti preko nekih drugim "markup" jezika kao što su Markdown ili Textile. Ako baš ne možemo da sprečimo korisnika da unosi HTML, Rails ima metodu #sanitize ali ni ovo nije kompletno rešenje.

Za view deo koji je pisan u Angularu možemo koristiti kombinaciju ng-bind directive za input polja. Na ovaj način, sav sadržaj koji se nađe unutar input polja sa ng-bind atributom će biti provučen kroz Angular-ov filter sanitize koji će sanitizirati svaki maliciozan HTML koji je korisnik uneo.

2. Broken Authentication and Session Management

Session Management

Ugrađeno ponašanje Rails-a je da koristi sesiju baziranu na korisničkom Cookie-ju (sesija se čuva u cookie-ju). Ako ne promenimo podešavanja servera, ovo znači da sesija neće nikad isteći na serveru. Ovo implicira da će aplikacije biti ranjiva na "replay" napade. Takođe, osetljive informacije ne bi trebalo stavljati u sesiju iz ovih razloga.

Lak način da se izbegne ovo je da se sesija čuva u bazi. Ovo je lako izvesti u Rails-u uz pomoć:

  Project::Application.config.session_store :active_record_store

podešavanja unutar aplikacije. Ovim kažemo da se sesija čuva u bazi umesto u cookie-ju.

Authentication

Rails ne podržava autentifikaciju "out of the box", ali se ona može lako uvesti u aplikaciju uz pomoć gem-ova kao što su Devise i AuthLogic. Razlike između ova dva su minimalne što se tiče bezbednosti. U našem projektu mi smo koristili Devise gem. Da bismo autentifikovali korisnika koristili smo autentifikaciju pre zvanja svake akcije koju imamo u aplikaciji. Ovo smo postigli stavljajući:

  class RandomController < ApplicationController
    before_filter :authenticate_user

Filter pre svake akcije proverava da li je pravi korisnik ulogovan. Ako korisnik nije ulogovan, redirektujemo ga na 404 stranicu.

1. Injection

Command Injection

Ruby ima funkciju eval koja može biti jako opasna i može dovesti do lakog command injectiona unutar aplikacije. eval funkcija evaluira string koji joj je prosleđen u Ruby kod. Ovo može biti veoma opasno.

Takođe postoji i funkcija preko kojeg možemo pozivati sistemske komande zvana System. Ovoj funkciji možemo proslediti bilo kakve komande koje operativni sistem ispod aplikacije može da izvrši. Takođe postoji i Kernel klasa sa svojom #exec metodom koja radi sličnu stvar sa kernelom ispod aplikacije.

  eval("ruby code here")
  System("os command here")
  Kernel.exec("os command here")

Iako su ovi pozivi veoma moćni, korišćenje se ne preporučuje i uglavnom je veoma loša ideja. Preporuka je da se ne koriste ako je moguće. Ako baš moraju da se koriste preporučuje se da se napravi whitelist komandi koje su dozvoljene za izvršavanje i da se radi provera komande pre nego što se izvrši.

SQL Injection

Rails se obično koristi sa ORM-om (Object Relationship Mapping) koji se zove ActiveRecord. ActiveRecord je odlično zaštićen od SQL Injection napada, mada se često dešava da početnici pišu kod uz pomoć koga je veoma lako izvršiti ovaj napad.

Klasični primer lošeg koda je kad upitima direktno prosledimo neobrađene parametre koji su stigli sa klijentske strane.

U primeru ispod vidimo kako se upitu direktno prosleđuje parametar id. Ovo dozvoljava korisniku da prosledi bilo koji string unutar id parametra i tako korumpira našu bazu podataka.

params[:id] = "admin = 't'"
User.find_by params[:id]

Ovo će dati sledeći SQL:

Query
  SELECT "users".* FROM "users" WHERE (admin = 't') LIMIT 1
Result
  #<User id: 30, name: "Admin", password: "supersecretpass", age: 25, admin: true, created_at: "2016-01-19 16:12:11", updated_at: "2016-01-19 16:12:11">

tj. na lak način smo dobili korisnika koji je admin aplikacije.

Ovo možemo sprečiti koristeći AREL rešenje:

User.find_by("id = ?", params[:id])

ili

User.find_by_id params[:id]

U Rails-u se lako može pogrešiti i napisati SQL Injection friendly kod zbog velike količine sintaksnog šećera koji je uveden u ActiveRecord. Na ovaj način programeri zaboravljaju šta se dešava ispod sintakse koje kucaju tj. kakvi SQL upiti se formiraju na osnovu njihovo koda. Ovo se može sprečiti edukacijom i pregledom najčešćih grešaka u pisanju koda koji dovlači nešto iz baze podataka. Dobro mesto za početak je Rails SQL Injection sajt koji predstavlja najčešće greške koje se javljaju u kucanju takvog koda.

References: