`Cookie` dalam TypeScript

`Cookie` dalam TypeScript

Artikel ini menerangkan Cookie dalam TypeScript.

Kami membincangkan corak praktikal untuk mengendalikan kuki dengan selamat dan boleh dipercayai di kedua-dua pelayar dan pelayan.

YouTube Video

Cookie dalam TypeScript

Konsep asas kuki

Kuki ialah mekanisme untuk menyimpan rentetan kecil (pasangan name=value) pada klien, dicipta melalui pengepala HTTP Set-Cookie atau document.cookie. Anda boleh mengawal tingkah lakunya dengan atribut keselamatan (HttpOnly, Secure, SameSite, dll.).

Operasi asas dalam pelayar: document.cookie

Di bawah ialah contoh paling ringkas untuk menulis kuki dalam pelayar. Cipta kuki dengan menambah rentetan pada document.cookie.

 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');
  • Kod ini mencipta kuki yang luput dalam 7 hari. Ia mudah digunakan di sisi pelayar, tetapi kerana anda tidak boleh menetapkan HttpOnly, anda harus mengelakkan daripada menyimpan maklumat sensitif.

Membaca kuki (pelayar)

Fungsi berikut ialah fungsi pembantu yang mendapatkan nilai kuki dengan nama yang dinyatakan daripada document.cookie. document.cookie dipulangkan sebagai rentetan yang dipisahkan oleh tanda titik koma dan satu ruang ('; '). Oleh itu, kami memisahkannya dan mencari kuki yang dikehendaki.

 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);
  • Fungsi ini menyahkod kedua-dua nama dan nilai kuki untuk membandingkannya dan mengambilnya dengan selamat. Ia menangani nama kuki yang bertindih dan aksara khas yang dienkod, menjadikannya pelaksanaan yang ringkas namun teguh.

Memahami dan mengaplikasikan atribut keselamatan

Kuki mempunyai beberapa atribut penting, setiap satunya mengawal keselamatan dan skop tingkah laku.

  • Atribut HttpOnly menghalang kuki daripada diakses oleh JavaScript, sekali gus membantu mengurangkan risiko serangan XSS (cross-site scripting). Ambil perhatian bahawa anda tidak boleh menetapkan HttpOnly dari bahagian pelayar.
  • Atribut Secure mengehadkan kuki supaya ia hanya dihantar melalui HTTPS, sekali gus mengurangkan risiko intipan dan pengubahsuaian.
  • Atribut SameSite mengawal sama ada kuki dihantar bersama permintaan rentas tapak dan membantu mencegah serangan CSRF (cross-site request forgery).
  • Atribut Path menentukan skop laluan permintaan bagi penghantaran kuki, manakala atribut Domain menentukan domain tempat kuki itu sah.
  • Dengan menetapkan atribut Expires atau Max-Age, anda boleh mengawal tarikh luput kuki.

Contoh menambah SameSite / Secure dalam pelayar (apa yang mungkin)

HttpOnly tidak boleh ditetapkan di sisi klien. Di bawah ialah contoh menambah SameSite dan Secure di sisi klien. Walau bagaimanapun, Secure hanya berkesan pada halaman HTTPS.

 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 ialah pilihan yang selamat dan lazim. Untuk sekatan yang lebih ketat gunakan SameSite=Strict, tetapi navigasi yang sah dari tapak luar mungkin berhenti berfungsi.

Menetapkan kuki pada pelayan (Set-Cookie) (Node / TypeScript)

Di pelayan anda boleh menambah HttpOnly melalui pengepala Set-Cookie, jadi pengurusan sesi sebaiknya dilakukan di sisi pelayan. Di bawah ialah contoh menggunakan modul http Node.

 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});
  • Apabila anda menetapkan atribut HttpOnly di sisi pelayan, kuki tidak lagi boleh diakses daripada JavaScript, sekali gus menyukarkan serangan XSS (cross-site scripting) untuk mencurinya. Selain itu, dengan menambah atribut Secure supaya kuki sentiasa dihantar melalui HTTPS, anda boleh menghalang intipan dan pengubahsuaian serta meningkatkan keselamatan komunikasi.

Pelaksanaan pensirian/penghuraian kuki (pembantu sisi pelayan)

Di bawah ialah utiliti sisi pelayan ringkas yang membina rentetan pengepala Set-Cookie.

 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"
  • Utiliti ini menjadi asas untuk mencipta Set-Cookie pada pelayan tersuai. Perpustakaan boleh mengendalikan lebih banyak kes pinggir.

Mencegah pengubahan dengan tandatangan (HMAC)

Adalah berbahaya untuk menyimpan nilai penting secara terus dalam kuki. Kami memperkenalkan kaedah yang menandatangani nilai pada pelayan untuk mengesan pengubahan. Di sini kami menggunakan HMAC-SHA256. Dalam persekitaran pengeluaran, anda juga perlu mengurus pembatalan token di sisi pelayan.

 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"
  • Dengan kaedah ini, anda boleh menyemak sama ada nilai Kuki telah diubah suai. Jangan masukkan kunci tandatangan ke dalam kod sumber; uruskannya melalui cara yang selamat seperti menggunakan pembolehubah persekitaran.

Kuki dan mitigasi CSRF (corak umum)

Sesi yang menggunakan kuki memerlukan perlindungan CSRF. Langkah mitigasi lazim termasuk:.

  • Tetapkan SameSite kepada Lax atau Strict untuk menghalang penghantaran rentas tapak yang tidak perlu. Gunakan SameSite=None; Secure hanya apabila komunikasi rentas asal diperlukan.
  • Gunakan token CSRF, yang disahkan oleh pelayan, untuk borang dan permintaan API. Jangan simpan token dalam kuki HttpOnly; sebaliknya, sediakannya melalui badan respons atau tag meta, dan biarkan JavaScript membacanya hanya apabila perlu.
  • Jika token boleh diakses daripada JavaScript, pastikan perlindungan XSS (CSP, pelarian output, dan lain-lain) turut dilaksanakan.
  • Wajibkan pengesahan semula untuk tindakan sensitif dan semasa log masuk, serta mencegah serangan pemfiksasian sesi.

Di bawah ialah contoh klien yang selamat yang menghantar token CSRF dalam pengepala. Ini menganggap klien telah menerima token daripada pelayan, contohnya dalam badan respons.

 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}
  • Jika anda menetapkan credentials: 'same-origin', hanya kuki untuk asal yang sama akan dihantar. Pada pelayan, sahkan nilai pengepala X-CSRF-Token dan pastikan token sepadan. Jika permintaan rentas tapak diperlukan, konfigurasikan CORS dengan berhati-hati.

Rentas tapak (CORS) dan hubungan dengan credentials

Untuk menghantar dan menerima kuki dalam komunikasi rentas asal, klien mesti menetapkan credentials: 'include' dan pelayan mesti menetapkan Access-Control-Allow-Credentials: true. Namun, hadkan konfigurasi ini kepada asal yang dipercayai dan jangan gunakan Access-Control-Allow-Origin: *.

 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}
  • Gabungan CORS dan kuki sangat sensitif dari sudut keselamatan. Urus asal yang dibenarkan secara ketat menggunakan senarai dibenarkan dan elakkan komunikasi rentas tapak yang tidak perlu. Selain itu, apabila menggunakan SameSite=None; Secure, kuatkuasakan HTTPS untuk mencegah serangan orang-di-tengah.

Contoh: tetapan kuki sesi selamat dengan Express (TypeScript)

Dalam amalan, gunakan Express, pustaka cookie, express-session, dan sebagainya. Di bawah ialah contoh ringkas menggunakan express dan cookie-parser. Dalam amalan, tetapkan secure kepada true dan urus secret melalui pembolehubah persekitaran.

 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);
  • Dengan menggunakan ciri secret milik cookieParser, anda boleh mengendalikan kuki yang ditandatangani dengan mudah. Namun, dalam aplikasi sebenar, dari perspektif keselamatan dan kebolehskalaan, anda tidak seharusnya menyimpan data secara langsung dalam kuki; sebaliknya, gunakan stor sesi khusus.

Awalan kuki __Host- dan __Secure-

Pelayar menguatkuasakan peraturan khas untuk sesetengah awalan.

  • Awalan __Secure- Jika nama kuki bermula dengan __Secure-, atribut Secure adalah wajib.
  • Awalan __Host- Jika ia bermula dengan __Host-, Secure diperlukan, laluan mesti / (akar), dan Domain tidak boleh ditetapkan.

Menggunakannya mengurangkan salah konfigurasi dan meningkatkan keselamatan.

Amalan terbaik kuki

Untuk mengendalikan Kuki dengan selamat, pertimbangkan perkara berikut.

  • Jangan simpan maklumat sensitif secara langsung dalam kuki. Utamakan ID sesi sisi pelayan untuk token akses.
  • Tetapkan kuki sesi dengan HttpOnly, Secure, dan SameSite=Lax (atau Strict).
  • Manfaatkan awalan seperti __Host- dan __Secure-.
  • Pertimbangkan tandatangan (HMAC) dan penyulitan untuk mencegah pengubahan dan penyadapan.
  • Dayakan Secure dan wajibkan HTTPS.
  • Sasarkan keistimewaan minimum dan tempoh luput yang pendek.
  • Gunakan token CSRF.
  • Waspada terhadap perbezaan tingkah laku SameSite antara pelayar, terutamanya yang lebih lama.

Salah tanggapan biasa tentang kuki

Berkaitan kuki, ambil perhatian terhadap salah faham umum berikut.

  • 'Menambah HttpOnly menghapuskan impak XSS.' Walaupun HttpOnly menghalang kuki diakses oleh JavaScript, XSS masih boleh digunakan untuk menghantar permintaan sewenang-wenangnya. Anda juga harus menggunakan pengesahan token CSRF, CSP (Content Security Policy), dan sanitasi input.
  • 'Secure tidak diperlukan untuk pembangunan setempat.' Mensimulasikan HTTPS dan mengesahkan kelakuan walaupun dalam persekitaran setempat meningkatkan ketepatan ujian. Sekurang-kurangnya, HTTPS hendaklah digunakan dalam persekitaran staging dan pengeluaran.
  • 'Tempoh luput yang panjang adalah mudah.' Jika anda menetapkan jangka hayat kuki yang panjang, tempoh ia boleh disalahgunakan jika dicuri akan meningkat. Anda boleh menetapkan tempoh luput yang lebih pendek serta menggabungkan pengesahan semula berkala dan penggiliran token.

Ringkasan

Walaupun kuki mudah digunakan, penyalahgunaannya boleh memperkenalkan kelemahan keselamatan. Untuk mengurusnya dengan betul dengan TypeScript, adalah penting untuk memahami atribut seperti HttpOnly, Secure, dan SameSite, serta menguatkuasakan tetapan sisi pelayan yang selamat. Dengan tidak menyimpan data sensitif secara langsung dan menggabungkan tandatangan dengan tempoh luput yang pendek, anda boleh mencapai pengurusan sesi yang selamat dan boleh dipercayai.

Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.

YouTube Video