Apa karakter yang diizinkan dalam cookie?

301

Apa saja karakter yang diizinkan dalam nama dan nilai cookie? Apakah sama dengan URL atau subset umum?

Alasan yang saya tanyakan adalah bahwa saya baru-baru ini menemukan beberapa perilaku aneh dengan cookie yang ada -dalam namanya dan saya hanya ingin tahu apakah itu sesuatu yang spesifik peramban atau jika kode saya salah.

Esko
sumber

Jawaban:

391

ini quickie:

Anda mungkin berpikir itu seharusnya, tetapi sebenarnya tidak sama sekali!

Apa saja karakter yang diizinkan dalam nama dan nilai cookie?

Menurut cookie_spec Netscape kuno seluruh NAME=VALUEstring adalah:

urutan karakter tidak termasuk titik koma, koma, dan spasi putih.

Jadi -seharusnya bekerja, dan sepertinya OK di browser saya sudah sampai di sini; di mana Anda mengalami masalah dengan itu?

Dengan implikasi dari hal di atas:

  • =legal untuk dimasukkan, tetapi berpotensi ambigu. Browser selalu membagi nama dan nilai pada =simbol pertama dalam string, jadi dalam praktiknya Anda dapat menempatkan =simbol di VALUE tetapi tidak pada NAME.

Apa yang tidak disebutkan, karena Netscape sangat buruk dalam menulis spesifikasi, tetapi tampaknya secara konsisten didukung oleh browser:

  • NAME atau VALUE mungkin berupa string kosong

  • jika tidak ada =simbol dalam string sama sekali, browser memperlakukannya sebagai cookie dengan nama string-kosong, yaitu Set-Cookie: foosama dengan Set-Cookie: =foo.

  • ketika browser menampilkan cookie dengan nama kosong, mereka menghilangkan tanda sama dengan. Jadi Set-Cookie: =barpinta Cookie: bar.

  • koma dan spasi dalam nama dan nilai tampaknya benar-benar berfungsi, meskipun ruang di sekitar tanda sama dipangkas

  • kontrol karakter ( \x00ke \x1Fplus \x7F) tidak diizinkan

Yang tidak disebutkan dan peramban yang sepenuhnya tidak konsisten adalah karakter non-ASCII (Unicode):

  • di Opera dan Google Chrome, mereka dikodekan ke header Cookie dengan UTF-8;
  • di IE, halaman kode default mesin digunakan (khusus lokal dan tidak pernah UTF-8);
  • Firefox (dan browser berbasis Mozilla lainnya) menggunakan byte rendah dari masing-masing titik kode UTF-16 sendiri (jadi ISO-8859-1 tidak apa-apa tetapi yang lainnya hancur);
  • Safari menolak untuk mengirim cookie apa pun yang mengandung karakter non-ASCII.

jadi dalam praktiknya Anda tidak dapat menggunakan karakter non-ASCII di cookie sama sekali. Jika Anda ingin menggunakan Unicode, kode kontrol atau urutan byte sewenang-wenang lainnya, cookie_spec menuntut Anda menggunakan skema pengkodean ad-hoc yang Anda pilih sendiri dan menyarankan pengkodean URL (seperti yang diproduksi oleh JavaScript encodeURIComponent) sebagai pilihan yang wajar.

Dalam hal standar aktual , ada beberapa upaya untuk menyusun perilaku cookie, tetapi sejauh ini tidak ada yang benar-benar mencerminkan dunia nyata.

  • RFC 2109 adalah upaya untuk mengkodifikasi dan memperbaiki cookie_spec Netscape asli. Dalam standar ini banyak karakter khusus lagi yang dianulir, karena menggunakan RFC 2616 token (a -adalah masih diperbolehkan ada), dan hanya nilai dapat ditentukan dalam dikutip-string dengan karakter lain. Tidak ada browser yang menerapkan batasan, penanganan khusus dari string dan pelarian yang dikutip, atau fitur baru dalam spesifikasi ini.

  • RFC 2965 lain dalam hal ini, merapikan 2109 dan menambahkan lebih banyak fitur di bawah skema 'cookie versi 2'. Tidak ada yang pernah menerapkan semua itu. Spesifikasi ini memiliki batasan token-dan-dikutip-string yang sama dengan versi sebelumnya dan itu sama banyaknya dengan omong kosong.

  • RFC 6265 adalah upaya HTML5-era untuk membersihkan kekacauan sejarah. Itu masih tidak cocok dengan kenyataan, tetapi itu jauh lebih baik daripada upaya sebelumnya — itu setidaknya bagian yang tepat dari apa yang didukung browser, tidak memperkenalkan sintaks yang seharusnya berfungsi tetapi tidak (seperti string yang dikutip sebelumnya) .

Di 6265 nama cookie masih ditentukan sebagai RFC 2616 token, yang berarti Anda dapat memilih dari alfanumer plus:

!#$%&'*+-.^_`|~

Dalam nilai cookie itu secara formal melarang karakter kontrol (difilter oleh browser) dan (non-ASCII karakter) yang diimplementasikan. Ini mempertahankan larangan cookie_spec pada ruang, koma, dan titik koma, ditambah untuk kompatibilitas dengan orang idiot miskin yang benar-benar menerapkan RFC sebelumnya, ia juga melarang backslash dan kutipan, selain dari kutipan yang membungkus seluruh nilai (tetapi dalam hal itu kutipan masih dianggap sebagai bagian dari nilai, bukan skema penyandian). Sehingga meninggalkan Anda dengan alfanumer plus:

!#$%&'()*+-./:<=>?@[]^_`{|}~

Di dunia nyata kita masih menggunakan Netscape cookie_spec asli-dan-terburuk, jadi kode yang mengkonsumsi cookie harus siap menghadapi banyak hal, tetapi untuk kode yang menghasilkan cookie disarankan untuk tetap menggunakan subset di RFC 6265.

bobince
sumber
@bobince Maksud Anda RFC menyatakan bahwa nilai cookie dapat memiliki ;karakter selama dikelilingi oleh tanda kutip ganda? Dengan demikian:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier
@ Peracerier: seluruh nilai harus menjadi string yang dikutip, jadi itu harus Name="Va;lue"; max-age.... Itu tidak bekerja di browser dan itu tidak diizinkan di RFC 6265, yang diusulkan untuk menggantikan 2965 dan mencoba untuk mencerminkan kenyataan sedikit lebih baik.
bobince
@obobince - Saya tahu ini sudah lama, tetapi apakah saya membaca jawaban Anda dengan benar berarti bahwa spasi tidak diizinkan secara teknis dalam nilai cookie? "tidak termasuk titik koma, koma, dan ruang putih " [penekanan milikku]
Adam Rackis
1
@Adam: Ya, jika Anda menggunakan spesifikasi Netscape atau RFC 6265, spasi putih tidak diizinkan dalam nilai cookie mentah (tidak DQUOTEd). Meskipun demikian tidak berfungsi di browser saya sudah mencoba, tetapi saya tidak akan bergantung padanya.
bobince
2
RFC 6265 mendefinisikan token sebagai 1*<any CHAR except CTLs or separators>dan pemisah yang (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPdan HT, sehingga nama cookie harus alphanums ditambah!#$%&'*+-.?^_`|~
Gan Quan
28

Di ASP.Net, Anda dapat menggunakannya System.Web.HttpUtilityuntuk menyandikan nilai cookie dengan aman sebelum menulis ke cookie dan mengubahnya kembali ke bentuk aslinya saat membacanya.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Ini akan menghentikan ampersand dan sama dengan tanda-tanda yang membagi nilai menjadi sekelompok pasangan nama / nilai saat ditulis ke cookie.

stephen
sumber
1
Hanya satu catatan, secara internal asp.net menggunakan pengkodean hex alih-alih UrlEncode saat menyimpan cookie otentikasi. Referenceource.microsoft.com # System.Web / Security / ... jadi mungkin ada beberapa kasus di mana url encode tidak akan memotongnya?
Peter
17

Saya pikir ini umumnya browser spesifik. Untuk berada di sisi aman, base64 menyandikan objek JSON, dan menyimpan segala sesuatu di dalamnya. Dengan begitu Anda hanya perlu men-decode dan mengurai JSON. Semua karakter yang digunakan dalam base64 harus bermain baik dengan sebagian besar, jika tidak semua browser.

Jamie Rumbelow
sumber
Jawaban ini tampaknya menjadi jawaban yang konsisten di seluruh browser. Saya menyadari ini setelah bekerja berjam-jam mencoba untuk mendapatkan solusi cepat: Saya juga tidak mendapatkannya. Lakukan saja seperti yang disarankan tepat di atas untuk menyelamatkan diri dari kerepotan.
tersenyumlah
Tidak mencoba ini, tetapi saya membaca posting lain tentang pepatah ini yang mengatakan base64 encode hanya berfungsi dengan karakter ascii.
user984003
11

Ini dia, sesedikit mungkin kata-kata . Fokus pada karakter yang tidak perlu melarikan diri:

Untuk kue kering:

abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!#$%&'()*+-./:<>?@[]^_`{|}~

Untuk url

abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789.-_~!$&'()*+,;=:@

Untuk cookie dan url (persimpangan)

abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!$&'()*+-.:@_~

Itulah jawaban Anda.

Perhatikan bahwa untuk cookie, = telah dihapus karena biasanya digunakan untuk menetapkan nilai cookie.

Untuk url ini = disimpan. Persimpangan jelas tanpa.

var chars = "abdefghijklmnqrstuvxyz"; chars += chars.toUpperCase() + "0123456789" + "!$&'()*+-.:@_~";

Ternyata melarikan diri masih terjadi dan tidak terduga terjadi, terutama di lingkungan cookie Java di mana cookie dibungkus dengan tanda kutip ganda jika bertemu dengan karakter terakhir.

Jadi agar aman, cukup gunakan A-Za-z1-9. Itu yang akan saya lakukan.

mmm
sumber
Safari Cookies adalah satu-satunya browser masalah saya - semua browser lain berfungsi dengan baik. Saya harus UrlEncode dan UrlDecode cookie saya untuk menangani tanda dan spasi = yang sama. Seperti Base64Encode di Cookie. (Hanya Safari yang diperlukan ini - browser lain berfungsi baik dengan dan tanpa cookie yang disandikan.)
Sql Surfer
Lebih baik jika Anda mencantumkan sumber apa yang mengarah ke jawaban Anda!
Loc
1
@ Lokasi Lebih dari 3 jam uji coba dan inspeksi.
mmm
10

Rfc6265 yang lebih baru diterbitkan pada bulan April 2011:

cookie-header = "Cookie:" OWS cookie-string OWS
cookie-string = cookie-pair *( ";" SP cookie-pair )
cookie-pair  = cookie-name "=" cookie-value
cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )

cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
                   ; US-ASCII characters excluding CTLs,
                   ; whitespace DQUOTE, comma, semicolon,
                   ; and backslash

Jika Anda melihat jawaban @bobince, Anda melihat bahwa pembatasan yang lebih baru lebih ketat.

gavenkoa
sumber
6

Anda tidak bisa memasukkan ";" di bidang nilai cookie, nama yang akan ditetapkan adalah string hingga ";" di sebagian besar browser ...

hagay onn
sumber
1

Ada 2 versi spesifikasi cookie
1. Cookie versi 0 alias cookie Netscape,
2. Versi 1 alias cookie RFC 2965
Dalam versi 0 Nama dan nilai cookie adalah urutan karakter, tidak termasuk tanda titik koma, koma, tanda sama dengan, dan spasi putih , jika tidak digunakan dengan tanda kutip ganda
versi 1 jauh lebih rumit, Anda dapat memeriksanya di sini.
Dalam versi ini spesifikasi untuk bagian nilai nama hampir sama kecuali nama tidak dapat dimulai dengan $ tanda

Tinku
sumber
Di mana dikatakan bahwa nilai harus mengecualikan sama dengan masuk versi 0?
Gili
1

Ada masalah lain yang menarik dengan IE dan Edge. Cookie yang memiliki nama dengan lebih dari 1 periode nampaknya diam-diam dihapus. Jadi ini berfungsi:

cookie_name_a = valuea

sementara ini akan turun

cookie.name.a = valuea

Arvoreen
sumber
Akan lebih bagus jika Anda menambahkan versi peramban yang tepat agar kami dapat mereplikasi, karena perilaku peramban tidak konsisten pada cookie.
Gerald
0

itu sederhana:

<cookie-name> dapat berupa karakter US-ASCII kecuali karakter kontrol (CTL), spasi, atau tab. Itu juga tidak boleh mengandung karakter pemisah seperti berikut: () <> @,; : \ "/ []? = {}.

<cookie-value> secara opsional dapat diatur dalam tanda kutip ganda dan karakter US-ASCII apa pun termasuk CTL, spasi putih, tanda kutip ganda, koma, titik koma, titik koma, dan garis miring terbalik diperbolehkan. Pengkodean: Banyak implementasi melakukan pengodean URL pada nilai cookie, namun itu tidak diperlukan sesuai spesifikasi RFC. Itu membantu memuaskan persyaratan tentang karakter mana yang diperbolehkan.

Tautan: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives

webolizzer
sumber
0

Satu pertimbangan lagi. Saya baru-baru ini menerapkan skema di mana beberapa data sensitif diposting ke skrip PHP perlu untuk mengkonversi dan mengembalikannya sebagai cookie terenkripsi, yang menggunakan semua nilai base64 yang saya pikir dijamin 'aman ". Jadi saya patuh mengenkripsi item data menggunakan RC4, berlari output melalui base64_encode, dan dengan senang hati mengembalikan cookie ke situs. Pengujian tampaknya berjalan dengan baik sampai string base64 yang dikodekan mengandung simbol "+". String ditulis ke cookie halaman tanpa masalah. Menggunakan diagnosa browser saya juga bisa memverifikasi cookie ditulis tidak berubah. Kemudian ketika halaman berikutnya memanggil PHP saya dan memperoleh cookie melalui $ _COOKIE array, saya tergagap untuk menemukan string sekarang hilang tanda "+". Setiap kemunculan karakter itu diganti dengan Ruang ASCII.

Mempertimbangkan berapa banyak keluhan serupa yang belum terselesaikan yang saya baca menggambarkan skenario ini sejak itu, sering mencari berbagai referensi untuk menggunakan base64 untuk "dengan aman" menyimpan data sewenang-wenang dalam cookie, saya pikir saya akan menunjukkan masalahnya dan menawarkan solusi yang saya anggap kumuh.

Setelah Anda melakukan enkripsi apa pun yang ingin Anda lakukan pada sepotong data, dan kemudian menggunakan base64_encode untuk membuatnya "cookie-safe", jalankan string keluaran melalui ini ...

// from browser to PHP. substitute troublesome chars with 
// other cookie safe chars, or vis-versa.  

function fix64($inp) {
    $out =$inp;
    for($i = 0; $i < strlen($inp); $i++) {
        $c = $inp[$i];
        switch ($c) {
            case '+':  $c = '*'; break; // definitly won't transfer!
            case '*':  $c = '+'; break;

            case '=':  $c = ':'; break; // = symbol seems like a bad idea
            case ':':  $c = '='; break;

            default: continue;
            }
        $out[$i] = $c;
        }
    return $out;
    }

Di sini saya hanya mengganti "+" (dan saya memutuskan "=" juga) dengan karakter "cookie safe" lainnya, sebelum mengembalikan nilai yang disandikan ke halaman, untuk digunakan sebagai cookie. Perhatikan bahwa panjang string yang sedang diproses tidak berubah. Ketika halaman yang sama (atau halaman lain di situs) menjalankan skrip PHP saya lagi, saya akan dapat memulihkan cookie ini tanpa karakter yang hilang. Saya hanya perlu ingat untuk meneruskan cookie kembali melalui panggilan fix64 () yang saya buat, dan dari sana saya dapat mendekode dengan base64_decode () biasa, diikuti oleh dekripsi apa pun lainnya dalam skema Anda.

Mungkin ada beberapa pengaturan yang bisa saya buat di PHP yang memungkinkan string base64 yang digunakan dalam cookie untuk ditransfer kembali ke PHP tanpa korupsi. Sementara itu, ini bekerja. "+" Mungkin nilai cookie "legal", tetapi jika Anda memiliki keinginan untuk dapat mengirimkan string seperti itu kembali ke PHP (dalam kasus saya melalui array $ _COOKIE), saya menyarankan pemrosesan ulang untuk menghapus menyinggung karakter, dan mengembalikannya setelah pemulihan. Ada banyak karakter "cookie aman" lainnya untuk dipilih.

Randy
sumber
0

Jika Anda menggunakan variabel nanti, Anda akan menemukan bahwa hal-hal seperti pathsebenarnya akan membiarkan karakter beraksen melewatinya, tetapi itu tidak akan benar-benar cocok dengan jalur browser. Untuk itu Anda perlu URIEncode mereka. Jadi seperti ini:

  const encodedPath = encodeURI(myPath);
  document.cookie = `use_pwa=true; domain=${location.host}; path=${encodedPath};`

Jadi karakter "diizinkan", mungkin lebih dari yang ada di spec. Tetapi Anda harus tetap dalam spesifikasi, dan menggunakan string yang dikodekan-URI agar aman.

odinho - Velmont
sumber
-1

Bertahun-tahun yang lalu, MSIE 5 atau 5.5 (dan mungkin keduanya) memiliki beberapa masalah serius dengan tanda "-" di blok HTML jika Anda percaya. Meskipun ini tidak terkait langsung, sejak kami menyimpan hash MD5 (hanya berisi huruf dan angka) di cookie untuk mencari segala sesuatu yang lain dalam database sisi server.

FYA
sumber
-2

Saya akhirnya menggunakan

cookie_value = encodeURIComponent(my_string);

dan

my_string = decodeURIComponent(cookie_value);

Itu tampaknya bekerja untuk semua jenis karakter. Sebaliknya, saya memiliki masalah aneh, bahkan dengan karakter yang bukan titik koma atau koma.

pengguna984003
sumber