Cara yang benar untuk menghapus cookie sisi server

141

Untuk proses otentikasi saya, saya membuat token unik ketika pengguna login dan memasukkannya ke dalam cookie yang digunakan untuk otentikasi.

Jadi saya akan mengirim sesuatu seperti ini dari server:

Set-Cookie: token=$2a$12$T94df7ArHkpkX7RGYndcq.fKU.oRlkVLOkCBNrMilaSWnTcWtCfJC; path=/;

Yang berfungsi di semua browser. Kemudian untuk menghapus cookie saya mengirim cookie serupa dengan expiresbidang yang ditetapkan untuk 1 Januari 1970

Set-Cookie: token=$2a$12$T94df7ArHkpkX7RGYndcq.fKU.oRlkVLOkCBNrMilaSWnTcWtCfJC; path=/; expires=Thu, Jan 01 1970 00:00:00 UTC; 

Dan itu berfungsi dengan baik di Firefox tetapi tidak menghapus cookie di IE atau Safari.

Jadi apa cara terbaik untuk menghapus cookie (tanpa JavaScript lebih disukai)? Metode set-the-expires-in-the-past tampaknya besar. Dan juga mengapa ini bekerja di FF tetapi tidak di IE atau Safari?

Joshkunz
sumber
Lihat juga stackoverflow.com/a/20320610/212378
Alexis Wilke

Jawaban:

208

Mengirim nilai cookie yang sama dengan yang ; expiresditambahkan tidak akan menghancurkan cookie.

Validasi cookie dengan menetapkan nilai kosong dan sertakan expiresbidang juga:

Set-Cookie: token=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT

Perhatikan bahwa Anda tidak dapat memaksa semua browser untuk menghapus cookie. Klien dapat mengonfigurasi browser sedemikian rupa sehingga cookie tetap ada, bahkan jika cookie itu kadaluwarsa. Menetapkan nilai seperti dijelaskan di atas akan menyelesaikan masalah ini.

Lekensteyn
sumber
52
Saya akan merekomendasikan untuk menggunakan teks kosong sebagai sampah, alih-alih "deleted", untuk menghindari kebingungan nanti dengan nilai yang berpotensi legal sama dengan "dihapus"
yegor256
8
@raulk Ya, Anda benar. Lucu yang belum diperhatikan sebelumnya, semoga saja tidak menimbulkan masalah terlalu banyak. yegor256, nilai kosong harus berfungsi dalam banyak kasus. Terkait: beberapa orang mungkin bertanya-tanya mengapa cookie mereka tidak dihapus bahkan setelah mengirim tajuk ini. Jika demikian, lihat cookie dari domain lain. Misalnya, setelah menghapus foo=bar; domain=www.example.com, cookie lain foo=qux; domain=.example.comakan digunakan.
Lekensteyn
3
"Klien dapat mengonfigurasi browser sedemikian rupa sehingga cookie tetap ada, bahkan jika cookie itu kadaluwarsa. Menetapkan nilai seperti yang dijelaskan di atas akan menyelesaikan masalah ini." Tidak bisakah klien dapat mengkonfigurasi browser untuk mengabaikan permintaan Anda untuk mengatur konten cookie menjadi "dihapus" juga? Anda tidak memiliki cara untuk memaksa klien untuk melakukan apa pun yang tidak diinginkannya.
Ajedi32
@ Ajedi32 Bisa, tapi kemudian Anda harus melalui upaya tambahan untuk melakukannya (sebagai klien). Perilaku mengabaikan nilai kosong jauh lebih umum, tidak masuk akal bagi browser untuk mengabaikan permintaan tersebut, terutama untuk ID sesi yang tidak valid.
Lekensteyn
2
-1 karena saya belum pernah melihat cara mengkonfigurasi browser untuk mengabaikan kedaluwarsa cookie, dan saya tidak yakin bahwa ada browser yang menawarkan opsi seperti itu. Terlebih lagi, kalimat pertama dari jawaban Anda, setelah pengeditan @ DaveJarvis yang agak berani, sekarang benar-benar palsu untuk semua browser utama atau agen pengguna yang memenuhi spesifikasi. tools.ietf.org/search/rfc6265#section-5.3 menyatakan bahwa "Agen pengguna HARUS mengusir semua cookie yang kedaluwarsa dari toko kue jika, sewaktu-waktu, kue yang kadaluarsa ada di toko kue." dan sejauh pengetahuan saya, itulah yang dilakukan oleh setiap browser.
Mark Amery
46

Pada saat saya menulis jawaban ini, jawaban yang diterima untuk pertanyaan ini tampaknya menyatakan bahwa browser tidak diharuskan untuk menghapus cookie ketika menerima cookie pengganti yang Expiresnilainya di masa lalu. Klaim itu salah. Pengaturan Expiresuntuk berada di masa lalu adalah cara standar, khusus untuk menghapus cookie, dan agen pengguna diharuskan oleh spec untuk menghormatinya.

Menggunakan Expiresatribut di masa lalu untuk menghapus cookie adalah benar dan merupakan cara untuk menghapus cookie yang ditentukan oleh spesifikasi. Bagian contoh dari RFC 6255 menyatakan:

Akhirnya, untuk menghapus cookie, server mengembalikan header Set-Cookie dengan tanggal kedaluwarsa di masa lalu. Server akan berhasil dalam menghapus cookie hanya jika atribut Path dan Domain di header Set-Cookie cocok dengan nilai-nilai yang digunakan ketika cookie dibuat.

Bagian Persyaratan Agen Pengguna mencakup persyaratan berikut, yang bersama-sama memiliki efek bahwa cookie harus segera dihapus jika agen pengguna menerima cookie baru dengan nama yang sama dengan tanggal kedaluwarsa di masa lalu

  1. Jika [saat menerima cookie baru] toko cookie berisi cookie dengan nama, domain, dan jalur yang sama dengan cookie yang baru dibuat:

    1. ...
    2. ...
    3. Perbarui waktu pembuatan cookie yang baru dibuat agar sesuai dengan waktu pembuatan cookie lama.
    4. Hapus cookie lama dari toko cookie.
  2. Masukkan cookie yang baru dibuat ke toko cookie.

Cookie "kedaluwarsa" jika cookie memiliki tanggal kedaluwarsa di masa lalu.

Agen pengguna HARUS mengusir semua cookie yang kedaluwarsa dari toko cookie jika, sewaktu-waktu, cookie yang sudah kadaluarsa ada di toko kue.

Poin 11-3, 11-4, dan 12 di atas bersama-sama berarti bahwa ketika cookie baru diterima dengan nama, domain, dan jalur yang sama, cookie lama harus dihapus dan diganti dengan cookie baru. Akhirnya, poin di bawah tentang kadaluarsa cookie lebih lanjut menentukan bahwa setelah itu selesai, cookie baru juga harus segera diusir. Spesifikasi tidak menawarkan ruang gerak untuk browser pada titik ini; jika browser menawarkan opsi kepada pengguna untuk menonaktifkan kedaluwarsa cookie, seperti jawaban yang diterima menyarankan beberapa browser, maka itu akan melanggar spesifikasi. (Fitur seperti itu juga tidak banyak berguna, dan sejauh yang saya tahu tidak ada di browser apa pun.)

Lalu, mengapa OP dari pertanyaan ini mengamati bahwa pendekatan ini gagal? Meskipun saya belum membersihkan salinan dari Internet Explorer untuk memeriksa perilakunya, saya menduga itu karena nilai OP Expiressalah! Mereka menggunakan nilai ini:

expires=Thu, Jan 01 1970 00:00:00 UTC;

Namun, ini tidak valid secara sintaksis dalam dua cara.

Bagian sintaks dari spec menentukan bahwa nilai Expiresatribut harus a

rfc1123 -tanggal , didefinisikan dalam [RFC2616], Bagian 3.3.1

Mengikuti tautan kedua di atas, kami menemukan ini diberikan sebagai contoh format:

Sun, 06 Nov 1994 08:49:37 GMT

dan temukan bahwa definisi sintaks ...

  1. mensyaratkan bahwa tanggal ditulis dalam format hari bulan tahun , bukan format bulan hari tahun seperti yang digunakan oleh penanya.

    Secara khusus, ini mendefinisikan rfc1123-datesebagai berikut:

    rfc1123-date = wkday "," SP date1 SP time SP "GMT"
    

    dan mendefinisikan date1seperti ini:

    date1        = 2DIGIT SP month SP 4DIGIT
                 ; day month year (e.g., 02 Jun 1982)
    

dan

  1. tidak mengizinkan UTCsebagai zona waktu.

    Spesifikasi tersebut berisi pernyataan berikut tentang offset zona waktu apa yang dapat diterima dalam format ini:

    Semua stempel tanggal / waktu HTTP HARUS diwakili dalam Greenwich Mean Time (GMT), tanpa kecuali.

    Terlebih lagi jika kita menggali lebih dalam ke spesifikasi asli format datetime ini, kita menemukan bahwa dalam spesifikasi awalnya di https://tools.ietf.org/html/rfc822 , bagian Sintaksis mencantumkan "UT" (artinya "waktu universal" ) sebagai nilai yang mungkin, tetapi tidak mencantumkan bukan UTC (Waktu Universal Terkoordinasi) yang valid. Sejauh yang saya tahu, menggunakan "UTC" dalam format tanggal ini tidak pernah valid; itu bukan nilai yang valid ketika format pertama kali ditentukan pada tahun 1982, dan spesifikasi HTTP telah mengadopsi versi format yang lebih ketat dengan melarang penggunaan semua nilai "zona" selain "GMT".

Jika penanya di sini menggunakan Expiresatribut seperti ini , maka:

expires=Thu, 01 Jan 1970 00:00:00 GMT;

maka itu mungkin akan berhasil.

Mark Amery
sumber
15

Pengaturan "kedaluwarsa" ke tanggal yang lalu adalah cara standar untuk menghapus cookie.

Masalah Anda mungkin karena format tanggal tidak konvensional. IE mungkin hanya mengharapkan GMT.

tak dapat disangkal
sumber
2

Gunakan Max-Age = -1 daripada "Kedaluwarsa". Itu lebih pendek, kurang pilih-pilih tentang sintaks, dan Max-Age lebih diutamakan daripada Expired.

Steven Pemberton
sumber
-1

Untuk implementasi GlassFish Jersey JAX-RS saya telah mengatasi masalah ini dengan metode umum yang menggambarkan semua parameter umum. Setidaknya tiga parameter harus sama: nama (= "nama"), jalur (= "/") dan domain (= nol):

public static NewCookie createDomainCookie(String value, int maxAgeInMinutes) {
    ZonedDateTime time = ZonedDateTime.now().plusMinutes(maxAgeInMinutes);
    Date expiry = time.toInstant().toEpochMilli();
    NewCookie newCookie = new NewCookie("name", value, "/", null, Cookie.DEFAULT_VERSION,null, maxAgeInMinutes*60, expiry, false, false);
    return newCookie;
}

Dan gunakan itu cara umum untuk mengatur cookie:

NewCookie domainNewCookie = RsCookieHelper.createDomainCookie(token, 60);
Response res = Response.status(Response.Status.OK).cookie(domainNewCookie).build();

dan untuk menghapus cookie:

NewCookie domainNewCookie = RsCookieHelper.createDomainCookie("", 0);
Response res = Response.status(Response.Status.OK).cookie(domainNewCookie).build();
RoutesMaps.com
sumber
bagi saya ketika saya menetapkan maxAge ke 0, itu menghasilkan cookie dengan Max-Age = 0 yang tampaknya diabaikan oleh Chrome. Dalam RFC 6265 bagian 4.1.1 itu menentukan sintaks Max-Age sebagai "non-zero-digit". Itu mungkin alasannya. Meskipun, sebagaimana disebutkan oleh @ JoshC13, bagian 5.2.2 berbicara tentang menafsirkan nilai kurang dari atau sama dengan nol. Jadi itu semacam kontradiksi dengan dirinya sendiri di sana ...
Matthijs Wessels
Saya tidak tahu detailnya, tetapi nilai-nilai ini berpasangan benar-benar berfungsi di Chrome dan browser lainnya: maxAgeInMinutes * 60, kedaluwarsa.
RoutesMaps.com
1
@MatthijsWessels Tangkapan yang bagus! Saya menggali sedikit lebih dalam, dan kontradiksi yang tampak pada kenyataannya disengaja, seperti dicatat dalam errata di rfc-editor.org/errata/eid3430 . Untuk "memaksimalkan interoperabilitas", agen pengguna harus menafsirkan nol atau negatif Max-Agesebagai tanggal dan waktu yang paling awal yang dapat diwakili, tetapi server dilarang mengirim nilai seperti itu Max-Age. Saya kira penulis tahu tentang kedua klien yang sudah ada yang tidak bisa menangani Max-Age=0dan server yang mengirimnya pada saat mereka menulis spec, dan mencoba untuk mengurangi masalah dari kedua ujungnya.
Mark Amery
@ Crimean.us saya juga tidak bisa menyalahkan. Mungkin saya melakukan sesuatu yang salah
Matthijs Wessels
@MatthijsWessels Masalah dengan mengabaikan Max-Age = 0 diperbaiki dalam contoh saya dengan menetapkan tanggal kedaluwarsa ke ZonedDateTime.now (). PlusMinutes (maxAgeInMinutes). Untuk maxAgeInMinutes = 0, ini adalah datetime saat ini. Kode ini berfungsi untuk waktu yang lama di aplikasi web yang sebenarnya.
RoutesMaps.com