💻SQL Injection
Giriş
Kibertəhlükəsizlik müxtəlif subyektləri əhatə edən geniş bir mövzudur, ancaq bu subyektlərdən çox azı databazalar qədər geniş yayılıb. İstəyirsiniz, bir veb tətbiqi qoruyun, SOC komandasında çalışın və SIEM istifadə edin, istifadəçi kimlik doğrulaması/müraciət kontrolunu konfiqurasiya edin və ya zərərli yazılım təhlili/təhdid aşkarlama alətləri istifadə edin, hər bir halda databazalara ehtiyacınız olacaq.
Data nədir?
Texniki olaraq bir data istənilən bir databazada saxlana bilər, bir çoxu da müəyyən data növləri və ya strukturları üçün dizayn edilib. Fərqli data növləri və istifadə halları, fərqli databaza funksiyalarını tələb edir.
Databaza nədir?
Databazalar, asanlıqla müraciət, emal və ya təhlil edilə bilən konfiqurasiya edilmiş məlumat və ya datalardan təşkil olunmuş bir kolleksiyadır. Və yaxud başqa bir tərif. Databazalar, müəyyən bir istifadəçi və ya başqa bir subyektə aid məlumatları strukturlaşdırılmış və təşkil olunmuş şəkildə saxlayan datalardan ibarət bir kolleksiyadır.
Bu datalar fərqli formatlarda ola bilər, məsələn bir tətbiq və ya bir sayta giriş edərkən saxlanılan və yoxlanılan istifadəçi kimlik doğrulama dataları (istifadəçi adı və parol və s.), istifadəçinin sayt üzrə fəaliyyət dataları (göndəriş, rəy, bəyənmə) və s.
Databazalar sadəcə böyük miqyaslı şirkətlərdə deyil, həm də kiçik miqyaslı şirkətlərdə də istifadə olunur. Bir neçə databaza növü mövcuddur. Ancaq bizim üçün önəmlisi relational və non-relational databazalardır.
Relational databazalar: Strukturlaşdırılmış dataları saxlayır, yəni bu növ databazaya daxil edilən datalar bir strukturu izləyir. Məsələn, bir istifadəçi haqqında yığılan datalar ad, soyad, e-poçt, istifadəçi adı və paroldan ibarətdir. Yeni bir istifadəçi qeydiyyatdan keçdikdə, datalar bu strukturu izləyərək databazaya daxil edirik. Bu datalar, bir cədvəldəki sətir və sütunlarda saxlanılır. Bu databazalardakı fərqli cədvəllər arasında əlaqə qurula bildiyi üçün relational (əlaqəli) termini istifadə olunur.
Non-relational databazalar: Dataları yuxarıdakı kimi saxlamaq əvəzinə cədvəl olmayan bir formatda saxlayır. Məsələn, müxtəlif növdə və miqdarda data ehtiva edən sənədlər skan edilərkən əhəmiyyətlidir. Məsələn:
{
_id: ObjectId("4556712cd2b2397ce1b47661"),
name: { first: "Thomas", last: "Anderson" },
date_of_birth: new Date('Sep 2, 1964'),
occupation: [ "The One"],
steps_taken : NumberLong(4738947387743977493)
}
Hansı növ databazaların istifadə edilməsi, konteksdən asılıdır. Relational databazalar, dataları daha istifadəçi ilə bağlı authentifikasiya məlumatlarını saxlayarkən, non-relational databazalar isə böyük miqdarda dataları saxlamaq və bu dataları daha tez sorğulamaq lazım gəldikdə istifadə olunur.
SQL injeksiya nədir
SQL, bir databazada saxlanılmış məlumatları soğrulamaq və dəyişdirmək üçün istifadə edilən bir proqramlaşdırma dilidir. SQL injeksiyası, hücum edənin bir SQL ifadəsinə zərərli input-u daxil edərək bir tətbiqin databazasında ixtiyari SQL əmrlərini icra etdiyi hücumdur. Bu, SQL sorğularında istifadə edilən input-ların yanlış filtrlənməsi və escape olması halında meydana gəlir, autentifikasiyanı (kimlik doğrulamanı) bypass etməyə, həssas dataların sızmasına, databazaya müdaxiləyə və bəzi hallarda RCE-yə (Remote Code Execution - Uzaqdan kodları icra etmə) səbəb olur.
Əksər veb framework-lər buna qarşı qoruma təmin edən daxili mexanizmlərə sahib olduğu üçün SQL injeksiyaları getdikcə azalır. Ancaq, yenə də geniş yayılıb.
Mövzumuz, iki növ SQL injeksiyasının necə tapılması və bundan necə faydalanmaqla bağlıdır: klassik SQL injeksiyası və blind SQL injeksiyası. Əlavə olaraq SQL sorğu dilini istifadə etməyən NoSQL databazalarındakı injeksiyalardan da danışacağıq.
Mexanizmlər
SQL injeksiyalarını anlamaq üçün SQL-in nə olduğunu bilməliyik. SQL (Structured Query Language - Strukturlaşdırılmış Sorğulama Dili), databazaları idarə etmək və onlarla ünsiyyət qurmaq üçün istifadə edilən bir dildir.
Ənənəvi olaraq, bir databazada cədvəllər, sütunlar, sətirlər və xanalar olur. Sətir və sütunlar, xanalarda saxlanılmış dataları ehtiva edir. Deyək ki, bir veb tətbiqin databazasında Users adlı cədvəl var.
1
admin
t5dJ12rp$fMDEbSWz
2
vickie
password123
3
jennifer
letmein!
Bu cədvəldə 3 sütun mövcuddur. Hər biri istifadəçi adları ilə bağlı fərqli dataları ehtiva edir. SQL dili, soğruları istifadə edərək databazada saxlanılmış datalarla əlaqə qurmağınıza kömək edir. Məsələn, SQL SELECT
ifadəsi databazadan data almaq üçün istifadə olunur. Aşağıdakı sorğu, databazadakı Users cədvəlini qaytaracaq:
SELECT * FROM Users;
Əgər, bu cədvəldəki Username sütununun datalarını görmək istəyiriksə:
SELECT Username FROM Users;
Əgər, Username sütununda admin adı olan dataları görmək istəyiriksə:
SELECT * FROM Users WHERE Username='admin';
SQL ifadələrinə kod injeksiya etmə
SQL injeksiya hücumu, bir haker, hədəf veb tətbiqinin databazasına müraciət etmək üçün istifadə etdiyi SQL ifadələrinə kod injeksiya edərək istədiyi SQL kodunu icra edə bildikdə meydana gəlir. Deyək ki, bir veb tətbiqə giriş etmək istəyirsiniz. Bu veb tətbiq sizə istək göndərərək istifadəçi adınızı və parolunuzu daxil etməyinizi istəyir. Veb tətbiq, istifadəçinin öz hesabına daxil olması üçün bu dataları SQL sorğusuna daxil edir. İstifadəçidən gələn POST request parametrləri SQL sorğusunu doldurmaq üçün istifadə olunur:
POST /login
Host: example.com
(POST request body)
username=vickie&password=password123
Daha sonra, POST request-ində qeyd olunan istifadəçi adı və parolla uyuşan istifadəçinin kimliyini tapmaq üçün databazaya SQL sorğusu göndərilir:
SELECT Id FROM Users
WHERE Username='vickie' AND Password='password123';
Yaxşı, deyə bilərsiniz ki, buradakı problem nədir? İstifadəçilər, başqalarının parollarını təxmin edə bilmədiyinə görə, onların hesablarına giriş edə bilməzlər. Ancaq problem odur ki, hakerlər SQL dilinə xas olan xüsusi simvolları daxil edərək sorğunun məntiqini qarışdıra bilər. Məsələn, bir haker aşağıdakı kimi POST request-i göndərsə:
POST /login
Host: example.com
(POST request body)
username="admin';-- "&password=password123
Databazaya göndərilməsi üçün yaradılmış SQL sorğusu belə olacaq:
SELECT Id FROM Users
WHERE Username='admin';-- ' AND Password='password123';
Buradakı --
sequence-i SQL sorğusunda özündən sonra gələn ifadələri rəyə (commentary) çevirir. Beləliklə haker, --
istifadə etməklə SQL sorğusunun qalan hissəsinin kod olaraq yox, rəy olaraq oxunulmasını təmin edir. Daha doğrusu sorğu, bu hala gəlir:
SELECT Id FROM Users WHERE Username='admin';
Parola nə yazırıqsa yazaq, fərqi yoxdur, sorğunun nəticəsi bizə, admin istifadəçisinin Id-sini qaytaracaq. Nəticə etibarilə, haker, SQL sorğusuna xüsusi simvollar daxil edərək, kimlik doğrulama mərhələsini bypass edə və doğru parolu bilmədən də sistemə admin olaraq giriş edə bilər.
Haker, SQL injeksiyası ilə "kimlik doğrulamanı bypass etmək"dən də əlavə çox şey edə bilər. Pisniyyətli şəxslər, müraciət edilməsinə icazə verilməyən həssas dataları əldə edə bilər. Deyək ki, bir veb sayt, istifadəçilərə, öz kimliklərini sübut etmələri üçün serverə istifadəçi adı və access key təqdim edərək e-poçtlarının siyahısına baxmağa imkan verir.
GET /emails?username=vickie&accesskey=ZB6w0YLjzvAVmp6zvr
Host: example.com
Bu GET request-i databazaya sorğu göndərmək üçün aşağıdakı SQL ifadəsini yaradacaq:
SELECT Title, Body FROM Emails
WHERE Username='vickie' AND AccessKey='ZB6w0YLjzvAVmp6zvr';
Bu halda, hakerlər, oxunmasına icazə verilməyən digər cədvəllərdəki dataları oxumaq üçün SQL sorğusunu istifadə edə bilərlər. Məsələn, serverə aşağıdakı HTTP request-ini göndərdiklərini düşünün:
GET /emails?username=vickie&accesskey="ZB6w0YLjzvAVmp6zvr'
UNION SELECT Username, Password FROM Users;-- "
Host: example.com
Server, orijinal SQL sorğusunu buna çevirəcək:
SELECT Title, Body FROM Emails
WHERE Username='vickie' AND AccessKey='ZB6w0YLjzvAVmp6zvr'
UNION SELECT Username, Password FROM Users;-- ;
2-ci SQL UNION operatoru, iki fərqli SELECT ifadəsinin nəticələrini birləşdirir. 1-ci SELECT, istifadəçilərin e-poçtlarını qaytarır, 3-cü SELECT isə Users cədvəlindəki bütün istifadəçi adı və parolları qaytarır. Beləliklə bu son sorğu, 1-ci və 3-cü SELECT ifadələrinin nəticələrini birləşdirir. Artıq haker, HTTP request-indəki bütün istifadəçilərin adlarını və parolları oxuya bilir!
SQL injeksiyaları, yalnız SELECT ifadəsi ilə məhdudlaşmır. Hakerlər, UPDATE, DELETE və INSERT kimi ifadələrə də kod injeksiya edə bilər. Deyək ki, qarşımızda istifadəçinin hədəf saytdakı parolunu güncəlləməsi üçün istifadə edilən POST request-i var:
POST /change_password
Host: example.com
(POST request body)
new_password=password12345
Veb sayt, giriş etdiyiniz istifadəçinin kimliyini yeni parolla birlikdə UPDATE sorğusunda göndərəcək. Bu sorğu, Users cədvəlində ID xanasında 2 olan sətri güncəlləyərək parolunu "password12345" olaraq təyin edəcək:
UPDATE Users
SET Password='password12345'
WHERE Id = 2;
Hakerlər, aşağıdakı kimi sorğu yarada bilər:
UPDATE Users
SET Password='password12345';-- WHERE Id = 2;
Güncəllənməli olan sətirlərin kriteriyalarını müəyyən edən WHERE ifadəsi burada rəy sətrinə çevrilib. Bununla da, databazadakı bütün sətirlər güncəllənir və Users cədvəlindəki bütün parollar "password12345" olaraq təyin edilir. Və haker, bu parolla istənilən istifadəçinin hesabına daxil ola bilər.
Second-order SQL injeksiyalarını istifadə etmə
İndiyə qədər baxdığımız SQL injeksiyalarının hamısı, birinci dərəcəli idi. Birinci dərəcəli SQL injeksiyaları, tətbiqlər, istifadəçilər tərəfindən göndərilmiş input-u birbaşa SQL sorğusunda istifadə etdikdə yananır. Digər tərəfdən, ikinci dərəcəli SQL injeksiyası, istifadəçi input-unun databazada saxlanması, daha sonra geri alınması və bir SQL sorğusunda güvənli olmayan şəkildə istifadə edilməsi halında meydana gəlir. Tətbiqlər, istifadəçi tərəfindən göndərilən input-ları düzgün emal etsə belə, tətbiq, databazadan alınmış datanı səhvən güvənli hesab etsə, təhlükəsizlik boşluğu meydana gəlir. Məsələn, istifadəçilərin istifadəçi adı və parol ilə qeydiyyatdan keçməsini təmin edən bir veb tətbiq düşünün. Pisniyyətli şəxs, aşağıdakı kimi bir request göndərir:
POST /signup
Host: example.com
(POST request body)
username="vickie' UNION SELECT Username, Password FROM Users;--
"&password=password123
Bu sorğuda, vickie'
istifadəçi adı UNION SELECT Username, Password FROM Users;--
ünvanına, password123
parolu isə /signup endpoint-ə göndərilir. İstifadəçi adı xanasına yazılmış SQL injeksiyası sayəsində, pisniyyətli şəxs, databazadakı bütün istifadəçi adlarını və parollarını seçib (SELECT) sorğunun nəticələri ilə birləşdirir. Ancaq tətbiq, bu cür zərərli input-ları əngəlləmək üçün bəzi qoruma texnikaları istifadə edir. Və vickie' UNION SELECT Username, Password FROM Users;--
ifadəsi pisniyyətli şəxsin istifadəçi adı kimi tətbiqin databazasında saxlanılır.
Daha sonra, pisniyyətli şəxs, aşağıdakı GET request-i ilə istifadəçilərin e-poçtlarına müraciət edir:
GET /emails
Host: example.com
Fərz edək ki, bu halda istifadəçi, istifadəçi adı və access key təqdim etməyib. Beləliklə tətbiq, həmin an giriş etmiş şəxsin istifadəçi adını databazadan alır və bunu SQL sorğusunu doldurmaq üçün istifadə edir:
SELECT Title, Body FROM Emails
WHERE Username='USERNAME'
Hakerin SQL kodunu ehtiva edən istifadəçi adı, SQL sorğusunu belə dəyişdirir:
SELECT Title, Body FROM Emails
WHERE Username='vickie'
UNION SELECT Username, Password FROM Users;--
Bu da, bütün istifadəçi adlarını və parollarını, HTTP response-unda e-poçt title və body olaraq qaytaracaq!
Qarşısını alma
SQL injeksiyaları, bir tətbiqin təhlükəsizliyi üçün dağıdıcı qüvvəyə malik olduğuna görə, bunların qarşısını almaq üçün vaxtında hərəkətə keçməlisiniz. SQL injeksiyalarını önləməyin bir yolu "prepared statement" istifadəsidir. Prepared statement, həm də parameterized queries kimi tanınır və SQL injeksiyalarını demək olar ki, qeyri-mümkün edir.
Prepared statement-in necə işlədiyinə baxmazdan əvvəl, SQL sorğularının necə icra olduğunu anlamaq vacibdir. SQL, bir proqramlaşdırma dilidir və SQL sorğunuz əsasən bir proqram sayılır. SQL proqramınız, SQL serverə çatdıqda, server bunun üzərində parsing (kodun təhlil edilməsi), compling (kodun maşın dilinə çevrilərək prosessor tərəfindən icra edilə bilən bir hala gətirilməsi) və optimizing (daha effektiv icra olunması üçün kodda təkmilləşdirmələr edilməsi) proseslərini icra edir. Sonda, server proqramı icra edir və icranın nəticəsini qaytarır.

Ancaq, SQL sorğularınıza istifadəçi input-larını daxil etsəniz, təməl olaraq istifadəçi input-u ilə proqramınızı yenidən yazırsınız. Pisniyyətli şəxslər də, input olaraq proqramın koduna müdaxilə edən, onun məntiqini dəyişdirən datalar daxil edə bilər.

Bir SQL sorğusu, sorğu ilə istifadəçi input-unu compile prosesindən əvvəl birləşdirdikdə, databazanın "istifadəçi input"unu kod olaraq qəbul etməsinə səbəb olur.
Prepared statement imkan vermir ki, istifadəçi tərəfindən yazılan input-lar, SQL sorğunuzun məntiqini dəyişdirsin. Bu SQL ifadələri, istifadəçinin yazdığı parametrlər daxil edilməzdən əvvəl SQL serverinə göndərilir və serverin compile prosesindən keçir. Bu o deməkdir ki, tam SQL sorğusunu compile olunması üçün serverə ötürməzdən əvvəl, bütün "SQL logic"ni müəyyən edirsiniz, compile edirsiniz və icra olunmazdan əvvəl istifadəçi parametrlərini sorğuya daxil edirsiniz.

Bir SQL sorğusu, soğru ilə istifadəçi input-unu compile prosesindən sonra birləşdirdikdə, databazanın SQL sorğusundakı kod və data hissələrini ayırmasına imkan verir.
Orijinal ifadədə olmayan hər şey, icra oluna bilən SQL kodu olaraq yox, string datası olaraq emal olunacaq. Bu imkan verir ki, databaza, input-a nə yazılmasından asılı olmayaraq SQL sorğusunun kod və data hissələrini ayırsın.
Last updated