TypeScript'te `Cookie`

TypeScript'te `Cookie`

Bu makale TypeScript'te Cookie konusunu açıklar.

Tarayıcıda ve sunucuda çerezleri güvenli ve güvenilir biçimde ele almak için pratik kalıpları adım adım inceliyoruz.

YouTube Video

TypeScript'te Cookie

Çerezlerin temel kavramları

Çerez, istemcide küçük dizeleri (ad=değer çiftleri) depolamak için bir mekanizmadır; Set-Cookie HTTP başlığı veya document.cookie ile oluşturulur. Davranışlarını güvenlik öznitelikleri (HttpOnly, Secure, SameSite vb.) ile kontrol edebilirsiniz.

Tarayıcıda temel işlemler: document.cookie

Aşağıda tarayıcıda çerez yazmanın en basit örneği yer alıyor. Bir çerezi document.cookie'ye bir dize ekleyerek oluşturun.

 1// Set a simple cookie that expires in 7 days.
 2// Note: Comments are in English per the user's preference.
 3const setSimpleCookie = (name: string, value: string) => {
 4  const days = 7;
 5  const expires = new Date(Date.now() + days * 86400_000).toUTCString();
 6  // name=value; Expires=...; Path=/
 7  document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; Expires=${expires}; Path=/`;
 8};
 9
10setSimpleCookie('theme', 'dark');
  • Bu kod, 7 gün sonra sona eren bir çerez oluşturur. Tarayıcı tarafında kullanımı kolaydır, ancak HttpOnly ayarlanamadığı için hassas bilgileri depolamaktan kaçınmalısınız.

Çerezleri okuma (tarayıcı)

Aşağıdaki işlev, document.cookie içinden belirtilen ada sahip çerezin değerini alan bir yardımcı işlevdir. document.cookie, noktalı virgül ve boşluk ('; ') ile ayrılmış bir dize olarak döner. Bu nedenle onu parçalara ayırıp istenen çerezi arıyoruz.

 1// Parse document.cookie and return value for given name or null if not found.
 2const getCookie = (name: string): string | null => {
 3  const cookies = document.cookie ? document.cookie.split('; ') : [];
 4  for (const cookie of cookies) {
 5    const [k, ...rest] = cookie.split('=');
 6    const v = rest.join('=');
 7    if (decodeURIComponent(k) === name) {
 8      return decodeURIComponent(v);
 9    }
10  }
11  return null;
12};
13
14// Example usage:
15const theme = getCookie('theme'); // => "dark" if set
16console.log('theme cookie:', theme);
  • Bu işlev, güvenli biçimde karşılaştırıp almak için çerezin hem adının hem de değerinin kodunu çözer. Yinelenen çerez adlarını ve kodlanmış özel karakterleri işler; bu da onu basit ama sağlam bir uygulama yapar.

Güvenli öznitelikleri anlama ve uygulama

Çerezlerin birkaç önemli niteliği vardır; bunların her biri güvenliği ve davranış kapsamını kontrol eder.

  • HttpOnly niteliği çerezin JavaScript'ten erişilebilir olmasını engeller ve XSS (cross-site scripting) saldırılarını hafifletmeye yardımcı olur. Tarayıcı tarafından HttpOnly ayarlanamayacağını unutmayın.
  • Secure niteliği çerezlerin yalnızca HTTPS üzerinden gönderilmesini kısıtlar, dinleme ve kurcalama riskini azaltır.
  • SameSite niteliği çerezlerin siteler arası isteklerle gönderilip gönderilmeyeceğini kontrol eder ve CSRF (cross-site request forgery) saldırılarını önlemeye yardımcı olur.
  • Path niteliği çerezin gönderileceği istek yollarının kapsamını belirtir, Domain niteliği ise çerezin geçerli olduğu etki alanını belirtir.
  • Expires veya Max-Age niteliğini ayarlayarak çerezin sona erme süresini kontrol edebilirsiniz.

Tarayıcıda SameSite / Secure ekleme örneği (mümkün olanlar)

HttpOnly istemci tarafında ayarlanamaz. Aşağıda istemci tarafında SameSite ve Secure ekleme örneği bulunmaktadır. Secure ise yalnızca HTTPS sayfalarında etkili olur.

 1// Set cookie with SameSite and Secure attributes (Secure only effective over HTTPS).
 2const setCookieWithAttributes = (name: string, value: string) => {
 3  const maxAge = 60 * 60 * 24 * 7; // 7 days in seconds
 4  // Note: HttpOnly cannot be set from JS; set it on server-side when you want to restrict JS access.
 5  document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; `
 6    + `Max-Age=${maxAge}; `
 7    + `Path=/; `
 8    + `SameSite=Lax; `
 9    + `Secure`;
10};
11
12setCookieWithAttributes('session_hint', 'true');
  • SameSite=Lax güvenli ve yaygın bir tercihtir. Daha sıkı kısıtlamalar için SameSite=Strict kullanın; ancak dış sitelerden meşru yönlendirmeler çalışmayabilir.

Sunucuda çerez ayarlama (Set-Cookie) (Node / TypeScript)

Sunucuda Set-Cookie başlığıyla HttpOnly ekleyebilirsiniz; bu nedenle oturum yönetimi ideal olarak sunucu tarafında yapılmalıdır. Aşağıda Node'un http modülünü kullanan bir örnek yer alıyor.

 1// A minimal Node HTTP server in TypeScript that sets a secure HttpOnly cookie.
 2// This example uses built-in 'crypto' for a random session id.
 3import http from 'http';
 4import crypto from 'crypto';
 5
 6const server = http.createServer((req, res) => {
 7  if (req.url === '/login') {
 8    const sessionId = crypto.randomBytes(16).toString('hex');
 9    // Set cookie with HttpOnly, Secure, SameSite and Path
10    // Expires is optional — Max-Age preferred for relative lifetimes.
11    res.setHeader('Set-Cookie', `sid=${sessionId}; `
12      + `HttpOnly; `
13      + `Secure; `
14      + `SameSite=Strict; `
15      + `Path=/; `
16      + `Max-Age=3600`
17    );
18    res.writeHead(302, { Location: '/' });
19    res.end();
20    return;
21  }
22
23  res.writeHead(200, { 'Content-Type': 'text/plain' });
24  res.end('Hello\n');
25});
26
27server.listen(3000, () => {
28  console.log('Server running on http://localhost:3000');
29});
  • Sunucu tarafında HttpOnly niteliğini ayarladığınızda çerez JavaScript'ten erişilemez hâle gelir ve XSS (cross-site scripting) saldırılarının onu çalmasını zorlaştırır. Ayrıca çerezlerin her zaman HTTPS üzerinden gönderilmesi için Secure niteliğini ekleyerek dinlemeyi ve kurcalamayı önleyebilir, iletişim güvenliğini artırabilirsiniz.

Çerez serileştirme/ayrıştırma uygulaması (sunucu tarafı yardımcı)

Aşağıda Set-Cookie başlık dizesi oluşturan basit bir sunucu tarafı yardımcı araç bulunmaktadır.

 1// Cookie serialization helper for server-side use.
 2// Returns a properly formatted Set-Cookie header value.
 3type CookieOptions = {
 4  path?: string;
 5  domain?: string;
 6  maxAge?: number;
 7  expires?: Date;
 8  httpOnly?: boolean;
 9  secure?: boolean;
10  sameSite?: 'Strict' | 'Lax' | 'None';
11};
12
13const serializeCookie = (name: string, value: string, opts: CookieOptions = {}): string => {
14  const parts: string[] = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
15
16  if (opts.maxAge != null) parts.push(`Max-Age=${Math.floor(opts.maxAge)}`);
17  if (opts.expires) parts.push(`Expires=${opts.expires.toUTCString()}`);
18  if (opts.domain) parts.push(`Domain=${opts.domain}`);
19  parts.push(`Path=${opts.path ?? '/'}`);
20  if (opts.httpOnly) parts.push('HttpOnly');
21  if (opts.secure) parts.push('Secure');
22  if (opts.sameSite) parts.push(`SameSite=${opts.sameSite}`);
23
24  return parts.join('; ');
25};
26
27// Example usage:
28const headerValue = serializeCookie('uid', 'abc123', {
29  httpOnly: true,
30  secure: true,
31  sameSite: 'Lax',
32  maxAge: 3600
33});
34console.log(headerValue);
35// => "uid=abc123; Max-Age=3600; Path=/; HttpOnly; Secure; SameSite=Lax"
  • Bu yardımcı araç, özel bir sunucuda Set-Cookie oluşturmanın temelini oluşturur. Kütüphaneler çok daha fazla uç durumu ele alabilir.

İmzalarla kurcalamayı önleme (HMAC)

Önemli değerleri doğrudan çerezlerde saklamak tehlikelidir. Kurcalamayı tespit etmek için değerleri sunucuda imzalayan bir yöntem sunuyoruz. Burada HMAC-SHA256 kullanıyoruz. Üretim ortamında, belirteç geçersiz kılmayı sunucu tarafında da yönetmeniz gerekir.

 1// A simple HMAC signing and verification helper for cookies.
 2// Signing prevents client from tampering cookie values.
 3import crypto from 'crypto';
 4
 5const SECRET = 'replace_with_env_secret'; // store in env var in production
 6
 7const signValue = (value: string) => {
 8  const hmac = crypto.createHmac('sha256', SECRET);
 9  hmac.update(value);
10  return `${value}.${hmac.digest('hex')}`;
11};
12
13const verifySignedValue = (signed: string): string | null => {
14  const idx = signed.lastIndexOf('.');
15  if (idx === -1) return null;
16  const value = signed.slice(0, idx);
17  const sig = signed.slice(idx + 1);
18
19  const hmac = crypto.createHmac('sha256', SECRET);
20  hmac.update(value);
21  const expected = hmac.digest('hex');
22  // use timing-safe comparison in production
23  if (crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
24    return value;
25  }
26  return null;
27};
28
29// Example usage:
30const signed = signValue('userId=42');
31console.log('signed:', signed);
32console.log('verified:', verifySignedValue(signed)); // => "userId=42"
  • Bu yöntemle, çerez değerinin kurcalanıp kurcalanmadığını kontrol edebilirsiniz. İmzalama anahtarını kaynak koda dahil etmeyin; ortam değişkenleri gibi güvenli yöntemlerle yönetin.

Çerezler ve CSRF azaltma (genel kalıplar)

Çerez kullanan oturumların CSRF korumasına ihtiyacı vardır. Tipik önlemler şunlardır:.

  • Gereksiz siteler arası gönderimi önlemek için SameSiteLax veya Strict olarak ayarlayın. Yalnızca çapraz kaynak iletişimi gerekli olduğunda SameSite=None; Secure kullanın.
  • Formlar ve API istekleri için sunucu tarafından doğrulanan CSRF belirteçlerini kullanın. HttpOnly çerezinde belirteci saklamayın; bunun yerine, yanıt gövdesi veya meta etiketleri aracılığıyla sağlayın ve JavaScript'in onu yalnızca gerektiğinde okumasını sağlayın.
  • Belirtece JavaScript'ten erişilebiliyorsa, XSS korumalarını (CSP, çıktı kaçışlama vb.) de uyguladığınızdan emin olun.
  • Hassas işlemler ve oturum açma için yeniden kimlik doğrulaması gerektirin ve oturum sabitleme saldırılarını önleyin.

Aşağıda, CSRF belirtecini bir başlıkta gönderen güvenli bir istemci örneği bulunmaktadır. Bu, istemcinin belirteci sunucudan zaten aldığını varsayar; örneğin yanıt gövdesinde.

 1// Example of sending CSRF token safely in a header using fetch.
 2// Assumes CSRF token was provided securely (e.g., via response body or meta tag).
 3async function sendProtectedRequest(url: string, csrfToken: string) {
 4  const res = await fetch(url, {
 5    method: 'POST',
 6    credentials: 'same-origin', // include cookies for same-site requests
 7    headers: {
 8      'Content-Type': 'application/json',
 9      'X-CSRF-Token': csrfToken
10    },
11    body: JSON.stringify({ action: 'doSomething' })
12  });
13  return res;
14}
  • credentials: 'same-origin' belirtirseniz, yalnızca aynı kökene ait çerezler gönderilir. Sunucuda, X-CSRF-Token başlığının değerini doğrulayın ve belirtecin eşleştiğini teyit edin. Çapraz köken istekleri gerekliyse, CORS'u dikkatle yapılandırın.

Siteler arası (CORS) ve credentials ile ilişkisi

Çapraz köken iletişiminde çerez göndermek ve almak için, istemci credentials: 'include' belirtmeli ve sunucu Access-Control-Allow-Credentials: true ayarlamalıdır. Ancak bu yapılandırmayı güvenilen kökenlerle sınırlandırın ve Access-Control-Allow-Origin: * kullanmayın.

 1async function fetchCrossOriginData() {
 2  // Example: cross-origin fetch sending cookies.
 3  // Server must set Access-Control-Allow-Credentials: true
 4  // and a specific trusted origin.
 5  const res = await fetch('https://api.example.com/data', {
 6    credentials: 'include', // send cookies only to trusted domains
 7    method: 'GET'
 8  });
 9  return res;
10}
  • CORS ve çerezlerin birlikte kullanımı güvenlik açısından son derece hassastır. İzin verilen kökenleri bir beyaz listeyle sıkı biçimde yönetin ve gereksiz çapraz köken iletişiminden kaçının. Ayrıca, SameSite=None; Secure kullanırken ortadaki adam saldırılarını önlemek için HTTPS'i zorunlu kılın.

Örnek: Express ile güvenli oturum çerezi ayarları (TypeScript)

Pratikte Express, cookie kütüphanesi, express-session vb. kullanın. Aşağıda express ve cookie-parser kullanan basit bir örnek vardır. Pratikte, secure'ü true yapın ve secret'ı ortam değişkenleriyle yönetin.

 1// Express example using cookie-parser and setting a secure httpOnly cookie.
 2// npm install express cookie-parser @types/express @types/cookie-parser
 3import express from 'express';
 4import cookieParser from 'cookie-parser';
 5
 6const app = express();
 7app.use(cookieParser(process.env.COOKIE_SECRET));
 8
 9app.post('/login', (req, res) => {
10  // authenticate user (omitted)
11  const sessionId = 'generated-session-id';
12  res.cookie('sid', sessionId, {
13    httpOnly: true,
14    secure: true,        // require HTTPS in production
15    sameSite: 'lax',
16    maxAge: 1000 * 60 * 60 // 1 hour
17  });
18  res.json({ ok: true });
19});
20
21app.listen(3000);
  • cookieParser'ın secret özelliğini kullanarak imzalı çerezlerle kolayca çalışabilirsiniz. Ancak gerçek uygulamalarda, güvenlik ve ölçeklenebilirlik açısından verileri doğrudan çerezlerde depolamamalı; bunun yerine özel bir oturum deposu kullanmalısınız.

Çerez önekleri __Host- ve __Secure-

Tarayıcılar bazı önekler için özel kuralları zorunlu kılar.

  • __Secure- öneki Bir çerez adı __Secure- ile başlıyorsa, Secure özniteliği zorunludur.
  • __Host- öneki __Host- ile başlıyorsa Secure zorunludur, yol / (kök) olmalı ve Domain ayarlanmamalıdır.

Bunları kullanmak yanlış yapılandırmayı azaltır ve güvenliği artırır.

Çerez en iyi uygulamaları

Çerezleri güvenli bir şekilde ele almak için aşağıdaki noktaları göz önünde bulundurun.

  • Hassas bilgileri doğrudan çerezlerde depolamayın. Erişim belirteçleri için sunucu taraflı bir oturum kimliğini tercih edin.
  • HttpOnly, Secure ve SameSite=Lax (veya Strict) ile oturum çerezleri ayarlayın.
  • __Host- ve __Secure- gibi öneklerden yararlanın.
  • Kurcalama ve dinlemeyi önlemek için imzaları (HMAC) ve şifrelemeyi değerlendirin.
  • Secure'ü etkinleştirin ve HTTPS zorunlu olsun.
  • En az ayrıcalık ve kısa sona erme sürelerini hedefleyin.
  • CSRF belirteçleri kullanın.
  • Özellikle eski olanlar arasında, tarayıcılar arasındaki SameSite davranışı farklarına dikkat edin.

Çerezlerle ilgili yaygın yanlış kanılar

Çerezlerle ilgili olarak, aşağıdaki yaygın yanılgılara dikkat edin.

  • 'HttpOnly eklemek XSS'in etkisini ortadan kaldırır.' HttpOnly çerezlere JavaScript tarafından erişilmesini engellese de, XSS yine de keyfi istekler göndermek için kullanılabilir. Ayrıca CSRF belirteci doğrulaması, CSP (İçerik Güvenlik Politikası) ve girdi arındırma da kullanmalısınız.
  • 'Yerel geliştirme için Secure gereksizdir.' Yerel ortamlarda bile HTTPS'i simüle etmek ve davranışı doğrulamak, test doğruluğunu artırır. En azından hazırlık (staging) ve üretim ortamlarında HTTPS kullanılmalıdır.
  • 'Uzun geçerlilik süreleri kullanışlıdır.' Çerezler için uzun yaşam süresi ayarlarsanız, çalınmaları hâlinde kötüye kullanılabilecekleri süre artar. Daha kısa sona erme süreleri belirleyebilir ve periyodik yeniden kimlik doğrulama ile belirteç döndürmeyi (token rotation) uygulayabilirsiniz.

Özet

Çerezler kullanımı kolay olsa da, yanlış yönetilmeleri güvenlik açıklarına yol açabilir. Bunları TypeScript ile doğru yönetmek için HttpOnly, Secure ve SameSite gibi öznitelikleri anlamak ve güvenli sunucu tarafı ayarlarını zorunlu kılmak önemlidir. Hassas verileri doğrudan saklamayarak ve imzaları kısa sona erme süreleriyle birleştirerek güvenli ve güvenilir bir oturum yönetimi sağlayabilirsiniz.

Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.

YouTube Video