nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Članci
     (spisak)
  • Kontakt
Povratak na vrh stranice

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 17.06.2021.

trejler_olovka Poslednja izmena: 11.06.2024.

trejler_dokument Jezici: ----

trejler_teg_narandzasti Težina: 7/10

json
token
jwt
json web token
autorizacija
login
prijava
internet
sigurnost
optimizacija
backend
fullstack
teorija
zanimljivosti

Povezani članci

JSON - tekstualni format za razmenu podatakaLokalno skladištenje podataka browsera (sessionStorage, localStorage, cookies)JavaScript ES6 sintaksaŠablonske niske u programskim jezicimaASCII, Unicode i UTF - Predstavljanje znakova na računarimaAsinhrono programiranje u JavaScriptuUvod u Node.jsUvod u PHP i back-end programiranjeUvod u JavaScript i DOM (Document Object Model)HTTP statusni kodoviStruktura web adresa i pristup internet stranicama
Svi članci
There are only two industries that refer to their customers as ‘users’.
Edward Tufte

JSON Web Token (JWT) - Struktura i primena u oblasti autorizacije web aplikacija

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark
početna > Članci > Teorija

Uvod

Budući da smo u jednom od prethodnih članaka detaljno predstavili postupak izrade formulara za autentifikaciju korisnika, čini se da je upoznavanje sa sistemima za autorizaciju korisnika, sledeći prirodan korak.

Pre svega, da objasnimo u čemu je razlika između dva navedena pojma:

  • autentifikacija je proces utvrđivanja identiteta korisnika (praktično se proverava da li korisnik (uopšte) ima pravo da pristupi sistemu)
  • autorizacija podrazumeva definisanje nivoa privilegija za korisnike koji su prethodno stekli pravo pristupa

Korišćenje JSON Web Tokena * (posebno formatiranih JSON objekata), predstavlja jedan od načina za autorizaciju korisnika (i glavnu temu članka), ali, prvo ćemo se osvrnuti ponešto detaljnije na problematiku autorizacije u opštem smislu.

* Token (eng.) je drugi naziv za žeton (fr. jeton). Više o vezi između 'tokena i žetona', nešto kasnije u članku....

Problematika autorizacije korisnika uopšteno

Postupak autorizacije naizgled ne deluje 'previše komplikovano', i stoga većina korisnika (i izvestan broj nedovoljno iskusnih programera), često ima utisak da posle uspešno završene prijave (to jest, posle uspešno obavljene autentifikacije), nema potrebe za preduzimanjem dodatnih koraka u situacijama kada se korisnik nadalje obraća serveru, ili (malo drugačije), deluje da se dalja komunikacija između korisnika i servera (u smislu provere identiteta korisnika i utvrđivanja privilegija), odvija "sama od sebe".

Naravno, takav utisak je u najmanju ruku varljiv, i svakako postoji razlika između toga šta se prividno dešava, i onoga što se zapravo dešava pri prosleđivanju podataka ....

Šta se naizgled dešava posle prijave korisnika?

Jednostavan odgovor na pitanje iz naslova, mogao bi biti, "Posle prijave, korisnik dobija pravo pristupa odgovarajućim sadržajima".

Koristeći se dobro poznatim primerom društvenih mreža: posle prijave na nalog (autentifikacija), korisnik dobija pristup početnoj stranici na kojoj može videti svoj 'avatar' i korisničko ime (najčešće u gornjem delu prozora), dok centralni deo zauzimaju sadržaji koje su objavljivali korisnik i osobe sa kojima je korisnik u kontaktu.

Ako korisnik pozove (npr) chat aplikaciju, može nekome od prijatelja poslati poruku pod svojim imenom, i (takođe), sledeći put kada otvori istu stranicu u browseru, neće morati ponovo da se prijavljuje, i dočekaće ga isti sadržaji (zapravo, najverovatnije ponešto izmenjeni sadržaji - u međuvremenu će još neko od poznanika napraviti još neku objavu).

Osim navedenog, u svemu se podrazumeva (ili makar "očekuje" :)), da ostali korisnici neće moći tek tako da "čeprkaju" po nalogu.

Šta se zapravo dešava posle prijave korisnika?

Na drugo pitanje daćemo drugačiji odgovor: na površini se i dalje dešava sve ono što smo prethodno opisali, ali (pretpostavljamo da je do sada postalo sasvim jasno) - ne dešava se "samo od sebe".

Da bi sve, iz perspektive korisnika, u praksi funkcionisalo onako kako smo navikli (i naveli u prethodnom odeljku), u pozadini se odvijaju brojni procesi.

O nekim procesima već smo diskutovali u ranijim člancima, neke ćemo opisati u ovom članku, neke u budućim člancima, ali, pre svega: potrebno je osmisliti racionalan sistem za pamćenje korisničkih podataka - da korisnici ne bi morali da se prijavljuju 'svaki čas' * (browser sam po sebi ne pamti uneto korisničko ime i lozinku automatski, i stoga, ili korisnici moraju ponovo unositi podatke za prijavu pri sledećem pokretanju, ili treba osmisliti siguran i praktičan način za čuvanje korisničkih podataka).

* Teoretski, mogli bismo svaki put da unosimo podatke za prijavu, ali, u praksi, takav pristup je prilično 'neudoban', i stoga - u velikoj većini web aplikacija - korisnici ne unose podatke za prijavu pri svakom pokretanju aplikacije (pogotovo ne pri slanju svake poruke i sl).

Ali .... povremeno ima izuzetaka ....

Aplikacije za transfer finansijskih sredstava, kao i druge aplikacije koje operišu sa vanredno osetljivim podacima, vrlo često obavezuju korisnike da se prijavljuju neposredno pre svake transakcije.

Pored do sada navedenih detalja, može se desiti i to da korisnik izgubi privilegije za pristup određenoj aplikaciji (recimo, privilegije za slanje poruka u chat aplikaciji, zbog neprimerenog ponašanja i sl), pri čemu je aplikacija ostala otvorena, što, ukoliko se privilegije ne proveravaju pri slanju svakog zahteva, može dovesti do nepravilnosti u radu.

Dakle, pri slanju svakog zahteva, potrebno je obaviti autorizaciju (tj. potrebno je proveriti 'da li korisnik ima pravo da šalje zahtev koji je poslao'), što podrazumeva jednu od dve prethodno pomenute mogućnosti:

  • prosleđivanje podataka za prijavu (korisničko ime i lozinka)
  • prosleđivanje posebno formatiranih podataka za autorizaciju (koji se čuvaju u nekom od lokalnih skladišta)

Pošto smo 'nezvanično utvrdili' da nije praktično (u većini slučajeva) da korisnici sistema prosleđuju korisničko ime i lozinku uz svaki zahtev (to jest, u većini situacija je znatno praktičnije izabrati opciju #2), vraćamo se na pitanje: koje podatke je potrebno čuvati, i - u kom formatu?

Reklo bi se da je došao trenutak da se JSON web tokeni vrate u diskusiju ....

JSON Web Tokeni - Struktura, oblast primene i postupak autorizacije

Kao što smo nagovestili još na početku, upotreba tokena u računarskim sistemima, u idejnom smislu se podudara sa upotrebom "žetona" u spoljnjem svetu.

U smislu pojavnog oblika, žeton je pljosnati komad plastike ili metala (najčešće okruglog oblika), koji se u ranijim vremenima * koristio za razne automate (javne telefone, električne automobile i ringišpile u zabavnim parkovima i sl), međutim, u smislu značenja koje ima u određenom kontekstu, 'žeton' (ili 'token') simbolično predstavlja određenu privilegiju (tj. mogućnost korišćenja određenih sadržaja):

  • na telefonskoj govornici ili u zabavnom parku, žeton omogućava korišćenje odgovarajućih sadržaja bez daljeg plaćanja novcem
  • u web aplikacijama, token simbolično predstavlja privilegiju korisnika da pristupi određenim sadržajima aplikacije, odnosno, da koristi aplikaciju tj. sajt - bez potrebe da "svaki čas" prosleđuje osetljive podatke koji su korišćeni za prijavu (npr. lozinku) **

* Žetoni se koriste i u današnje vreme, ali, ne toliko često kao ranije.

** U kontekstu sigurnosti u računarskim mrežama, korisničko ime se u većini situacija ne smatra poverljivom informacijom (pogotovo npr. u slučaju društvenih mreža, gde je korisničko ime jednog korisnika najčešće dostupno svim ostalim korisnicima), dok, sa druge strane - lozinka i te kako predstavlja poverljivu informaciju, i stoga se lozinke nikako ne čuvaju u izvornom obliku (bar 'po pravilu'). :)

Kada je sigurnost u pitanju, napomenimo i to da izdati JSON tokeni mogu biti ukradeni (ili kompromitovani na neki drugi način), ali, u ovom članku upoznaćemo se samo sa osnovnim osobinama JSON web tokena i sa time kako se tokeni koriste za autorizaciju korisnika, dok ćemo ostalim pitanjima koja se tiču sigurnosnih rizika pri upotrebi tokena (odnosno, rizika u procesu autorizacije uopšte), posvetiti zaseban članak.

Da bi web token mogao u praksi funkcionisati kao mehanizam za autorizaciju, potrebno je postići ravnotežu između dva (naizgled) oprečna zahteva: JSON web token mora sadržati dovoljno informacija za identifikaciju korisnika i dodelu privilegija, ali - tako da nijedna od zapisanih informacija ne bude poverljiva (lozinka ili drugi osetljivi podaci).

Prvo ćemo detaljno razmotriti sve zahteve koji se postavljaju pred sistem za autorizaciju koji je zasnovan na tokenima, a onda ćemo se osvrnuti i na implementaciju.

Struktura JSON Web Tokena

Zahtevi koji se stavljaju pred web token su sledeći:

  • token mora biti u stanju da identifikuje korisnika i omogući dodelu odgovarajućih privilegija korisniku
  • navedeni zadatak potrebno je rešiti bez čuvanja osetljivih podataka o korisniku (ime, prezime, pogotovo ne korisnička lozinka i drugi osetljivi podaci)
  • token obavezno mora sadržati određeni mehanizam za zaštitu podataka (kao zamenu za lozinku)
  • svi podaci koji su potrebni za autorizaciju, moraju biti sadržani u samom tokenu, i treba ih čuvati na strani klijenta

Implementacija koja poštuje sve navedene zahteve, može se realizovati preko JSON objekta koji se sastoji od sledeća tri dela:

  • zaglavlje - deo u kome je naveden kriptografski algoritam preko koga nastaje potpis (poslednji deo JWT-a)
  • sadržaj - glavni deo tokena, koji obuhvata informacije za autorizaciju (korisničko ime, nivo privilegija i druge informacije koje su neophodne za autorizaciju, ali, nisu poverljive)
  • potpis - kontrolni deo koji nastaje enkripcijom kombinacije prethodna dva dela, uz korišćenje šifara (pri čemu odmah treba pomenuti da nisu u pitanju korisničke lozinke, već, šifre ili posebno formatirani 'ključevi' koji se čuvaju na serveru)

Prva dva dela JSON Web Tokena (koji odgovara navedenim zahtevima), biće enkodirani, a pre enkodiranja, navedeni delovi imaju strukturu koja je definisana po sledećem obrascu:

		
// zaglavlje (izabrani metod enkripcije):

{
	"alg": "HS256",
	"typ": "JWT"
}

// sadržaj (info o korisniku):

{
	"id":             42,
	"admin":          true,
	"korisnicko_ime": "darth_korisnik",
	"iat":            1516239022

	// Podaci kao što su:
	// ID korisnika, korisničko ime, informacija o
	// tome da li korisnik nema administratorske privilegije,
	// vreme izdavanja tokena (iat - issued at) -
	// ne smatraju se osetljivim podacima
}
		
	
Slika 1. - Primer strukture zaglavlja i podataka za autorizaciju - pre enkodiranja.

Potpis nastaje kriptovanjem enkodiranog zaglavlja i sadržaja, uz korišćenje šifre:

		
HMACSHA256(
  base64UrlEncode(zaglavlje) + '.' +
  base64UrlEncode(sadržaj),
  tajna_šifra
) 
		
	
Slika 2. - Šematski prikaz funkcije za haširanje JWT-a.

Posle završenog procesa enkodiranja, token dobija svoj finalni oblik:

		
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJpZCI6NDIsImFkbWluIjp0cnVlLCJrb3Jpc25pY2tvX2ltZSI6ImRhcnRoX2tvcmlzbmlrIn0.
4TEC8hmvR9JyB5dKUglCfLA2b2QyEdMVVlz4m2euSnY
		
	
Slika 3. - Sadržaj JSON web tokena koji nosi podatke sa slike #1.

Da pojasnimo dodatno: enkodiranje koje smo spomenuli (Base64), nije metoda enkripcije (odnosno metoda zaštite), već, način da se određeni niz bajtova - pre enkripcije - svede na nisku koja odgovara određenoj specifikaciji (u konkretnom slučaju, proizvoljna niska znakova koja možda sadrži i Unicode znake, biva svedena na nisku koja se sastoji isključivo od ASCII slova i cifara).

Enkodiranje, kao proces koji je reverzibilan, * ne pruža nikakvu zaštitu (odnosno "skrivanje podataka").

Zaglavlje i sadržaj su direktno dostupni bilo kome ko pročita token, ali - to je sasvim u redu, budući da smo još ranije utvrdili da JWT neće nositi poverljive podatke (već samo podatke koji su i inače javno dostupni), i stoga ne moramo brinuti o tome da će preko JW tokena neko doći do poverljivih podataka.

* Od enkodirane niske, moguće je - obrnutim postupkom - dobiti ulazni podatak, i to je nešto što će u slučaju JWT-a svakako biti od koristi (ali, kao što smo već naveli, ne u smislu zaštite podataka).

Zaštita se zapravo postiže upotrebom hash funkcija, uz korišćenje tajne šifre ('secret'), ili ključeva (što su podaci koji se čuvaju na serveru).

Enkripcija je postupak svođenja niza bajtova na nisku proizvoljne dužine, * čiji sadržaj se ne može upotrebiti za dobijanje ulaznog podatka (u ovom slučaju, proces nije reverzibilan), ali - u pitanju je niska koja je jedinstvena (teorija nalaže da bi svakom ulaznom podatku morala odgovarati samo jedna niska koja nastaje procesom haširanja, a kada su u pitanju algoritmi koji se tipično koriste za potpisivanje i verifikaciju JW tokena, praksa još uvek nije opovrgla teoriju).

U nastavku, sledi primer vrlo jednostavne ** implementacije JW tokena uz korišćenje ugrađenog modula crypto (implementaciju možete isprobati u radnom okruženju Node.js), a nakon toga, prikazaćemo opšte principe upotrebe JW tokena u cilju autorizacije korisnika. ***

* Na primer, algoritam SHA256 vraća niske dužine 64 karaktera.

** Programski kod koji sledi u nastavku, sasvim uspešno ilustruje proces kreiranja i verifikacije JW tokena, ali, u produkcijskim uslovima, nedvosmisleno preporučujemo da koristite gotova, isprobana open-source rešenja (zarad sigurnosti podataka).

*** Korišćenje (ponešto) kompleksnijih postupaka pri potpisivanju tokena, prikazaćemo drugom prilikom (u članku koji ćemo posvetiti kreiranju Node.js servera).

Takođe, u ovom članku samo smo se dotakli tematike enkodiranja i enkripcije (kao i razlika između dva pristupa), ali, uskoro ćemo navedenim temama posvetiti više prostora.

Implementacija u okruženju Node.js

Budući da smo se u članku o ES6 sintaksi već upoznali sa konceptom upotrebe modula u (iole) ozbiljnijim JS projektima, funkcije koje ćemo koristiti za potpisivanje i verifikaciju tokena biće 'razdeljene' u odgovarajuće module.

Za sam početak, pripremićemo modul sa nekoliko pomoćnih funkcija.

Funkcije za enkodiranje i dekodiranje podrazumevaju dodatne korake koji se tiču pravilne obrade niski koje sadrže Unicode znakove (odnosno, znakove kojih nema u ASCII specifikaciji), a potrebno je koristiti i pomoćnu funkciju koja uklanja znakove = sa desne strane (koji se pojavljuju u slučajevima kada enkodirane niske imaju dužinu koja nije deljiva sa 4).

		
/* ------------------------- */
// Modul 'util'
/* ------------------------- */
// Da bi funkcija btoa mogla uredno da obradi
// Unicode znakove, potrebno je koristiti i funkcije
// encodeURIComponent i unescape, na sledeći način:
export function enkodiranje(s) {
	let s1 = encodeURIComponent(s)
	let s2 = unescape(s1)
	let s3 = btoa(s2)
	return s3;
}
// Da bi funkcija atob mogla uredno da obradi
// Unicode znakove, potrebno je koristiti i funkcije
// decodeURIComponent i escape, na sledeći način:
export function dekodiranje(s) {
	let s1 = atob(s)
	let s2 = decodneURIComponent(s1)
	let s3 = escape(s2)
	return s3;
}
/* ------------------------- */
// Pomoćna funkcija za uklanjanje znakova '=',
// koji se automatski dodaju sa desne strane
// ukoliko broj znakova u niski
// (koja se dobija preko funkcije enkodiranje),
// nije deljiv sa 4.
export function desniTrim(s, c) {
	let i = s.length - 1
	let p = 0;

	while (s[i] == c) {
		p++;
		i--;
	}

	return s.substring(0, s.length - p);
}
/* ------------------------- */
		
	
Slika 4. - Modul 'util' (koji sadrži pomoćne funkcije).

Tajnu šifru preporučljivo je čuvati preko zasebnog modula (koji tipično nosi naziv "config") ....

		
/* ------------------------- */
// Modul 'config'
/* ------------------------- */
export const secret = `You .... shall .... not .... pass!`
		
	
Slika 5. - Modul 'config' (koji u ovom slučaju sadrži samo tajnu šifru za kreiranje i verifikaciju potpisa).

.... a u slučaju kada se koriste komplikovanije metode enkripcije, sa dva ključa, praktično je obavezno (i vrlo uobičajeno), da svaki ključ bude u zasebnoj datoteci.

Tajna šifra koja je zapisana u zasebnoj datoteci (u koju mogu biti smešteni i ostali poverljivi podaci), neće se pojavljivati direktno u ostalim modulima u projektu.

Na primer: ukoliko koristite Git za praćenje promena u projektu, datoteka koja sadrži šifre, ključeve i druge osetljive podatke (datoteka .env ili config.js i sl), može se lako isključiti iz praćenja (.gitignore).

Kreiranje potpisa

U modulu sa funkcijama preko kojih se obavlja potpisivanje tokena, ovoga puta ćemo podatke zapisati unapred, nakon čega sledi obrada:

  • (budući) delovi tokena pretvaraju se u JSON objekte *
  • obavlja se enkodiranje po standardu Base64
  • enkodirano zaglavlje se spaja sa enkodiranim sadržajem
  • poziva se funkcija za kreiranje potpisa

* JSON objekti moraju biti zapisani bez razmaka i drugih whitespace znakova (onako kako možete videti u donjim komentarima).

Na kraju, sva tri dela JW tokena, spajaju se u jednu nisku.

		
/* ------------------------- */
// Modul 'potpisivanje'
/* ------------------------- */
import crypto from 'crypto'
import { enkodiranje, desniTrim }  from './util.js'
import * as config from './config.js'
/* ------------------------- */
// Ulazni podaci:
let token_raw = {
	header: {
		"alg": "HS256",
		"typ": "JWT"
	},
	payload: {
		"id":             42,
		"admin":          true,
		"korisnicko_ime": "darth_korisnik"
	}
}
/* ------------------------- */
// Zaglavlje i sadržaj moraju biti zapisani bez
// whitespace znakova ....
let jtrim_1 = JSON.stringify(token_raw.header)
let jtrim_2 = JSON.stringify(token_raw.payload)
// {"alg":"HS256","typ":"JWT"}
// {"id":42,"admin":true,"korisnicko_ime":"darth_korisnik"}

// Base64 enkodiranje ulaznih podataka:
let jwt_h = enkodiranje(jtrim_1)
let jwt_p = enkodiranje(jtrim_2)
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
// eyJpZCI6NDIsImFkbWluIjp0cnVlLCJrb3Jpc25pY2tvX2ltZSI6ImRhcnRoX2tvcmlzbmlrIn0=

// Uklanjanje znakova '=' sa desne strane niski:
let jwt_1 = desniTrim(jwt_h, '=')
let jwt_2 = desniTrim(jwt_p, '=')

// Kao što je ranije navedeno, zaglavlje i sadržaj koji su
// enkodirani, spajaju se preko znaka '.', i takva niska
// predstavlja ulaznu vrednost naredbe za kreiranje potpisa:
let s = `${jwt_1}.${jwt_2}`
/* ------------------------- */
// Kreiranje potpisa uz korišćenje tajne šifre:
const potpis = crypto.createHmac('sha256', config.secret)  
                 .update(s)  
                 .digest('base64')
/* ------------------------- */
// Potpis takođe može sadržati znakove '='
// sa desne strane ....
let jwt_3 = desniTrim(potpis, '=')
// Sastavljanje JW tokena:
let token = `${jwt_1}.${jwt_2}.${jwt_3}`
/* ------------------------- */
console.log(token)
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsImFkbWluIjp0cnVlLCJrb3Jpc25pY2tvX2ltZSI6ImRhcnRoX2tvcmlzbmlrIn0.4TEC8hmvR9JyB5dKUglCfLA2b2QyEdMVVlz4m2euSnY
/* ------------------------- */

		
	
Slika 6. - Modul sa instrukcijama za 'potpisivanje' tokena.

Verifikacija potpisa

U slučaju korišćenja metode HMAC, verifikacija potpisa može se obaviti ponovnim kreiranjem potpisa shodno podacima koji su zapisani u tokenu.

		
/* ------------------------- */
// Modul 'verifikacija'
/* ------------------------- */
import crypto from 'crypto'
import { dekodiranje }  from './util.js'
import * as config from './config.js'
/* ------------------------- */
const token = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDIsImFkbWluIjp0cnVlLCJrb3Jpc25pY2tvX2ltZSI6ImRhcnRoX2tvcmlzbmlrIn0.4TEC8hmvR9JyB5dKUglCfLA2b2QyEdMVVlz4m2euSnY`

const delovi = token.split('.')
console.log(delovi[0])
console.log(delovi[1])
console.log(delovi[2])

let s = `${delovi[0]}.${delovi[1]}`
console.log(dekodiranje(delovi[0]))
console.log(dekodiranje(delovi[1]))
		
	
Slika 7. - Modul sa instrukcijama za verifikaciju tokena - početna faza (prepustićemo čitaocima da sami osmisle ostatak). :)

Pustićemo vas da glavnu metodu za verifikaciju osmislite sami, ali, osnovna ideja je prilično jednostavna: prvo je potrebno podeliti token na tri dela, nakon čega se obavlja dekodiranje prva dva dela, i (na kraju), ukoliko od 'dekodiranih delova' (uz korišćenje postupka koji smo ranije prikazali), nastane potpis koji je isti kao i potpis koji je došao uz token, sledi da je token validan.

Generator JWT-a

Ako želite da isprobate kako u praksi funkcioniše kreiranje JSON web tokena, sa podacima po vašem izboru, možete iskoristiti donji formular.

Zaglavlje:
{
	"alg": "HS256",
	"typ": "JWT"
}
Sadržaj:
{
	"id":             42,
	"admin":          true,
	"korisnicko_ime": "darth_korisnik"
}
Tajna šifra ("secret"):
You .... shall .... not .... pass!
Token:

Primećujemo da se enkodirana verzija središnje niske menja samo "mestimično" (u onom delu koji proporcionalno odgovara mestu na kom smo napravili izmenu u ulaznoj niski), dok se potpis drastično menja pri svakoj (pa i najmanjoj) promeni sadržaja.

Upravo tako i treba da bude (i to jeste razlika između enkodiranja i haširanja), a za kraj ostaje da prikažemo kako postupak autorizacije funkcioniše u praksi.

Kao što smo već najavili, ovoga puta bavimo se samo opštim principima (prava implementacija će ostati za neku drugu priliku).

Postupak autorizacije korisnika preko JWT-a

Budući da se šifra za enkripciju potpisa čuva na serveru * i budući da se korisnicima (posle uspešne autentifikacije) šalje 'potpis' koji nastaje korišćenjem šifre, pri utvrđivanju autentičnosti zahteva (koji klijent kasnije šalje serveru), dovoljno je proveriti samo token koji server prima zajedno sa zahtevom.

Sadržaj tokena (koji, između ostalog, čine podaci za autorizaciju i potpis), jeste moguće izmeniti, ali, bez odgovarajuće 'tajne šifre' (ili ključeva) sa servera, praktično je nemoguće napraviti potpis koji odgovara zaglavlju i podacima za autorizaciju.

* Za enkripciju se nikako ne koriste korisničke lozinke, i (naravno), šifre za enkripciju se ne šalju klijentskim browserima!

Kada browser pošalje serveru token (pri slanju zahteva za pristup korisničkoj stranici, slanju chat poruke i sl), server obavlja sledeće radnje:

  • prima token
  • čita zaglavlje i sadržaj
  • proverava potpis (shodno primljenom zaglavlju i sadržaju)

Ukoliko je potpis korektan - korisniku se dozvoljava pristup sadržajima, a ukoliko potpis nije korektan - korisnik gubi privilegije za pristup.

Pogledajmo i primere ....

Primeri korišćenja JSON Web Tokena

Uz nekoliko slika (jer "slika vredi ~1024 reči" u programerskim diskusijama), lakše ćemo sagledati kako sistem zaštite funkcioniše u praksi ....

Uspešna autentifikacija

Kada korisnik prosledi korektne podatke za prijavu ....

JWT 03
Slika 8. - Slanje podataka za prijavu (ovoga puta, podaci su odgovarajući).

.... na serveru se kreira token koji sadrži zaglavlje, podatke i potpis ....

JWT 03
Slika 9. - Uspešno obavljena autentifikacija (u sledećem koraku, kreira se token za autorizaciju, koji će biti poslat korisniku).

.... i potom se token šalje klijentu:

JWT 05
Slika 10. - Slanje tokena korisniku i pristup aplikaciji.

Po prijemu tokena, klijent dobija pristup aplikaciji.

Neuspešna autentifikacija

Ako korisnik ne prosledi odgovarajuće podatke za prijavu ....

JWT 01
Slika 11. - Pokušaj slanja neodgovarajućih podataka za autentifikaciju korisnika.

.... token neće ni biti kreiran (i samim tim neće biti izdat)!

JWT 02
Slika 12. - Odgovor servera na pokušaj prijave uz neodgovarajuću lozinku.

Za ovakve situacije se mogu implementirati rešenja koja dozvoljavaju samo određen broj pokušaja (pristupa), pre nego što se formular za pristup privremeno blokira (na primer, 15 minuta pauze posle 5. neuspešnog pokušaja i sl), a može se koristiti i "captcha" * ili neki sličan mehanizam.

* CAPTCHA je skraćenica za "Completely Automated Public Turing test to Tell Computers and Humans Apart" (verujemo da ste viđali formulare koji zahtevaju da korisnik unese pojam koji je na priloženoj slici ispisan 'vijugavim slovima', ili, formulare koji zahtevaju da korisnik označi "sve kvadratiće sa semaforima/hidrantima/autobusima", i sl).

Uspešna autorizacija

U sledećoj situaciji, korisnik pred sobom već ima otvorenu aplikaciju (sa sadržajima koji odgovaraju korisničkom nalogu), i potrebno je, pri slanju novog zahteva, utvrditi da li korisnik (i dalje) ima privilegije za pristup sadržajima na serveru.

Ako za primer uzmemo slanje poruke u chat aplikaciji, provera funkcioniše na sledeći način:

  • klijent se obraća serveru sa zahtevom za obradu podataka
  • ukoliko zahtev bude prihvaćen, poslata poruka će biti dodata u bazu podataka i prikazana sa ostalim porukama
  • ako zahtev bude odbijen, sistem neće uneti novu poruku u bazu * (pri čemu će klijent, koji je poruku poslao, dobiti povratnu poruku o grešci)
  • uz zahtev se prosleđuje i JSON web token.

Prosleđeni token se proverava po pravilima sa kojima smo se ranije upoznali ('da li potpis koji je poslat uz token odgovara sadržaju') ....

JWT 06
Slika 13. - Pokušaj autorizacije uz slanje korektnog tokena.

.... i pošto u ovom slučaju provera daje korektan rezultat ....

JWT 07
Slika 14. - Uspešno obavljena provera poslatog tokena.

.... zahtev (tj. poruka) je prihvaćen(a):

JWT 08
Slika 15. - Posle uspešne provere tokena, poruka se prihvata (tj. uvodi se u bazu podataka na serveru). Pri prvom sledećem ažuriranju sadržaja, aplikacija na strani klijenta će prikazati novu poruku.

U sledećem ciklusu ažuriranja prikaza u chat aplikaciji, nova poruka (zajedno sa prethodnim porukama), biće prikazana svim klijentima koji imaju privilegije za prikaz poruka.

Sadržaj web tokena figurativno se naziva "tvrdnja" (eng. claim), u smislu: "klijent koji je poslao zahtev preko HTTP protokola (i sa zahtevom JWT), 'tvrdi' (npr), da ima korisničke privilegije koje obuhvataju pristup svim javnim delovima sajta i objavljivanje poruka".

Preko potpisa, proverava se da li je tvrdnja tačna (ili nije).

* U određenim sistemima, ako se prepozna obrazac posebno nedoličnog ponašanja (višestruki prekršaji korisnika koji šalje poruku i sl), preduzimaju se i dodatni koraci (umanjivanje nivoa privilegija, privremena ili trajna zabrana pristupa uz dodavanje korisničkog imena u "crnu knjigu" i sl).

Neuspešna autorizacija

Ako neko pokuša da "prošvercuje" token sa izmenjenim sadržajem (recimo, običan korisnik pokušava da se predstavi kao administrator) ....

JWT 09
Slika 16. - Pokušaj autorizacije preko 'hakovanog' tokena.

.... sadržaj tokena će sam po sebi "delovati" dobro, ali, pošto poslati potpis nije odgovarajući ....

JWT 10
Slika 17. - Proverom tokena, utvrđeno je da potpis ne odgovara sadržaju.

.... provera neće vratiti korektan rezultat.

Token se stoga ne prihvata .... samim tim ni poruka neće biti prihvaćena (!) ....

JWT 11
Slika 18. - Usled neuspešne autorizacije - zahtev za slanje poruke je odbijen.

.... i pri tom će korisnik koji je pokušao da prosledi poruku (uz nevažeći token), biti obavešten o tome da je došlo do greške.

Ostali korisnici, naravno, neće bez potrebe videti poruku upozorenja.

Kratak rezime ....

Korišćenje JSON Web Tokena uglavnom predstavlja sasvim pouzdan sistem za autorizaciju (koji je takođe i veoma popularan u poslednjih desetak godina, otkako se pojavio), ali, JSON tokeni nisu "svemogući i nepogrešivi".

U svemu što smo pisali do sada, podrazumevalo se da server "veruje" tokenu, međutim (kao što smo takođe naveli), tokeni mogu biti i kompromitovani (ne mogu se "obijati" tek tako, ali, ni izdaleka nije nemoguće), i stoga ćemo temi sigurnosti tokena, temama koje su vezane za enkodiranje i enkripciju, kao i ostalim temama koje se tiču autorizacije - uskoro posvetiti više pažnje ....

Autor članka Nikola Vukićević Za web portal codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna > Članci > JSON Web Token (JWT) - Struktura i primena u oblasti autorizacije web aplikacija
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt