Các ký tự được phép trong cookie là gì?


301

Các ký tự được phép trong cả tên và giá trị cookie là gì? Chúng có giống như URL hoặc một số tập hợp con phổ biến không?

Lý do tôi hỏi là gần đây tôi đã gặp phải một số hành vi lạ với các cookie có -tên của họ và tôi chỉ tự hỏi liệu đó có phải là một trình duyệt cụ thể hay mã của tôi bị lỗi.

Câu trả lời:


391

Đây là một quickie:

Bạn có thể nghĩ rằng nó nên, nhưng thực sự nó không phải là tất cả!

Các ký tự được phép trong cả tên và giá trị cookie là gì?

Theo cookie_spec cổ của Netscape , toàn bộ NAME=VALUEchuỗi là:

một chuỗi các ký tự không bao gồm dấu chấm phẩy, dấu phẩy và khoảng trắng.

Vì vậy, -nên hoạt động, và nó có vẻ ổn trong các trình duyệt tôi đã có ở đây; bạn gặp rắc rối với nó ở đâu?

Theo ngụ ý của những điều trên:

  • =là hợp pháp để bao gồm, nhưng có khả năng mơ hồ. Các trình duyệt luôn phân chia tên và giá trị trên =biểu tượng đầu tiên trong chuỗi, vì vậy trong thực tế, bạn có thể đặt một =biểu tượng trong GIÁ TRỊ chứ không phải TÊN.

Những gì không được đề cập, bởi vì Netscape rất tệ trong việc viết thông số kỹ thuật, nhưng dường như được các trình duyệt hỗ trợ một cách nhất quán:

  • TÊN hoặc GIÁ TRỊ có thể là các chuỗi trống

  • nếu không có =ký hiệu nào trong chuỗi, các trình duyệt coi nó là cookie với tên chuỗi rỗng, nghĩa Set-Cookie: foolà giống như Set-Cookie: =foo.

  • khi các trình duyệt xuất một cookie có tên trống, chúng sẽ bỏ qua dấu bằng. Vì vậy, Set-Cookie: =barsinh ra Cookie: bar.

  • dấu phẩy và khoảng trắng trong tên và giá trị thực sự có vẻ hoạt động, mặc dù khoảng trắng xung quanh dấu bằng được cắt bớt

  • ký tự điều khiển ( \x00để \x1Fcộng \x7F) không được phép

Những gì không được đề cập và trình duyệt hoàn toàn không nhất quán, là các ký tự không phải ASCII (Unicode):

  • trong Opera và Google Chrome, chúng được mã hóa thành các tiêu đề Cookie với UTF-8;
  • trong IE, trang mã mặc định của máy được sử dụng (cụ thể theo địa phương và không bao giờ UTF-8);
  • Firefox (và các trình duyệt dựa trên Mozilla khác) sử dụng byte thấp của từng điểm mã UTF-16 (vì vậy ISO-8859-1 vẫn ổn nhưng mọi thứ khác đều bị sai lệch);
  • Safari chỉ từ chối gửi bất kỳ cookie nào chứa các ký tự không phải ASCII.

vì vậy trong thực tế, bạn không thể sử dụng các ký tự không phải ASCII trong cookie. Nếu bạn muốn sử dụng Unicode, mã điều khiển hoặc các chuỗi byte tùy ý khác, cookie_spec yêu cầu bạn sử dụng sơ đồ mã hóa đặc biệt do chính bạn chọn và đề xuất mã hóa URL (do JavaScript tạo ra encodeURIComponent) như một lựa chọn hợp lý.

Về các tiêu chuẩn thực tế , đã có một vài nỗ lực để mã hóa hành vi cookie nhưng không có gì thực sự phản ánh thế giới thực.

  • RFC 2109 là một nỗ lực để mã hóa và sửa lỗi Netscape cookie_spec ban đầu. Trong tiêu chuẩn nhiều ký tự đặc biệt hơn này là không được phép, vì nó sử dụng RFC 2616 tokens (một -vẫn cho phép có), và chỉ có giá trị có thể được quy định trong một trích dẫn dây với các nhân vật khác. Không có trình duyệt nào từng thực hiện các giới hạn, xử lý đặc biệt các chuỗi được trích dẫn và thoát hoặc các tính năng mới trong thông số này.

  • RFC 2965 là một hướng đi khác, thu dọn 2109 và bổ sung thêm nhiều tính năng theo sơ đồ 'cookie phiên bản 2'. Không ai từng thực hiện bất kỳ điều đó. Thông số kỹ thuật này có các giới hạn chuỗi mã thông báo và trích dẫn giống như phiên bản trước đó và nó cũng chỉ là một tải vô nghĩa.

  • RFC 6265 là một nỗ lực trong thời đại HTML5 để dọn dẹp mớ hỗn độn lịch sử. Nó vẫn không khớp chính xác với thực tế nhưng nó tốt hơn nhiều so với những lần thử trước đó, ít nhất nó là một tập hợp con phù hợp với những gì trình duyệt hỗ trợ, không đưa ra bất kỳ cú pháp nào được cho là hoạt động nhưng không (như chuỗi trích dẫn trước đó) .

Trong 6265, tên cookie vẫn được chỉ định là RFC 2616 token, có nghĩa là bạn có thể chọn từ các chữ cái và chữ cái cộng:

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

Trong giá trị cookie, nó chính thức cấm các ký tự điều khiển (được lọc bởi trình duyệt) và các ký tự không phải ASCII (được triển khai không nhất quán). Nó giữ lại sự cấm đoán của cookie_spec đối với không gian, dấu phẩy và dấu chấm phẩy, cộng với việc tương thích với bất kỳ kẻ ngốc nào thực sự thực hiện các RFC trước đó, nó cũng cấm dấu gạch chéo ngược và trích dẫn, ngoài các trích dẫn bao gồm toàn bộ giá trị (nhưng trong trường hợp đó, các trích dẫn vẫn được coi là một phần của giá trị, không phải là sơ đồ mã hóa). Vì vậy, để lại cho bạn các chữ và số cộng:

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

Trong thế giới thực, chúng ta vẫn đang sử dụng cookie_spec Netscape ban đầu và tồi tệ nhất, do đó, mã tiêu thụ cookie nên được chuẩn bị để gặp khá nhiều thứ, nhưng đối với mã tạo ra cookie, nên sử dụng tập hợp con trong RFC 6265.


@bobince Bạn có nghĩa là RFC nói rằng các giá trị cookie có thể có ;ký tự miễn là nó được bao quanh bởi dấu ngoặc kép? Như vậy:Set-Cookie: Name=Va";"lue; Max-Age=3600
Pacerier

@Pacerier: toàn bộ giá trị sẽ phải là một chuỗi trích dẫn, vì vậy nó sẽ phải như vậy Name="Va;lue"; max-age.... Nó không hoạt động trong các trình duyệt và nó không được phép trong RFC 6265, được đề xuất thay thế 2965 và cố gắng phản ánh thực tế tốt hơn một chút.
bobince

@bobince - Tôi biết điều này đã cũ, nhưng tôi có đọc chính xác câu trả lời của bạn để có nghĩa là không gian không được phép về mặt kỹ thuật trong các giá trị cookie không? "Không bao gồm dấu chấm phẩy, dấu phẩy và khoảng trắng " [nhấn mạnh của tôi]
Adam Rackis

1
@Adam: Có, nếu bạn đi theo thông số Netscape hoặc RFC 6265, khoảng trắng không được phép trong giá trị cookie thô (un-DQUOTEd). Tuy nhiên, nó không hoạt động trong các trình duyệt tôi đã thử, nhưng tôi sẽ không dựa vào nó.
bobince

2
RFC 6265 định nghĩa mã thông báo như 1*<any CHAR except CTLs or separators>và dải phân cách là (, ), <, >, @, ,, ;, :, \, ", /, [, ], ?, =, {, }, SPHT , vì vậy các tên cookie nên alphanums cộng!#$%&'*+-.?^_`|~
Gan Quan

28

Trong ASP.Net, bạn có thể sử dụng System.Web.HttpUtilityđể mã hóa giá trị cookie một cách an toàn trước khi ghi vào cookie và chuyển đổi nó trở lại dạng ban đầu khi đọc nó.

// Encode
HttpUtility.UrlEncode(cookieData);

// Decode
HttpUtility.UrlDecode(encodedCookieData);

Điều này sẽ dừng ký hiệu và dấu bằng bằng cách chia một giá trị thành một nhóm các cặp tên / giá trị khi nó được ghi vào cookie.


1
Chỉ cần một lưu ý, nội bộ asp.net sử dụng mã hóa hex thay vì UrlEncode khi lưu trữ cookie xác thực. Tài liệu tham khảoource.microsoft.com # System.Web / Security / Lỗi vì vậy có thể có một số trường hợp mã hóa url không cắt nó?
Peter

17

Tôi nghĩ nó thường là trình duyệt cụ thể. Để đảm bảo an toàn, base64 mã hóa một đối tượng JSON và lưu trữ mọi thứ trong đó. Bằng cách đó, bạn chỉ cần giải mã nó và phân tích JSON. Tất cả các ký tự được sử dụng trong base64 sẽ chơi tốt với hầu hết các trình duyệt, nếu không phải tất cả các trình duyệt.


Câu trả lời này dường như là nhất quán trên các trình duyệt. Tôi nhận ra điều này sau khi làm việc nhiều giờ để cố gắng có được giải pháp nhanh chóng: tôi cũng không nhận được một giải pháp nào. Chỉ cần làm như được đề nghị chính xác ở trên để tiết kiệm cho mình những rắc rối.
cười

Không thử điều này, nhưng tôi đã đọc các bài viết khác về điều này nói rằng mã hóa base64 chỉ hoạt động với các ký tự ascii.
user984003

11

Đây là, trong càng ít từ càng tốt . Tập trung vào các nhân vật không cần thoát:

Cho những cái bánh quy:

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

Cho các url

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

Đối với cookie và url (giao lộ)

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

Đó là cách bạn trả lời.

Lưu ý rằng đối với cookie, = đã bị xóa vì nó thường được sử dụng để đặt giá trị cookie.

Đối với các url này, = được giữ. Giao lộ rõ ​​ràng là không có.

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

Hóa ra việc thoát vẫn xảy ra và bất ngờ xảy ra, đặc biệt là trong môi trường cookie Java nơi cookie được gói bằng dấu ngoặc kép nếu nó gặp các ký tự cuối cùng.

Vì vậy, để an toàn, chỉ cần sử dụng A-Za-z1-9. Đó là những gì tôi sẽ làm.


Safari Cookies là trình duyệt vấn đề duy nhất của tôi - tất cả các trình duyệt khác đều hoạt động tốt. Tôi đã phải UrlEncode và UrlDecode cookie của tôi để xử lý bằng = dấu hiệu và khoảng trắng. Giống như một Base64Encode trong Cookie. (Safari Chỉ yêu cầu điều này - các trình duyệt khác hoạt động tốt với và không có cookie được mã hóa.)
Sql Surfer

Sẽ tốt hơn nếu bạn liệt kê những nguồn dẫn đến câu trả lời của bạn!
Lộc

1
@Loc Hơn 3 giờ dùng thử và kiểm tra.
mmm

10

Mới hơn rfc6265 xuất bản vào tháng 4 năm 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

Nếu bạn xem câu trả lời của @bobince, bạn sẽ thấy rằng các hạn chế mới hơn nghiêm ngặt hơn.


6

bạn không thể đặt ";" trong trường giá trị của cookie, tên sẽ được đặt là chuỗi cho đến dấu ";" trong hầu hết các trình duyệt ...


1

Có 2 phiên bản thông số kỹ thuật của cookie
1. Cookie phiên bản 0 hay còn gọi là cookie Netscape,
2. Phiên bản 1 aka RFC 2965 cookie
Trong phiên bản 0 Phần tên và giá trị của cookie là các chuỗi ký tự, ngoại trừ dấu chấm phẩy, dấu phẩy, dấu bằng và khoảng trắng , nếu không được sử dụng với dấu ngoặc kép
phiên bản 1 thì phức tạp hơn rất nhiều, bạn có thể kiểm tra nó ở đây
Trong phiên bản này, thông số kỹ thuật cho phần giá trị tên gần như giống nhau ngoại trừ tên không thể bắt đầu bằng dấu $


Trường hợp nào nói rằng các giá trị phải loại trừ dấu bằng trong phiên bản 0?
Gili

1

Có một vấn đề thú vị khác với IE và Edge. Cookies có tên với hơn 1 thời gian dường như bị bỏ âm thầm. Vì vậy, điều này hoạt động:

cookie_name_a = valuea

trong khi điều này sẽ bị rơi

cookie.name.a = valuea


Sẽ thật tuyệt nếu bạn thêm phiên bản trình duyệt chính xác để chúng tôi sao chép, vì hành vi của trình duyệt không nhất quán trên cookie.
Gerald

0

thật đơn giản:

<Tên cookie> có thể là bất kỳ ký tự US-ASCII nào ngoại trừ các ký tự điều khiển (CTL), dấu cách hoặc tab. Nó cũng không được chứa ký tự phân cách như sau: () <> @ ,; : \ "/ []? = {}.

Tùy chọn <cookie-value> có thể được đặt trong dấu ngoặc kép và bất kỳ ký tự US-ASCII nào trừ CTL, khoảng trắng, dấu ngoặc kép, dấu phẩy, dấu chấm phẩy và dấu gạch chéo ngược đều được cho phép. Mã hóa: Nhiều triển khai thực hiện mã hóa URL trên các giá trị cookie, tuy nhiên không bắt buộc theo thông số RFC. Nó giúp đáp ứng các yêu cầu về các nhân vật được phép mặc dù.

Liên kết: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/set-Cookie#Directives


0

Thêm một sự cân nhắc. Gần đây tôi đã thực hiện một lược đồ trong đó một số dữ liệu nhạy cảm được đăng lên tập lệnh PHP cần thiết để chuyển đổi và trả lại dưới dạng cookie được mã hóa, sử dụng tất cả các giá trị cơ bản 64 mà tôi nghĩ là được bảo đảm "an toàn". Vì vậy, tôi đã mã hóa cẩn thận các mục dữ liệu bằng RC4, đã chạy đầu ra thông qua base64_encode và vui vẻ trả lại cookie cho trang web. Việc kiểm tra dường như diễn ra tốt đẹp cho đến khi chuỗi được mã hóa base64 chứa ký hiệu "+". Chuỗi được ghi vào cookie trang mà không gặp sự cố. Tôi cũng có thể sử dụng chẩn đoán trình duyệt. Xác minh các cookie được viết không thay đổi. Sau đó, khi một trang tiếp theo gọi PHP của tôi và lấy cookie thông qua mảng $ _COOKIE, tôi đã bối rối khi thấy chuỗi hiện thiếu dấu "+". Mỗi lần xuất hiện của ký tự đó được thay thế bằng một ký tự Không gian ASCII.

Xem xét có bao nhiêu khiếu nại chưa được giải quyết tương tự mà tôi đã đọc mô tả kịch bản này kể từ đó, thường đưa ra nhiều tài liệu tham khảo để sử dụng Base64 để "lưu trữ" dữ liệu tùy ý trong cookie, tôi nghĩ rằng tôi đã chỉ ra vấn đề và đưa ra giải pháp không chấp nhận được.

Sau khi bạn đã thực hiện bất kỳ mã hóa nào bạn muốn thực hiện trên một phần dữ liệu và sau đó sử dụng base64_encode để làm cho nó "an toàn cookie", hãy chạy chuỗi đầu ra thông qua ...

// 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;
    }

Ở đây tôi chỉ đơn giản là thay thế "+" (và tôi cũng đã quyết định "=") bằng các ký tự "an toàn cookie" khác, trước khi trả lại giá trị được mã hóa cho trang, để sử dụng làm cookie. Lưu ý rằng độ dài của chuỗi đang được xử lý không thay đổi. Khi cùng (hoặc một trang khác trên trang web) chạy lại tập lệnh PHP của tôi, tôi sẽ có thể khôi phục cookie này mà không bị thiếu các ký tự. Tôi chỉ cần nhớ chuyển cookie trở lại qua cùng một cuộc gọi fix64 () mà tôi đã tạo và từ đó tôi có thể giải mã nó bằng base64_decode () thông thường, theo sau là bất kỳ giải mã nào khác trong lược đồ của bạn.

Có thể có một số cài đặt tôi có thể thực hiện trong PHP cho phép các chuỗi base64 được sử dụng trong cookie được chuyển trở lại PHP mà không bị hỏng. Trong thời gian này hoạt động. "+" Có thể là giá trị cookie "hợp pháp", nhưng nếu bạn muốn chuyển chuỗi đó lại cho PHP (trong trường hợp của tôi thông qua mảng $ _COOKIE), tôi khuyên bạn nên xử lý lại để xóa nhân vật vi phạm, và khôi phục chúng sau khi phục hồi. Có rất nhiều nhân vật "an toàn cookie" khác để lựa chọn.


0

Nếu bạn đang sử dụng các biến sau này, bạn sẽ thấy những thứ như paththực sự sẽ cho phép các ký tự có dấu, nhưng nó sẽ không thực sự khớp với đường dẫn trình duyệt. Cho rằng bạn cần URIEncode chúng. Vì vậy, tức là như thế này:

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

Vì vậy, ký tự "được phép", có thể nhiều hơn những gì trong thông số kỹ thuật. Nhưng bạn nên ở trong thông số kỹ thuật và sử dụng các chuỗi được mã hóa URI để an toàn.


-1

Nhiều năm trước MSIE 5 hoặc 5.5 (và có lẽ cả hai) đã có một số vấn đề nghiêm trọng với "-" trong khối HTML nếu bạn có thể tin được. Mặc dù nó không liên quan trực tiếp, kể từ khi chúng tôi lưu trữ hàm băm MD5 (chỉ chứa các chữ cái và số) trong cookie để tìm kiếm mọi thứ khác trong cơ sở dữ liệu phía máy chủ.


-2

Tôi đã kết thúc bằng cách sử dụng

cookie_value = encodeURIComponent(my_string);

my_string = decodeURIComponent(cookie_value);

Điều đó dường như làm việc cho tất cả các loại nhân vật. Tôi có vấn đề kỳ lạ khác, ngay cả với các ký tự không phải dấu chấm phẩy hoặc dấu phẩy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.