Pada chapter sebelumnya kita membuat cookie dengan tiga argumen sederhana: nama, nilai, dan kedaluwarsa. setcookie() sebenarnya menerima satu array opsi sebagai argumen ketiga, berisi path, domain, secure, httponly, dan samesite. Setiap opsi mengatur di mana dan bagaimana cookie dikirim, dan setiap opsi keamanan memblokir kelas serangan yang berbeda — dari penyadapan jaringan, pencurian lewat XSS, sampai pemalsuan request lintas situs. Chapter ini membedah opsi-opsi tersebut satu per satu, lalu merangkumnya menjadi sebuah helper cookie yang aman untuk dipakai ulang di seluruh aplikasi.

Bentuk Lengkap melalui Array Options #

Bentuk array memungkinkan kita menuliskan seluruh opsi secara eksplisit dan mudah dibaca. Berikut contoh cookie yang mengaktifkan semua opsi keamanan:

php
<?php
$berhasil = setcookie('sesi_login', 'abc123', [
    'expires'  => 1767225600,
    'path'     => '/',
    'domain'   => '',
    'secure'   => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);

var_dump($berhasil);

Output yang Dihasilkan:

text
bool(true)

Tabel berikut merangkum makna setiap opsi beserta ancaman yang diblokirnya:

OpsiEfekAncaman yang diblokir
expiresmasa berlaku cookie (Unix timestamp)—
pathcookie hanya dikirim pada path tertentukebocoran cakupan ke path lain
domaincakupan host dan subdomainkebocoran ke subdomain lain
securehanya dikirim melalui HTTPSpenyadapan jaringan (sniffing)
httponlytidak dapat dibaca JavaScriptpencurian cookie via XSS
samesitemembatasi pengiriman lintas situsCSRF

Mengatur Scope dengan expires, path, dan domain #

Opsi expires mengikuti aturan yang sudah kita kenal: angka 0 berarti cookie hidup selama browser terbuka, sedangkan timestamp di masa depan menentukan tanggal kadaluarsa. Opsi path membatasi cookie hanya dikirim pada URL yang berawalan path tersebut — cookie dengan path: '/admin/' tidak ikut terkirim ketika pengguna membuka halaman depan toko. Opsi domain yang diisi '' mengikat cookie pada host saat ini; mengisinya dengan 'example.com' membuat seluruh subdomain ikut menerima cookie, sehingga pilihan tersebut justru memperluas permukaan serangan bila ada subdomain yang kurang terjaga.

php
<?php
$seluruhSitus = setcookie('tema', 'gelap', ['expires' => 0, 'path' => '/']);
$hanyaAdmin   = setcookie('admin_ui', 'ringkas', ['expires' => 0, 'path' => '/admin/']);

var_dump($seluruhSitus, $hanyaAdmin);

Output yang Dihasilkan:

text
bool(true)
bool(true)

Kedua cookie di atas berhasil disiapkan sebagai header. Browser kemudian hanya menyertakan admin_ui ketika request menuju path /admin/ dan turunannya, sementara tema menyertai seluruh request ke situs tersebut.

Tiga opsi berikut tidak mengubah isi cookie, tetapi mengubah kondisi pengiriman dan aksesnya. Ketiganya bekerja di sisi browser dan hanya efektif bila kita menuliskannya secara eksplisit pada setiap cookie yang kita buat.

secure: Hanya Melalui HTTPS #

Tanpa secure, cookie ikut terkirim pada request http:// polos. Di jaringan terbuka seperti WiFi kafe, penyadap dapat membaca seluruh lalu lintas termasuk header Cookie yang berisi ID login. Dengan secure: true, browser menolak mengirimkan cookie kecuali melalui koneksi HTTPS yang terenkripsi. Aktifkan opsi ini pada produksi yang sudah menjalankan HTTPS, dan siapkan sertifikat lokal untuk lingkungan pengembangan.

httponly: Menutup Akses JavaScript #

Secara bawaan, JavaScript dapat membaca cookie melalui document.cookie. Jika halaman mengandung celah XSS, skrip jahat yang tersisip dapat mencuri cookie session dan mengirimkannya ke server penyerang. Dengan httponly: true, browser melarang akses JavaScript terhadap cookie tersebut, sementara pengiriman otomatis pada request tetap berjalan normal. Penjelasan mendalam tentang XSS tersedia pada chapter Cross-Site Scripting .

samesite: Memutus Vektor CSRF #

Serangan CSRF memancing browser korban mengirim request ke aplikasi kita dari situs lain, dan browser secara bawaan tetap menyertakan cookie aplikasi kita pada request tersebut. Opsi samesite mengatur kapan cookie boleh ikut request lintas situs:

NilaiCookie dikirim padaKarakter
Stricthanya request dari situs yang samapaling ketat; klik tautan dari situs lain masuk dalam kondisi belum login
Laxrequest same-site plus navigasi GET tingkat ataskeseimbangan yang umum dipakai
Nonesemua request, termasuk lintas situstanpa perlindungan CSRF; wajib secure: true

Prefix __Secure- dan __Host- #

Prefiks nama adalah konvensi yang dipaksakan langsung oleh browser, bukan oleh PHP. Cookie yang namanya diawali __Secure- wajib mengaktifkan secure, sedangkan __Host- wajib mengaktifkan secure, mengosongkan domain, dan memakai path '/' — tanpa syarat tersebut browser menolak menyimpan cookie-nya. Manfaat utamanya adalah kebal dari penyerahan cookie palsu: subdomain yang diretas tidak dapat menyetel cookie __Host- karena syarat domain yang kosong mengikat cookie pada satu host saja.

PrefiksSyarat wajibKegunaan tipikal
__Secure-secure: truemenandai cookie penting lainnya
__Host-secure: true, domain kosong, path: '/'cookie session yang terikat ketat ke satu host
php
<?php
// Cookie session yang terikat ketat ke satu host
$ok = setcookie('__Host-sesi', 'abc123', [
    'expires'  => 0,
    'path'     => '/',
    'secure'   => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);

var_dump($ok);

Output yang Dihasilkan:

text
bool(true)

PHP mengembalikan true karena header berhasil disiapkan; pemeriksaan prefiks __Host- dilakukan oleh browser ketika menerima header tersebut.

Menuliskan keenam opsi pada setiap pemanggilan rawan lupa. Praktik yang lebih baik adalah memusatkan konfigurasi aman dalam satu helper, sehingga seluruh cookie aplikasi otomatis mendapat perlindungan yang sama.

php
<?php
function setSecureCookie(
    string $name,
    string $value,
    int $expires = 0,
    string $samesite = 'Lax',
): bool {
    return setcookie($name, $value, [
        'expires'  => $expires,
        'path'     => '/',
        'domain'   => '',
        'secure'   => true,
        'httponly' => true,
        'samesite' => $samesite,
    ]);
}

$satu = setSecureCookie('sesi_login', 'abc123', 1767225600);
$dua  = setSecureCookie('preferensi_tema', 'gelap');

var_dump($satu, $dua);

Output yang Dihasilkan:

text
bool(true)
bool(true)

Mari kita telaah helper di atas:

  1. Baris 2-8 (signature): parameter int $expires = 0 membuat cookie berumur selama browser terbuka secara default, dan string $samesite = 'Lax' memilih perlindungan CSRF yang seimbang.
  2. Baris 9-17 (array opsi): seluruh opsi keamanan ditetapkan di satu tempat — secure, httponly, path '/', dan domain kosong.
  3. Baris 19-20: pemanggil hanya perlu menyetel hal yang benar-benar berbeda, misalnya masa berlaku cookie login yang lebih panjang.

Ringkasan #

Array opsi setcookie() memberi kita kendali penuh atas masa berlaku, cakupan, dan keamanan cookie: secure memutus penyadap jaringan, httponly menutup pencurian lewat JavaScript, dan samesite memutus vektor CSRF. Prefiks __Host- mengikat cookie pada satu host secara ketat, dan helper setSecureCookie() memastikan seluruh cookie aplikasi memakai konfigurasi aman yang sama. Meski begitu, cookie tetap menyimpan data di sisi browser yang bisa dilihat dan dimanipulasi pengguna. Untuk data login yang sesungguhnya — ID pengguna, status verifikasi, isi keranjang — kita membutuhkan penyimpanan di server, dan itulah topik utama chapter Sessions berikutnya.

Referensi #