Məzmuna keçLogo

Command Palette

Search for a command to run...

Çərəzlər (Cookies) — Veb Tətbiqlərinin Əvəzolunmaz Yaddaşı

Dərc olundu
14 apr 2025
Çərəzlər (Cookies) — Veb Tətbiqlərinin Əvəzolunmaz Yaddaşı

Çərəzlər (Cookies): Veb Tətbiqlərinin Əvəzolunmaz Yaddaşı

Salamlar, Keçən dəfə HTTP-nin "vətəndaşlığı olmayan" (stateless) təbiətindən danışmışdıq. Bəs bu yaddaşsız protokolla necə olur ki, veb saytlar bizi "tanıyır", login statusumuzu saxlayır, alış-veriş səbətimiz boş qalmır? Cavab çox vaxt kiçik mətn fayllarında gizlənir: Cookies. Bu gün biz bu kiçik, amma qüdrətli köməkçilərin dərinliklərinə baş vuracağıq – necə yarandığından tutmuş, təhlükəsizlik risklərinə və müasir alternativlərinə qədər. Hazırsınızsa, cookie jar-ı açaq!

Bir cookie-nin həyatı serverin göndərdiyi HTTP response başlığı ilə başlayır: Set-Cookie. Brauzer bu başlığı gördükdə, içindəki direktivlərə əsasən cookie-ni yadda saxlayır və gələcək uyğun istəklərdə (Cookie başlığı ilə) serverə geri göndərir.

Tipik bir Set-Cookie başlığı belə görünə bilər:

responses/set-cookie.txt
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: sessionId=a3fWa; Expires=Wed, 21 Oct 2026 07:28:00 GMT; Path=/; Domain=.example.com; Secure; HttpOnly; SameSite=Lax // [!code highlight]

Gəlin bu direktivləri (parametrləri) detallı şəkildə analiz edək:

  • Name=Value: Cookie-nin əsas yükü. sessionId=a3fWa hissəsi cookie-nin adını (sessionId) və dəyərini (a3fWa) göstərir. Bu, serverin istifadəçini və ya onun vəziyyətini tanıması üçün istifadə etdiyi məlumatdır.
  • Expires=Date: Cookie-nin son istifadə tarixini göstərir. Bu tarixdən sonra brauzer cookie-ni avtomatik silir. Formatı spesifikdir (RFC 6265). Əgər Expires və Max-Age təyin edilməyibsə, bu bir session cookie olur və brauzer sessiyası (adətən brauzer pəncərəsi) bağlananda silinir.
  • Max-Age=Seconds: Cookie-nin neçə saniyə yaşayacağını göstərir. Expires-dən daha müasirdir və ona nəzərən üstünlüyə malikdir (əgər hər ikisi təyin edilibsə). Mənfi dəyər cookie-ni dərhal silir. Məsələn, Max-Age=3600 cookie-nin 1 saat yaşayacağını bildirir.
  • Domain=domain.name: Cookie-nin hansı domen(lər)ə göndəriləcəyini təyin edir. Əgər təyin edilməzsə, yalnız cookie-ni təyin edən serverin domen adı (originating host) üçün keçərli olur. . ilə başlayan dəyər (məs: .example.com) həm əsas domen, həm də onun bütün subdomain-ləri (məs: www.example.com, api.example.com) üçün keçərli olmasını təmin edir.
  • Path=path: Cookie-nin hansı URL path-ları üçün göndəriləcəyini məhdudlaşdırır. Əgər / təyin edilibsə, bütün path-lar üçün göndərilir. Əgər /app təyin edilibsə, yalnız /app və onun altındakı path-lar (/app/profile, /app/settings) üçün göndərilir.
  • 🛡️ Secure: Bu flag təyin edildikdə, brauzer cookie-ni yalnız HTTPS bağlantısı üzərindən göndərir. HTTP üzərindən göndərilməsinin qarşısını alaraq man-in-the-middle hücumlarında cookie-nin oğurlanma riskini azaldır. Mütləq istifadə olunmalıdır!
  • 🛡️ HttpOnly: Bu flag təyin edildikdə, cookie-yə JavaScript vasitəsilə (document.cookie API) müraciət etmək mümkün olmur. Bu, Cross-Site Scripting (XSS) hücumları nəticəsində session cookie-lərinin oğurlanmasının qarşısını almaq üçün ən vacib təhlükəsizlik tədbirlərindən biridir.
  • 🛡️ SameSite=Strict | Lax | None: Cross-Site Request Forgery (CSRF) hücumlarına qarşı müdafiəni gücləndirir. Cookie-nin cross-site (fərqli saytdan gələn) istəklərlə birlikdə göndərilib-göndərilməyəcəyini idarə edir:
    • Strict: Cookie yalnız eyni saytdan (same-site) gələn istəklərlə göndərilir. Başqa saytdakı linkə klikləyərək gəlsəniz belə, cookie göndərilmir. Ən təhlükəsizdir, amma bəzən istifadəçi təcrübəsini poza bilər.
    • Lax: Standart dəyər (əksər müasir brauzerlərdə). Cookie eyni saytdan gələn istəklərlə VƏ başqa saytdan gələn top-level navigation (GET istəyi, məsələn linkə klikləmə) ilə göndərilir. POST, PUT, DELETE kimi cross-site istəklərlə və ya <iframe>, <img> içindəki istəklərlə göndərilmir. CSRF-ə qarşı yaxşı balans təqdim edir.
    • None: Cookie bütün cross-site istəklərlə göndərilir. Ancaq bu dəyəri istifadə etmək üçün mütləq Secure atributu da təyin edilməlidir. Əsasən third-party kontekstlərdə (məsələn, embedded content) istifadə olunur.

Praktik İstifadə Sahələri: Oturum İdarəetməsi (Session Management) və İstifadəçi Təcrübəsi

Cookie-lərin ən fundamental rolu HTTP-nin yaddaşsızlığını aradan qaldırmaqdır:

  • Oturum İdarəetməsi (Session Management):
    • İstifadəçi login olduqda, server unikal bir session identifier (session ID) yaradır.
    • Bu session ID Set-Cookie başlığı ilə brauzerə göndərilir (adətən HttpOnlySecure flag-ləri ilə).
    • Brauzer bu cookie-ni saxlayır və eyni domenə edilən hər sonrakı istəkdə Cookie: sessionId=... başlığı ilə geri göndərir.
    • Server bu session ID-ni alır, ona uyğun session məlumatlarını (kimin login olduğu, səlahiyyətləri və s.) server tərəfdəki yaddaşdan (RAM, database, cache) tapır və istifadəçini "tanıyır".
    • Nəticə: İstifadəçi hər səhifəyə keçdikdə yenidən login olmaq məcburiyyətində qalmır. Bu, stateful təcrübənin əsasıdır.
  • İstifadəçi Təcrübəsi (User Experience) və Fərdiləşdirmə:
    • Tercihlərin Saxlanması: Saytın dili, theme (qaranlıq/işıqlı rejim), baxılmış məhsullar kimi istifadəçi seçimlərini yadda saxlamaq üçün istifadə edilə bilər.
    • Alış-veriş Səbəti (Shopping Cart): Login olmamış istifadəçilərin belə səbətlərini müvəqqəti olaraq cookie-lərdə saxlamaq mümkündür (baxmayaraq ki, daha mürəkkəb həllər adətən backend sessiyaları və ya localStorage istifadə edir).
    • İzləmə və Analitika (Tracking & Analytics): İstifadəçilərin saytdakı davranışlarını (hansı səhifələrə baxdıqları, nə qədər vaxt keçirdikləri) izləmək üçün istifadə olunur (məs: Google Analytics). Bu, xüsusilə third-party cookies vasitəsilə həyata keçirilir və məhz bu səbəbdən məxfilik narahatlıqları yaradır.

JavaScript ilə Çərəz Əməliyyatları (document.cookie)

Əgər bir cookie HttpOnly olaraq işarələnməyibsə, ona client-side JavaScript vasitəsilə müraciət etmək mümkündür:

JavaScript
client/document-cookie.js
// Bütün əlçatan cookie-ləri oxumaq (string formatında)
let allCookies = document.cookie;
console.log(allCookies); // Output: "pref=dark; lang=en; other=value" (misal)

// Yeni bir cookie yazmaq və ya mövcudu dəyişmək
// Diqqət: Bu əməliyyat digər cookie-ləri silmir, yalnız göstəriləni əlavə edir/dəyişir
document.cookie = "username=johndoe; expires=Fri, 25 Apr 2026 20:36:32 GMT; path=/; SameSite=Lax"; 

// Cookie silmək üçün Expires tarixini keçmişə təyin etmək
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"; 

// Max-Age ilə yazmaq
document.cookie = "theme=dark; max-age=86400; path=/"; // 86400 saniyə = 1 gün

⚠️ Diqqət! document.cookie API-si bir az yöndəmsizdir. Bütün cookie-ləri bir string kimi qaytarır və onları parse etmək lazımdır. Həmçinin, bir cookie-ni yeniləmək üçün bütün atributlarını yenidən təyin etmək lazımdır. Ən əsası isə, əgər saytınızda XSS zəifliyi varsa, HttpOnly olmayan bütün cookie-lər (o cümlədən JS ilə yazdıqlarınız) oğurlana bilər! Buna görə də həssas məlumatları (session ID, tokenlər) JS-dən əlçatmaz etmək üçün HttpOnly istifadə etmək kritikdir.

Backend tərəfdə (məsələn, Java Spring Boot ilə) cookie-lərlə işləmək daha nəzarətli və təhlükəsizdir.

  • Cookie Oxumaq:

    • @CookieValue Annotation: Ən asan yol. Spring avtomatik olaraq istənilən cookie-nin dəyərini metod parametrininə inject edir.
    controller/CookieController.java
    import org.springframework.web.bind.annotation.CookieValue;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class CookieController {
    
        @GetMapping("/read-session")
        public String readSessionCookie(@CookieValue(name = "sessionId", defaultValue = "guest") String sessionId) { 
            // sessionId dəyərini istifadə et...
            return "Session ID from cookie: " + sessionId;
        }
    }
    • HttpServletRequest: Bütün cookie-ləri array şəklində əldə etmək üçün.
    controller/CookieControllerReadAll.java
    import jakarta.servlet.http.Cookie;
    import jakarta.servlet.http.HttpServletRequest;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.Arrays;
    import java.util.Optional;
    
    @RestController
    public class CookieController {
    
        @GetMapping("/read-all")
        public String readAllCookies(HttpServletRequest request) {
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                Optional<Cookie> themeCookie = Arrays.stream(cookies)
                            .filter(cookie -> "theme".equals(cookie.getName()))
                            .findFirst();
    
                if (themeCookie.isPresent()) {
                    return "Theme: " + themeCookie.get().getValue();
                }
            }
            return "No theme cookie found.";
        }
    }
  • Cookie Yazmaq/Təyin Etmək:

    • HttpServletResponse.addCookie() (Ənənəvi): jakarta.servlet.http.Cookie obyekti yaradıb response-a əlavə etmək.
    controller/CookieControllerSetTheme.java
    import jakarta.servlet.http.Cookie;
    import jakarta.servlet.http.HttpServletResponse;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class CookieController {
    
        @GetMapping("/set-theme")
        public String setThemeCookie(HttpServletResponse response) {
            Cookie themeCookie = new Cookie("theme", "dark");
            themeCookie.setPath("/");
            themeCookie.setMaxAge(86400); // 1 gün
            themeCookie.setHttpOnly(true); 
            themeCookie.setSecure(true); // HTTPS tələb olunur!
            // themeCookie.setDomain(".example.com"); // Lazım gələrsə
            response.addCookie(themeCookie); 
            return "Theme cookie set to dark.";
        }
    }
    • ResponseCookie (Spring 5+ - Müasir): Daha axıcı (fluent) və müasir atributları (xüsusilə SameSite) asanlıqla təyin etməyə imkan verən builder interfeysi təqdim edir. HttpHeaders.SET_COOKIE başlığı ilə istifadə olunur.
    controller/CookieControllerModern.java
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.ResponseCookie;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.time.Duration;
    
    @RestController
    public class CookieController {
    
        @GetMapping("/set-session-modern")
        public ResponseEntity<String> setSessionCookieModern() {
            String sessionId = generateSecureSessionId(); // Təhlükəsiz ID yaratmaq lazımdır
    
            ResponseCookie sessionCookie = ResponseCookie.from("sessionId", sessionId)
                        .httpOnly(true) 
                        .secure(true) // Production üçün mütləq true olmalıdır
                        .path("/")
                        .maxAge(Duration.ofHours(1)) // 1 saat
                        .sameSite("Lax") // CSRF qoruması üçün
                        // .domain(".example.com") // Production üçün domen təyin edin
                        .build();
    
            return ResponseEntity.ok()
                        .header(HttpHeaders.SET_COOKIE, sessionCookie.toString()) 
                        .body("Modern session cookie set.");
        }
    
        private String generateSecureSessionId() {
            // Burada kriptoqrafik olaraq təhlükəsiz bir session ID generatoru istifadə edilməlidir
            // Məsələn: UUID.randomUUID().toString() və ya daha güclü metodlar
            return java.util.UUID.randomUUID().toString();
        }
    }

    ⚙️ ResponseCookie istifadəsi daha aydın kod yazmağa və bütün vacib təhlükəsizlik atributlarını nəzərə almağa kömək edir.

Təhlükəsizlik Radarında: Risklər və Qorunma Yolları

Cookie-lər faydalı olduğu qədər də təhlükə mənbəyi ola bilər. Əsas risklər və müdafiə mexanizmləri:

  • XSS (Cross-Site Scripting):
    • Risk: Əgər saytınızda XSS zəifliyi varsa, təcavüzkar zərərli JavaScript kodu yeridərək istifadəçinin brauzerində işə sala bilər. Bu kod document.cookie vasitəsilə HttpOnly olmayan bütün cookie-ləri (məsələn, session ID) oğurlaya və təcavüzkarın serverinə göndərə bilər. Nəticədə təcavüzkar həmin istifadəçinin sessiyasını ələ keçirə bilər (session hijacking).
    • 🛡️ Müdafiə: HttpOnly atributunu MÜTLƏQ aktivləşdirin! Bu, JS-nin cookie-yə birbaşa girişini əngəlləyir. Həmçinin, input validationoutput encoding kimi standart XSS müdafiə tədbirlərini tətbiq edin.
  • CSRF (Cross-Site Request Forgery):
    • Risk: Brauzerlər cookie-ləri avtomatik olaraq eyni domenə gedən hər istəyə əlavə edir. Təcavüzkar, istifadəçinin login olduğu bir saytda (məs: bank.com) onun adından gizli şəkildə əməliyyat aparmaq üçün başqa bir saytda (məs: evil.com) xüsusi hazırlanmış bir form və ya link yerləşdirə bilər. İstifadəçi evil.coma daxil olub bu linkə kliklədikdə (və ya form avtomatik submit olduqda), brauzer bank.coma istək göndərərkən bank.com üçün olan cookie-ləri (session ID daxil) avtomatik əlavə edəcək. bank.com bu istəyin legitim istifadəçidən gəldiyini düşünərək əməliyyatı (məs: pul köçürmə) icra edə bilər.
    • 🛡️ Müdafiə: SameSite atributunu Lax (standart) və ya Strict olaraq təyin edin! Bu, cookie-lərin cross-site istəklərlə göndərilməsini məhdudlaşdıraraq CSRF hücumlarının əksəriyyətinin qarşısını alır. Əlavə təhlükəsizlik qatı üçün state-i dəyişən əməliyyatlarda (POST, PUT, DELETE) Anti-CSRF Token mexanizmini tətbiq edin.
  • Session Hijacking (Oğurluq) / Fixation (Sabitləmə):
    • Risk: Cookie-ləri şəbəkədə (HTTPS istifadə edilməzsə) dinlənilə (sniffing), XSS ilə oğurlana və ya təcavüzkar tərəfindən əvvəlcədən təyin edilmiş bir session ID istifadəçiyə məcbur edilə (fixation) bilər.
    • 🛡️ Müdafiə: Həmişə HTTPS istifadə edin (Secure atributu ilə birlikdə)! Bu, sniffing-in qarşısını alır. HttpOnly XSS vasitəsilə oğurluğa qarşıdır. Session fixation-a qarşı isə istifadəçi login olduqdan dərhal sonra yeni bir session ID generate edin və köhnəsini etibarsız sayın.

Cookie-lər kontekstə görə iki cür olur:

  • First-party Cookie: İstifadəçinin birbaşa daxil olduğu domen tərəfindən təyin edilir (məs: example.comda gəzərkən example.com tərəfindən təyin edilən cookie).
  • Third-party Cookie: İstifadəçinin daxil olduğu domendən fərqli bir domen tərəfindən təyin edilir. Adətən reklamlar, sosial media widget-ları, analitika xidmətləri kimi embedded contentlər tərəfindən istifadə olunur (məs: example.comda gəzərkən adnetwork.com tərəfindən təyin edilən cookie).

⚠️ Trend: Məxfilik narahatlıqları səbəbilə (xüsusilə saytlararası izləmə - cross-site tracking), əksər müasir brauzerlər (Safari, Firefox başda olmaqla, Chrome da tədricən) third-party cookie-ləri bloklamağa və ya məhdudlaşdırmağa başlayıb. Bu, rəqəmsal reklam və analitika sənayesində ciddi dəyişikliklərə səbəb olur və alternativ texnologiyaların (məs: Google Privacy Sandbox) inkişafını sürətləndirir.

Çərəzlərə Alternativlər: Müasir Yanaşmalar

Cookie-lər hələ də geniş istifadə olunsa da, bəzi ssenarilərdə alternativlər daha uyğun ola bilər:

  • JWT (JSON Web Tokens):
    • Stateless autentifikasiya üçün populyar seçimdir. Login zamanı server imzalanmış bir token yaradır və client-ə göndərir.
    • Client bu token-i adətən localStorage və ya sessionStorageda saxlayır və hər qorunan istəkdə Authorization: Bearer <token> başlığı ilə göndərir.
    • Serverin session məlumatlarını saxlamasına ehtiyac qalmır (ona görə stateless).
    • Müqayisə: Cookie-lərə nəzərən CSRF-ə qarşı təbii olaraq daha davamlıdır (çünki avtomatik göndərilmir), amma localStorage-da saxlandıqda XSS hücumlarına qarşı həssasdır (oğurlanmış token istifadə edilə bilər).
  • Web Storage API (localStorage və sessionStorage):
    • Brauzerdə key-value şəklində məlumat saxlamaq üçün nəzərdə tutulub (cookie-lərdən daha çox yer təklif edir, adətən 5-10MB).
    • localStorage məlumatı brauzer bağlanıb açılanda belə saxlayır.
    • sessionStorage məlumatı yalnız cari brauzer tab-ı/pəncərəsi açıq olduğu müddətcə saxlayır.
    • Müqayisə: Cookie-lərdən fərqli olaraq, Web Storage-dakı məlumatlar serverə avtomatik göndərilmir. Lazım gələrsə, JavaScript ilə oxunub istəklərə (məsələn, header və ya body-də) əlavə edilməlidir. Həmçinin, XSS hücumlarına qarşı həssasdırlar, çünki JS ilə tam əlçatandırlar. Həssas session məlumatlarını burada saxlamaq adətən tövsiyə edilmir. UI state-i, istifadəçi preferences, offline data üçün daha uyğundur.
Thanks for reading.