JWT (Json Web Token)

JWT nədir?

JSON Web Token (JWT) iki tərəf arasında məlumatı təhlükəsiz şəkildə təmsil etmək üçün yığcam və müstəqil bir üsuldur. O, adətən veb inkişafında autentifikasiya və məlumat mübadiləsi üçün istifadə olunur. JWT üç hissədən ibarətdir: başlıq, payload və imza. Başlıq adətən işarənin növünü və imzalama alqoritmini təyin edir, paylaod isə iddiaları və ya məlumatları əhatə edir. Bu hissələr JWT yaratmaq üçün base64 kodlu və birləşdirilir. İmza, tokenin bütövlüyünü yoxlamaq üçün bir yol təqdim edən secret açardan istifadə edərək yaradılır. JWT-lər tez-tez autentifikasiya proseslərində istifadə olunur, burada istifadəçi uğurlu girişdən sonra nişan alır və istifadəçinin şəxsiyyətini və icazələrini təmin etmək üçün bu işarədən istifadə edərək sonrakı sorğular təsdiqlənə bilər.

JWT-nin formatı

JSON Veb Tokeni aşağıdakı kimi nöqtələrlə ayrılmış base64url kodlaşdırmasında başlıq, payload və imzadan ibarətdir:

HEADER.PAYLOAD.SIGNATURE

Aşağıdakı həqiqi nişanı ayıraq:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJuYW1lIjoiSm9obiBEb2UiLCJ1c2VyX25hbWUiOiJqb2huLmRvZSIsImlzX2FkbWluIjpmYWxzZX0.
fSppjHFaqlNcpK1Q8VudRD84YIuhqFfA67XkLam0_aY

Başlıqda imza üçün istifadə olunan alqoritm və işarənin növü (sadəcə JWT) kimi nişan haqqında metadata var. Bu misal üçün kodlaşdırmadan əvvəl başlıq belədir:

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

Payload-da proqram tərəfindən yoxlanılacaq qurum (user) haqqında məlumat (claims) var. Nümunə nişanımıza aşağıdakı claim-lər daxildir:

{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": false
}

Nəhayət, imza yaratmaq üçün başlığa, nöqtəyə və payload-a base64url kodlamasını tətbiq etməli və sonra alqoritmdən asılı olaraq secret (simmetrik şifrələmə üçün) və ya private key (asimmetrik şifrələmə üçün) istifadə edərək hər şeyi imzalamalıyıq. HS256-nı simmetrik bir alqoritm olan başlığa yerləşdirdik, buna görə də kodlaşdırma və imzalama əməliyyatı belə olur:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

Bu, bizə aşağıdakı imzanı verir, daha sonra base64url ilə kodlanmış başlığa və payload-a əlavə olunur (nöqtədən sonra):

fSppjHFaqlNcpK1Q8VudRD84YIuhqFfA67XkLam0_aY

Ümumi JWT zəiflikləri

JSON Veb Tokenləri çevik və gələcəyə davamlı olmaq üçün nəzərdə tutulmuşdur, müxtəlif istifadə hallarına və tələblərinə uyğunlaşmaq üçün çoxlu yer, həm də tətbiq və istifadədə səhvlər üçün çox yer buraxmışdır. JWT-lərlə işləyərkən təqdim edilə bilən bəzi tipik zəifliklər bunlardır.

İmzanı yoxlamaqla bağlı xətalar

Bir çox JWT kitabxanaları nişanı deşifrə etmək üçün bir üsul, onu yoxlamaq üçün isə digər üsul təqdim edir:

  • decode(): İmzanı yoxlamadan yalnız base64url kodlaşdırmasından nişanı deşifrə edir.

  • verify(): Tokenin kodunu açır və imzanı yoxlayır.

Bəzən tərtibatçılar bu üsulları qarışdıra bilərlər. Bu halda, imza heç vaxt yoxlanılmır və proqram hər hansı işarəni (etibarlı formatda) qəbul edəcək. Tərtibatçılar sınaq üçün imza doğrulamasını deaktiv edə və sonra onu yenidən aktivləşdirməyi unuda bilərlər. Bu cür səhvlər hesaba ixtiyari girişə və ya imtiyazların artmasına səbəb ola bilər.

Məsələn, tutaq ki, heç vaxt təsdiqlənməmiş aşağıdakı etibarlı işarəmiz var:

{
  "alg": "HS256",
  "typ": "JWT"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": false
}

Təcavüzkar üst səviyyə imtiyazları əldə etmək üçün ixtiyari imza ilə aşağıdakı işarəni göndərə bilər:

{
  "alg": "HS256",
  "typ": "JWT"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": true
}

None alqoritminə icazə verilərsə

JWT standartı imza yaratmaq üçün bir çox müxtəlif növ alqoritmləri qəbul edir:

  • RSA

  • HMAC

  • Elliptic Curve

  • None

None alqoritmi işarənin imzalanmadığını müəyyən edir. Bu alqoritmə icazə verilirsə, mövcud alqoritmi None-a dəyişdirərək və imzanı silməklə imza yoxlamasını bypass edə bilərik. Gözlənilən nişanımızla başlayaq:

{
  "alg": "HS256",
  "typ": "JWT" 
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": false
}.SIGNATURE

Şifrələnmiş və imzalanmış nişan bu kimi görünəcək (qalın hərflərlə imza):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJuYW1lIjoiSm9obiBEb2UiLCJ1c2VyX25hbWUiOiJqb2huLmRvZSIsImlzX2FkbWluIjpmYWxzZX0.
fSppjHFaqlNcpK1Q8VudRD84YIuhqFfA67XkLam0_aY

Əgər alqoritm dəyəri kimi None icazə verilmirsə, təcavüzkar ondan sadəcə olaraq etibarlı alqoritmi əvəz etmək üçün istifadə edə və sonra imzadan qurtula bilər:

{
  "alg": "None",
  "typ": "JWT"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": true
}.

İndi imzalanmamış olsa da, dəyişdirilmiş nişan tətbiq tərəfindən qəbul ediləcək:

eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.
eyJuYW1lIjoiSm9obiBEb2UiLCJ1c2VyX25hbWUiOiJqb2huLmRvZSIsImlzX2FkbWluIjp0cnVlfQ.

Buna görə də alg başlığında None, none, NONE, nOnE və ya hər hansı digər hal dəyişikliyi ilə tokenləri qəbul etməmək vacibdir.

Algorithm qarışıqlılığı

JWT həm simmetrik, həm də asimmetrik şifrələmə alqoritmlərini qəbul edir. Şifrələmə növündən asılı olaraq, ya paylaşılan secret, ya da public-private açar cütündən istifadə etməlisiniz:

Tətbiq asimmetrik şifrələmədən istifadə etdikdə, o, açıq açarını açıq şəkildə dərc edə və private key-i gizli saxlaya bilər. Bu, proqrama private key-dən istifadə edərək nişanları imzalamağa imkan verir və hər kəs public-key istifadə edərək bu nişanı yoxlaya bilər. Alqoritm çaşqınlığı zəifliyi, proqram qəbul edilmiş işarənin alqoritminin gözlənilən alqoritmə uyğun olub-olmadığını yoxlamadıqda yaranır.

Bir çox JWT kitabxanasında imzanı yoxlamaq üçün üsul belədir:

  • verify(token, secret) – nişan HMAC ilə imzalanıbsa

  • verify(token, publicKey) – nişan RSA və ya oxşarı ilə imzalanıbsa

Təəssüf ki, bəzi kitabxanalarda bu üsul öz-özünə qəbul edilmiş işarənin tətbiqin gözlənilən alqoritmi ilə imzalanıb-imzalanmadığını yoxlamır. Buna görə HMAC vəziyyətində bu üsul ikinci arqumenti paylaşılan secret, RSA vəziyyətində isə public-key kimi nəzərdən keçirəcəkdir.

Əgər public-key tətbiq daxilində əlçatandırsa, təcavüzkar zərərli nişanları saxtalaşdıra bilər:

  1. Tokenin alqoritminin HMAC-ə dəyişdirilməsi

  2. İstədiyiniz nəticəni əldə etmək üçün faydalı yükə müdaxilə

  3. Tətbiqdə tapılan açıq açarla zərərli nişanın imzalanması

  4. JWT-nin tətbiqə geri göndərilməsi

Tətbiq RSA şifrələməsini gözləyir, ona görə də təcavüzkar əvəzinə HMAC təmin etdikdə, verify() metodu public-key-i HMAC-nin paylaşılan secret kimi qəbul edəcək və asimmetrik şifrələmədən daha çox simmetrik istifadə edəcək. Bu o deməkdir ki, nişan tətbiqin gizli olmayan public key ilə imzalanacaq və sonra eyni public key-dən istifadə edilərək yoxlanılacaq.

Bu zəifliyin qarşısını almaq üçün proqramlar tokeni verify() metoduna ötürməzdən əvvəl qəbul edilmiş tokenin alqoritminin gözlənilən alqoritm olub-olmadığını yoxlamalıdır.

Önəmsiz secret-lərdən istifadə etmək

Simmetrik şifrələmə ilə kriptoqrafik imza yalnız istifadə edilən secret qədər güclüdür. Tətbiq zəif bir secret istifadə edərsə, təcavüzkar orijinal imza saxta imzaya uyğun gələnə qədər müxtəlif gizli dəyərləri sınayaraq onu sadəcə olaraq brute force edə bilər. Secret-i aşkar etdikdən sonra təcavüzkar ondan zərərli nişanlar üçün etibarlı imzalar yaratmaq üçün istifadə edə bilər. Bu zəifliyin qarşısını almaq üçün güclü secret-lər həmişə simmetrik şifrələmə ilə istifadə edilməlidir.

JSON Veb Tokenlərinə qarşı hücumlar

kid parametrlərinin enjeksiyonları

JWT başlığında Açar İd parametri kid ola bilər. Çox vaxt database-dən və ya fayl sistemindən açarı almaq üçün istifadə olunur. Ərizə kid parametri vasitəsilə əldə edilən açardan istifadə edərək imzanı yoxlayır. Parametr inyeksiya edilə biləndirsə, o, imza atmağa və ya hətta RCE, SQLi və LFI kimi hücumlara yol aça bilər.

Bunu hərəkətdə görmək üçün aşağıdakı etibarlı işarə ilə başlayaq:

{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "key1"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": false
}

Kid parametri əmr inyeksiyasına həssasdırsa, aşağıdakı modifikasiya kodun uzaqdan icrasına səbəb ola bilər:

{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "key1|/usr/bin/uname"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": false
}

kid parameter injection + directory traversal = signature bypass

Əgər proqram fayl sistemindən açarı əldə etmək üçün kid parametrindən istifadə edirsə, o, kataloq keçidinə qarşı həssas ola bilər. Bundan sonra təcavüzkar tətbiqi doğrulama üçün açar kimi dəyərini təxmin edə biləcəyi fayldan istifadə etməyə məcbur edə bilər. Bu, proqram daxilində istənilən statik fayldan istifadə etməklə edilə bilər. Açar fayl dəyərini bilən təcavüzkar zərərli nişan yarada və məlum açardan istifadə edərək onu imzalaya bilər.

Əvvəlki JWT nümunəsinə davam edərək, təcavüzkar tətbiqi boş açardan istifadə etməyə məcbur etmək üçün əsas mənbə kimi /dev/null daxil etməyə cəhd edə bilər:

{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "../../../../../../dev/null"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": true
}

If directory traversal to /dev/null succeeds, the attacker will be able to sign a malicious token using an empty string. The same technique can be used with known static files, for example CSS files.

kid parameter injection + SQL injection = signature bypass

Əgər proqram database-dən açarı əldə etmək üçün kid parametrindən istifadə edirsə, o, SQL inyeksiyasına qarşı həssas ola bilər. Müvəffəqiyyətli olarsa, təcavüzkar SQL sorğusundan kid parametrinə qaytarılan dəyəri idarə edə və onu zərərli nişanı imzalamaq üçün istifadə edə bilər.

Yenə eyni nümunə işarəsindən istifadə edərək, deyək ki, proqram kid parametri vasitəsilə JWT açarını əldə etmək üçün aşağıdakı həssas SQL sorğusundan istifadə edir:

SELECT key FROM keys WHERE key='key1'

Təcavüzkar daha sonra əsas dəyəri idarə etmək üçün kid parametrinə UNION SELECT ifadəsini yeridə bilər:

{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "xxxx' UNION SELECT 'aaa"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": true
}

SQL inyeksiyası uğurlu olarsa, proqram imza açarını əldə etmək üçün aşağıdakı sorğudan istifadə edəcək:

SELECT key FROM keys WHERE key='xxxx' UNION SELECT 'aaa'

Bu sorğu aaa-nı kid parametrinə qaytararaq, təcavüzkara sadəcə aaa ilə zərərli nişanı imzalamağa imkan verir.

Bu və digər inyeksiya hücumlarının qarşısını almaq üçün proqramlar həmişə kid parametrinin dəyərini istifadə etməzdən əvvəl təmizləməlidir.

Jku başlığından istifadə edərək hücumlar

JWT başlığında tərtibatçılar JSON Veb Açar Dəsti URL-ni təyin etmək üçün jku parametrindən də istifadə edə bilərlər. Bu parametr, tətbiqin imzanı yoxlamaq üçün istifadə edilən JSON Veb Açarını (JWK) harada tapa biləcəyini göstərir - əsasən JSON formatında açıq açar.

Nümunə etmək üçün public key-i təyin etmək üçün jku parametrindən istifadə edən aşağıdakı JWT-ni götürək:

{
  "alg": "RS256",
  "typ": "JWT",
  "jku":"https://example.com/key.json"
}.
{
  "name": "John Doe",
  "user_name": "john.doe",
  "is_admin": false
}

Göstərilən key.json faylı belə görünə bilər:

{
  "kty": "RSA",
  "n": "-4KIwb83vQMH0YrzE44HppWvyNYmyuznuZPKWFt3e0xmdi-WcgiQZ1TC...RMxYC9lr4ZDp-M0",
  "e": "AQAB"
}

Tətbiq jku başlıq dəyəri əsasında əldə edilmiş JSON Veb Açarından istifadə edərək imzanı yoxlayır:

İndi hücum üçün təcavüzkar jku parametrinin dəyərini dəyişdirərək etibarlı olan əvəzinə öz JWK-ni göstərə bilər. Qəbul edilərsə, bu, təcavüzkara öz private key-dən istifadə edərək zərərli nişanları imzalamağa imkan verir. Zərərli nişan göndərildikdən sonra proqram təcavüzkarın JWK-ni alacaq və imzanı yoxlamaq üçün ondan istifadə edəcək:

Bu cür hücumların qarşısını almaq üçün proqramlar adətən URL filtrindən istifadə edir. Təəssüf ki, təcavüzkarların bu cür filtrləmədən yan keçməsinin yolları var, o cümlədən:

  • Tətbiq etibarlı ilə başlayan URL-ləri yoxlayırsa, https://trusted istifadə edərək (məsələn, https://[email protected]/key.json)

  • DNS adlandırma iyerarxiyasından istifadə

  • Açıq yönləndirmə ilə zəncirləmə

  • Başlıq inyeksiyası ilə zəncirləmə

  • SSRF ilə zəncirləmə

Bu səbəbdən, tətbiqin icazə verilən hostları white-list-ə salması və düzgün URL filtrinin olması çox vacibdir. Bundan əlavə, tətbiqdə təcavüzkarın URL filtrini bypass etməsi üçün zəncirləyə biləcəyi digər zəifliklər olmamalıdır.

Nəticə

JSON Veb Tokenləri müasir veb tətbiqetmələrin inkişafında, xüsusən də tək giriş (SSO) həyata keçirərkən autentifikasiya proseslərinin mühüm hissəsinə çevrilir. JWT zəifliklərinin qarşısını almaq üçün tərtibatçılar ən yaxşı təcrübələrə əməl etməli və öz tətbiqlərini yaymaq əvəzinə etibarlı JWT kitabxanalarından istifadə etməlidirlər. Təcavüzkarların JWT hücumlarını digər zəifliklərlə zəncirləmə riskini minimuma endirmək üçün siz həmçinin zəif tərəfləri kibercinayətkarlar tərəfindən istismar edilməzdən əvvəl tapmaq üçün yüksək keyfiyyətli zəiflik skan həllindən istifadə etməlisiniz. Invicti kimi müasir DAST aləti minlərlə digər problemlə yanaşı JWT zəifliklərini də müəyyən edə bilər və onu istənilən proqram təhlükəsizliyi alətlər qutusunun mühüm hissəsinə çevirir.

Praktiki nümunə

Last updated