อักขระที่อนุญาตในทั้งชื่อคุกกี้และค่าคืออะไร พวกเขาเหมือนกันกับ URL หรือบางส่วนย่อยทั่วไป?
เหตุผลที่ฉันถามคือเมื่อเร็ว ๆ นี้ฉันพบพฤติกรรมแปลก ๆ บางอย่างกับคุกกี้ที่มี-
ชื่ออยู่และฉันแค่สงสัยว่าเป็นสิ่งที่เบราว์เซอร์ระบุหรือรหัสของฉันผิด
อักขระที่อนุญาตในทั้งชื่อคุกกี้และค่าคืออะไร พวกเขาเหมือนกันกับ URL หรือบางส่วนย่อยทั่วไป?
เหตุผลที่ฉันถามคือเมื่อเร็ว ๆ นี้ฉันพบพฤติกรรมแปลก ๆ บางอย่างกับคุกกี้ที่มี-
ชื่ออยู่และฉันแค่สงสัยว่าเป็นสิ่งที่เบราว์เซอร์ระบุหรือรหัสของฉันผิด
คำตอบ:
คนนี้เป็นกุ๊กกิ๊ก:
คุณอาจคิดว่ามันควรจะเป็น แต่จริงๆแล้วมันไม่ได้เลย!
อักขระที่อนุญาตในทั้งชื่อคุกกี้และค่าคืออะไร
ตาม Netscape cookie_specโบราณNAME=VALUE
สตริงทั้งหมดคือ:
ลำดับของอักขระที่ไม่รวมเซมิโคลอนเครื่องหมายจุลภาคและ white space
ดังนั้น-
ควรใช้งานได้และดูเหมือนว่าจะใช้ได้ในเบราว์เซอร์ที่ฉันได้มาที่นี่ คุณมีปัญหากับที่ไหน
โดยนัยจากข้างต้น:
=
ถูกกฎหมายที่จะรวมถึง แต่อาจคลุมเครือ เบราว์เซอร์จะแบ่งชื่อและค่าบน=
สัญลักษณ์แรกในสตริงเสมอดังนั้นในทางปฏิบัติคุณสามารถใส่=
สัญลักษณ์ในค่าได้ แต่ไม่ใช่ชื่อสิ่งที่ไม่ได้กล่าวถึงเนื่องจาก Netscape แย่มากในการเขียนรายละเอียด แต่ดูเหมือนว่าจะได้รับการสนับสนุนอย่างต่อเนื่องโดยเบราว์เซอร์:
NAME หรือ VALUE อาจเป็นสตริงว่างเปล่า
ถ้าไม่มี=
สัญลักษณ์ในสตริงที่ทุกเบราว์เซอร์รักษามันเป็นคุกกี้ที่มีชื่อเปล่าสตริงคือเป็นเช่นเดียวกับSet-Cookie: foo
Set-Cookie: =foo
เมื่อเบราว์เซอร์แสดงคุกกี้ที่มีชื่อว่างเปล่ามันจะตัดเครื่องหมายเท่ากับ ดังนั้นbegetsSet-Cookie: =bar
Cookie: bar
เครื่องหมายจุลภาคและช่องว่างในชื่อและค่าดูเหมือนจริงจะใช้งานได้แม้ว่าช่องว่างรอบเครื่องหมายเท่ากับจะถูกตัดแต่ง
ตัวควบคุม ( \x00
การ\x1F
บวก\x7F
) จะไม่ได้รับอนุญาต
สิ่งที่ไม่ได้กล่าวถึงและเบราว์เซอร์ไม่สอดคล้องกันโดยสิ้นเชิงคืออักขระที่ไม่ใช่ ASCII (Unicode):
ดังนั้นในทางปฏิบัติคุณไม่สามารถใช้อักขระที่ไม่ใช่ ASCII ในคุกกี้ได้เลย หากคุณต้องการใช้ Unicode, รหัสควบคุมหรือลำดับไบต์อื่น ๆ cookie_spec ต้องการให้คุณใช้รูปแบบการเข้ารหัสแบบ ad-hoc ที่คุณเลือกเองและแนะนำการเข้ารหัส URL (ตามที่ผลิตโดย JavaScript encodeURIComponent
) เป็นตัวเลือกที่สมเหตุสมผล
ในแง่ของมาตรฐานที่เกิดขึ้นจริงมีความพยายามสองสามครั้งที่จะประมวลผลพฤติกรรมของคุกกี้
RFC 2109เป็นความพยายามในการแปลงรหัสและแก้ไข Netscape cookie_spec ดั้งเดิม ในหลายมาตรฐานตัวอักษรพิเศษมากขึ้นนี้จะไม่ได้รับอนุญาตที่จะใช้RFC 2616ราชสกุล (ก-
จะยังคงได้รับอนุญาตให้มี) และมีเพียงค่าอาจจะระบุไว้ในที่ยกสตริงกับตัวละครอื่น ๆ ไม่มีเบราว์เซอร์ใดที่ใช้งานข้อ จำกัด การจัดการสตริงและคำยกเว้นแบบพิเศษที่ยกมาหรือคุณสมบัติใหม่ในข้อมูลจำเพาะนี้
RFC 2965เป็นอีกสิ่งหนึ่งที่สามารถจัดการได้ถึง 2109 รายการและเพิ่มคุณสมบัติเพิ่มเติมภายใต้รูปแบบ 'คุกกี้รุ่น 2' ไม่มีใครเคยทำเช่นนั้นมาก่อน ข้อมูลจำเพาะนี้มีข้อ จำกัด โทเค็นและสตริงที่อ้างอิงเหมือนกับรุ่นก่อนหน้าและเป็นเพียงเรื่องไร้สาระมากมาย
RFC 6265เป็นความพยายามในยุค HTML5 ในการแก้ไขปัญหาทางประวัติศาสตร์ มันยังไม่ตรงกับความเป็นจริง แต่มันก็ยังดีกว่าความพยายามก่อนหน้านี้ - อย่างน้อยก็เป็นเซตย่อยที่เหมาะสมของสิ่งที่เบราว์เซอร์รองรับไม่แนะนำไวยากรณ์ใด ๆ ที่ควรจะใช้งานได้ แต่ไม่เหมือน .
ใน 6265 ชื่อคุกกี้ยังคงถูกระบุเป็น RFC 2616 token
ซึ่งหมายความว่าคุณสามารถเลือกได้จากตัวอักษรบวก:
!#$%&'*+-.^_`|~
ในค่าคุกกี้มันจะแบนตัวควบคุม (กรองโดยเบราว์เซอร์) อย่างเป็นทางการและอักขระที่ไม่ใช่ ASCII มันยังคงมีข้อห้ามของ cookie_spec ในช่องว่างเครื่องหมายจุลภาคและเซมิโคลอนรวมถึงความเข้ากันได้กับไอดีที่ไม่ดีที่ใช้ RFCs ก่อนหน้านี้มันยังห้ามแบ็กสแลชและเครื่องหมายคำพูดนอกเหนือจากเครื่องหมายคำพูดที่ตัดค่าทั้งหมด ค่าไม่ใช่รูปแบบการเข้ารหัส) ดังนั้นนั่นจะทำให้คุณมีตัวอักษรผสมบวก:
!#$%&'()*+-./:<=>?@[]^_`{|}~
ในโลกแห่งความเป็นจริงเรายังคงใช้ Netscape cookie_spec ดั้งเดิมและที่เลวร้ายที่สุดดังนั้นรหัสที่ใช้คุกกี้ควรเตรียมพร้อมที่จะพบกับสิ่งใดมาก แต่สำหรับรหัสที่ผลิตคุกกี้ขอแนะนำให้ติดกับชุดย่อยใน RFC 6265
Name="Va;lue"; max-age...
ค่าทั้งหมดจะต้องมีการยกสตริงดังนั้นจึงจะต้องมีการ มันไม่ทำงานในเบราว์เซอร์และไม่ได้รับอนุญาตใน RFC 6265 ซึ่งเสนอให้แทนที่ 2965 และพยายามสะท้อนความเป็นจริงให้ดีขึ้น
ใน ASP.Net คุณสามารถใช้System.Web.HttpUtility
เข้ารหัสค่าคุกกี้ได้อย่างปลอดภัยก่อนที่จะเขียนลงในคุกกี้และแปลงกลับเป็นรูปแบบดั้งเดิมเมื่ออ่านออก
// Encode
HttpUtility.UrlEncode(cookieData);
// Decode
HttpUtility.UrlDecode(encodedCookieData);
สิ่งนี้จะหยุดเครื่องหมายและเครื่องหมายเท่ากับการแบ่งค่าเป็นคู่ของชื่อ / ค่าตามที่เขียนลงในคุกกี้
ฉันคิดว่ามันเป็นเบราว์เซอร์ที่เฉพาะเจาะจงโดยทั่วไป เพื่อให้ปลอดภัยโดย base64 เข้ารหัสวัตถุ JSON และเก็บทุกอย่างไว้ในนั้น ด้วยวิธีนี้คุณเพียงแค่ต้องถอดรหัสและวิเคราะห์ JSON อักขระทั้งหมดที่ใช้ใน base64 ควรเล่นได้ดีที่สุดหากไม่ใช่เบราว์เซอร์ทั้งหมด
นี่มันเป็นในขณะที่คำไม่กี่คำที่เป็นไปได้ มุ่งเน้นไปที่ตัวละครที่ไม่ต้องการหลบหนี:
สำหรับคุ๊กกี้:
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!#$%&'()*+-./:<>?@[]^_`{|}~
สำหรับ URL
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789.-_~!$&'()*+,;=:@
สำหรับคุกกี้และ URL (สี่แยก)
abdefghijklmnqrstuvxyzABDEFGHIJKLMNQRSTUVXYZ0123456789!$&'()*+-.:@_~
นั่นคือวิธีที่คุณตอบ
โปรดทราบว่าสำหรับคุกกี้นั้นจะมีการลบ=เนื่องจากมักจะใช้เพื่อตั้งค่าคุกกี้
สำหรับ URL นี้ = ถูกเก็บไว้ เห็นได้ชัดว่าแยกได้โดยไม่ต้อง
var chars = "abdefghijklmnqrstuvxyz"; chars += chars.toUpperCase() + "0123456789" + "!$&'()*+-.:@_~";
ปรากฎว่าการหลบหนียังคงเกิดขึ้นและเกิดขึ้นโดยไม่คาดคิดโดยเฉพาะในสภาพแวดล้อมคุกกี้ Java ซึ่งคุกกี้ถูกห่อด้วยเครื่องหมายคำพูดคู่หากพบอักขระตัวสุดท้าย
เพื่อความปลอดภัยเพียงใช้ A-Za-z1-9 นั่นคือสิ่งที่ฉันจะทำ
ใหม่กว่าrfc6265เผยแพร่ในเดือนเมษายน 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
หากคุณดู@bobinceตอบคุณจะเห็นว่าข้อ จำกัด ที่ใหม่กว่าเข้มงวดกว่านี้
คุณไม่สามารถใส่ ";" ในฟิลด์ค่าของคุกกี้ชื่อที่จะตั้งเป็นสตริงจนถึง ";" ในเบราว์เซอร์ส่วนใหญ่ ...
ข้อกำหนดของคุกกี้มี 2 รุ่น
1. คุกกี้รุ่น 0 คุกกี้ aka Netscape,
2. รุ่นที่ 1 หรือที่เรียกว่าคุกกี้ RFC 2965
ในรุ่น 0 ชื่อและส่วนค่าของคุกกี้คือลำดับของอักขระไม่รวมอัฒภาค, เครื่องหมายจุลภาค, เครื่องหมายเท่ากับและช่องว่าง ถ้าไม่ได้ใช้กับอัญประกาศคู่
รุ่น 1 มีความซับซ้อนมากขึ้นคุณสามารถตรวจสอบได้ที่นี่
ในรายละเอียดรุ่นสำหรับส่วนค่าชื่อเกือบจะเหมือนกันยกเว้นชื่อไม่สามารถเริ่มต้นด้วย $ sign
มีปัญหาอื่นที่น่าสนใจเกี่ยวกับ IE และ Edge ดูเหมือนว่าคุกกี้ที่มีชื่อที่มีระยะเวลามากกว่า 1 รอบจะถูกลบอย่างเงียบ ๆ ดังนั้นวิธีนี้ใช้งานได้:
cookie_name_a = valuea
ขณะนี้จะลดลง
cookie.name.a = valuea
มันง่ายมาก:
<cookie-name> สามารถเป็นอักขระ US-ASCII ใดก็ได้ยกเว้นอักขระควบคุม (CTLs), ช่องว่างหรือแท็บ และต้องไม่มีอักขระตัวคั่นดังนี้: () <> @,; : \ "/ []? = {}
<cookie-value> สามารถตั้งค่าเป็นเครื่องหมายคำพูดคู่และตัวอักษร US-ASCII ใด ๆ ที่ไม่รวม CTL, ช่องว่าง, เครื่องหมายคำพูดคู่, เครื่องหมายจุลภาค, เครื่องหมายอัฒภาคและเครื่องหมายแบ็กสแลชได้ การเข้ารหัส: การนำไปใช้งานจำนวนมากทำการเข้ารหัส URL บนค่าคุกกี้อย่างไรก็ตามไม่จำเป็นต้องใช้ตามข้อกำหนด RFC มันช่วยให้เป็นไปตามข้อกำหนดเกี่ยวกับตัวละครที่ได้รับอนุญาต
Link: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives
อีกหนึ่งข้อพิจารณา ฉันเพิ่งใช้รูปแบบที่ข้อมูลสำคัญบางอย่างโพสต์ไปยังสคริปต์ PHP ที่จำเป็นในการแปลงและส่งคืนเป็นคุกกี้ที่เข้ารหัสซึ่งใช้ค่า base64 ทั้งหมดที่ฉันคิดว่ารับประกันว่า "ปลอดภัย" ดังนั้นฉันจึงเข้ารหัสรายการข้อมูลโดยใช้ RC4 ผลลัพธ์ผ่าน base64_encode และนำคุกกี้กลับมาที่เว็บไซต์อย่างมีความสุขการทดสอบดูเหมือนจะทำได้ดีจนกระทั่งสตริงที่เข้ารหัส base64 มีสัญลักษณ์ "+" สตริงถูกเขียนลงในหน้าคุกกี้โดยไม่มีปัญหาการใช้การวินิจฉัยเบราว์เซอร์ที่ฉันสามารถทำได้ ตรวจสอบว่าคุกกี้ถูกเขียนไม่เปลี่ยนแปลงจากนั้นเมื่อหน้าถัดมาเรียกว่า PHP ของฉันและรับคุกกี้ผ่านอาร์เรย์ $ _COOKIE ฉันก็ติดขัดเพื่อค้นหาสตริงที่ตอนนี้ไม่มีเครื่องหมาย "+" ทุกตัวของอักขระนั้นถูกแทนที่ด้วย พื้นที่ ASCII
เมื่อพิจารณาถึงจำนวนข้อร้องเรียนที่ไม่ได้รับการแก้ไขที่คล้ายกันที่ฉันได้อ่านอธิบายสถานการณ์นี้ตั้งแต่นั้นมามักจะอ้างอิงจำนวนมากเพื่อใช้ base64 กับ "ปลอดภัย" จัดเก็บข้อมูลโดยพลการในคุกกี้ฉันคิดว่าฉันจะชี้ปัญหา
หลังจากที่คุณทำการเข้ารหัสที่คุณต้องการทำกับข้อมูลแล้วใช้ base64_encode เพื่อทำให้มัน "ปลอดภัยสำหรับคุกกี้" ให้รันสตริงเอาต์พุตผ่านสิ่งนี้ ...
// 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;
}
ที่นี่ฉันเพียงแค่แทนที่ "+" (และฉันตัดสินใจ "=" เช่นกัน) ด้วยอักขระ "คุกกี้ปลอดภัย" อื่น ๆ ก่อนที่จะส่งคืนค่าที่เข้ารหัสไปยังหน้าเพื่อใช้เป็นคุกกี้ โปรดทราบว่าความยาวของสตริงที่ประมวลผลไม่เปลี่ยนแปลง เมื่อหน้าเดียวกัน (หรืออีกหน้าหนึ่งบนไซต์) เรียกใช้สคริปต์ PHP ของฉันอีกครั้งฉันจะสามารถกู้คืนคุกกี้นี้ได้โดยไม่ขาดอักขระ ฉันต้องจำไว้ว่าให้ส่งคุกกี้กลับผ่าน fix64 () สายเดียวที่ฉันสร้างขึ้นและจากนั้นฉันสามารถถอดรหัสได้ด้วย base64_decode ปกติ () ตามด้วยการถอดรหัสอื่น ๆ ในแบบแผนของคุณ
อาจมีการตั้งค่าบางอย่างที่ฉันสามารถทำได้ใน PHP ที่อนุญาตให้ base64 สตริงที่ใช้ในคุกกี้เพื่อถ่ายโอนกลับไปที่ PHP โดยไม่มีความเสียหาย ในช่วงเวลานี้ได้ผล "+" อาจเป็นค่าคุกกี้ "ถูกกฎหมาย" แต่หากคุณมีความปรารถนาที่จะสามารถส่งสตริงดังกล่าวกลับไปที่ PHP (ในกรณีของฉันผ่านอาร์เรย์ $ _COOKIE) ฉันขอแนะนำให้ประมวลผลอีกครั้งเพื่อลบ อักขระที่ละเมิดและกู้คืนได้หลังจากการกู้คืน มีตัวเลือก "ปลอดภัยคุกกี้" อื่น ๆ อีกมากมายให้เลือก
หากคุณใช้ตัวแปรในภายหลังคุณจะพบว่าสิ่งที่ชอบpath
จริง ๆ จะทำให้อักขระเน้นเสียงผ่านได้ แต่จริง ๆ แล้วจะไม่ตรงกับเส้นทางเบราว์เซอร์ สำหรับสิ่งที่คุณต้อง URIEncode พวกเขา ดังนั้นเช่นนี้:
const encodedPath = encodeURI(myPath);
document.cookie = `use_pwa=true; domain=${location.host}; path=${encodedPath};`
ตัวอักษร "ที่อนุญาต" อาจมีมากกว่าในสเป็ค แต่คุณควรอยู่ในข้อมูลจำเพาะและใช้สตริงที่เข้ารหัส URI เพื่อความปลอดภัย
หลายปีที่ผ่านมา MSIE 5 หรือ 5.5 (และอาจเป็นได้ทั้งคู่) มีปัญหาร้ายแรงที่มี "-" ในบล็อก HTML หากคุณเชื่อ แม้ว่ามันจะไม่เกี่ยวข้องโดยตรงเนื่องจากเราเก็บ MD5 แฮช (ที่มีตัวอักษรและตัวเลขเท่านั้น) ในคุกกี้เพื่อค้นหาทุกอย่างในฐานข้อมูลฝั่งเซิร์ฟเวอร์
ฉันลงเอยด้วยการใช้
cookie_value = encodeURIComponent(my_string);
และ
my_string = decodeURIComponent(cookie_value);
ดูเหมือนว่าจะใช้ได้กับตัวละครทุกประเภท ฉันมีปัญหาแปลก ๆ อย่างอื่นแม้จะมีตัวละครที่ไม่ใช่อัฒภาคหรือคอมมา
;
อักขระได้ตราบใดที่มันล้อมรอบด้วยเครื่องหมายคำพูดคู่หรือไม่ เป็นเช่นนี้:Set-Cookie: Name=Va";"lue; Max-Age=3600