Cách chính xác để xóa cookie phía máy chủ


141

Đối với quy trình xác thực của tôi, tôi tạo một mã thông báo duy nhất khi người dùng đăng nhập và đặt mã đó vào cookie được sử dụng để xác thực.

Vì vậy, tôi sẽ gửi một cái gì đó như thế này từ máy chủ:

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

Mà hoạt động trên tất cả các trình duyệt. Sau đó, để xóa cookie, tôi gửi một cookie tương tự với expirestrường được đặt cho ngày 1 tháng 1 năm 1970

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

Và nó hoạt động tốt trên Firefox nhưng không xóa cookie trên IE hoặc Safari.

Vậy cách tốt nhất để xóa cookie (tốt nhất là không có JavaScript) là gì? Phương pháp set-the-expires-in-the-past có vẻ cồng kềnh. Và tại sao điều này hoạt động trong FF nhưng không phải trong IE hay Safari?


Câu trả lời:


208

Gửi cùng một giá trị cookie với được ; expiresnối sẽ không phá hủy cookie.

Vô hiệu hóa cookie bằng cách đặt một giá trị trống và bao gồm cả một expirestrường:

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

Lưu ý rằng bạn không thể buộc tất cả các trình duyệt xóa cookie. Máy khách có thể định cấu hình trình duyệt theo cách mà cookie vẫn tồn tại, ngay cả khi nó đã hết hạn. Đặt giá trị như mô tả ở trên sẽ giải quyết vấn đề này.


52
Tôi khuyên bạn nên sử dụng một văn bản trống làm rác, thay vì "deleted"để tránh nhầm lẫn sau này với giá trị pháp lý tiềm năng tương đương với "đã xóa"
yegor256

8
@AFk Vâng, bạn đã đúng. Thật buồn cười là nó đã không được chú ý trước đó, hy vọng nó không gây ra quá nhiều vấn đề. yegor256, một giá trị trống sẽ hoạt động trong hầu hết các trường hợp. Liên quan: một số người có thể tự hỏi tại sao cookie của họ không bị xóa ngay cả sau khi gửi tiêu đề này. Trong trường hợp đó, hãy xem cookie từ các tên miền khác. Ví dụ, sau khi xóa foo=bar; domain=www.example.com, một cookie khác foo=qux; domain=.example.comsẽ được sử dụng.
Lekensteyn

3
"Máy khách có thể định cấu hình trình duyệt theo cách mà cookie vẫn tồn tại, ngay cả khi nó hết hạn. Đặt giá trị như mô tả ở trên sẽ giải quyết vấn đề này." Không phải khách hàng có thể định cấu hình trình duyệt để bỏ qua yêu cầu của bạn để đặt nội dung cookie thành "đã xóa" sao? Bạn không có cách nào để buộc khách hàng làm bất cứ điều gì nó không muốn.
Ajedi32

@ Ajedi32 Có thể, nhưng sau đó bạn phải trải qua nỗ lực bổ sung để làm như vậy (với tư cách là khách hàng). Hành vi bỏ qua một giá trị trống là phổ biến hơn nhiều, sẽ không có ý nghĩa khi trình duyệt bỏ qua các yêu cầu như vậy, đặc biệt đối với ID phiên bị vô hiệu.
Lekensteyn

2
-1 bởi vì tôi chưa bao giờ thấy một cách nào để định cấu hình trình duyệt để bỏ qua hết hạn cookie và không tin rằng bất kỳ trình duyệt nào tồn tại đều cung cấp tùy chọn như vậy. Hơn nữa, câu đầu tiên trong câu trả lời của bạn, sau lần chỉnh sửa khá táo bạo của @ DaveJarvis, giờ đây hoàn toàn sai đối với bất kỳ trình duyệt chính hoặc bất kỳ tác nhân người dùng tuân thủ thông số kỹ thuật nào. tools.ietf.org/search/rfc6265#section-5.3 ra lệnh rằng "Tác nhân người dùng PHẢI đuổi tất cả các cookie đã hết hạn từ cửa hàng cookie nếu bất cứ lúc nào, một cookie hết hạn tồn tại trong cửa hàng cookie." và theo hiểu biết tốt nhất của tôi đó là những gì mọi trình duyệt trên thực tế làm.
Đánh dấu Amery

46

Tại thời điểm tôi viết câu trả lời này, câu trả lời được chấp nhận cho câu hỏi này dường như nói rằng các trình duyệt không bắt buộc phải xóa cookie khi nhận được cookie thay thế có Expiresgiá trị trong quá khứ. Yêu cầu đó là sai. Thiết lập Expirestrước đây là cách xóa tiêu chuẩn, tuân thủ thông số kỹ thuật và các tác nhân người dùng được yêu cầu bởi thông số kỹ thuật để tôn trọng nó.

Sử dụng một Expiresthuộc tính trong quá khứ để xóa cookie là chính xác và là cách để loại bỏ cookie được quy định bởi thông số kỹ thuật. Phần ví dụ của RFC 6255 nêu rõ:

Cuối cùng, để xóa cookie, máy chủ trả về tiêu đề Set-Cookie có ngày hết hạn trong quá khứ. Máy chủ sẽ thành công trong việc xóa cookie chỉ khi thuộc tính Đường dẫn và Tên miền trong tiêu đề Set-Cookie khớp với các giá trị được sử dụng khi cookie được tạo.

Phần Yêu cầu Tác nhân Người dùng bao gồm các yêu cầu sau, cùng với đó có tác dụng là cookie phải hết hạn ngay lập tức nếu tác nhân người dùng nhận được cookie mới có cùng tên đã hết hạn sử dụng

  1. Nếu [khi nhận cookie mới], cửa hàng cookie chứa cookie có cùng tên, tên miền và đường dẫn với cookie mới được tạo:

    1. ...
    2. ...
    3. Cập nhật thời gian tạo của cookie mới tạo để khớp với thời gian tạo của cookie cũ.
    4. Loại bỏ cookie cũ khỏi cửa hàng cookie.
  2. Chèn cookie vừa tạo vào cửa hàng cookie.

Một cookie đã "hết hạn" nếu cookie có thời hạn sử dụng trong quá khứ.

Tác nhân người dùng PHẢI đuổi tất cả các cookie đã hết hạn khỏi cửa hàng cookie nếu bất cứ lúc nào, một cookie hết hạn tồn tại trong cửa hàng cookie.

Các điểm 11-3, 11-4 và 12 ở trên cùng có nghĩa là khi nhận được cookie mới có cùng tên, tên miền và đường dẫn, cookie cũ phải được hết hạn và thay thế bằng cookie mới. Cuối cùng, điểm dưới đây về cookie hết hạn cho biết thêm rằng sau khi hoàn thành, cookie mới cũng phải bị đuổi ngay lập tức. Thông số kỹ thuật không cung cấp phòng lắc cho các trình duyệt vào thời điểm này; nếu một trình duyệt cung cấp cho người dùng tùy chọn vô hiệu hóa hết hạn cookie, vì câu trả lời được chấp nhận cho thấy một số trình duyệt thực hiện, thì nó sẽ vi phạm thông số kỹ thuật. (Một tính năng như vậy cũng sẽ có ít sử dụng và theo như tôi biết thì nó không tồn tại trong bất kỳ trình duyệt nào.)

Tại sao, sau đó, OP của câu hỏi này quan sát cách tiếp cận này không thành công? Mặc dù tôi đã không bỏ qua một bản sao của Internet Explorer để kiểm tra hành vi của nó, tôi nghi ngờ đó là vì Expiresgiá trị của OP không đúng! Họ đã sử dụng giá trị này:

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

Tuy nhiên, điều này là không hợp lệ về mặt cú pháp theo hai cách.

Phần cú pháp của spec quy định rằng giá trị của Expiresthuộc tính phải là một

rfc1123 -date , được định nghĩa trong [RFC2616], Mục 3.3.1

Theo liên kết thứ hai ở trên, chúng tôi thấy đây là một ví dụ về định dạng:

Sun, 06 Nov 1994 08:49:37 GMT

và thấy rằng định nghĩa cú pháp ...

  1. yêu cầu ngày được viết theo định dạng ngày tháng năm , không phải định dạng tháng tháng năm như người hỏi đặt ra.

    Cụ thể, nó định nghĩa rfc1123-datenhư sau:

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

    và định nghĩa date1như thế này:

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

  1. không cho phép UTCnhư một múi giờ.

    Thông số kỹ thuật có chứa tuyên bố sau về độ lệch múi giờ được chấp nhận trong định dạng này:

    Tất cả tem ngày / giờ HTTP PHẢI được thể hiện bằng Giờ chuẩn Greenwich (GMT), không có ngoại lệ.

    Còn gì nữa nếu chúng ta tìm hiểu sâu hơn về thông số ban đầu của định dạng datetime này, chúng ta thấy rằng trong thông số ban đầu của nó trong https://tools.ietf.org/html/rfc822 , phần Syntax liệt kê "UT" (có nghĩa là "thời gian phổ quát" ) là một giá trị có thể, nhưng không liệt kê không phải UTC (Giờ phối hợp quốc tế) là hợp lệ. Theo tôi biết, sử dụng "UTC" ở định dạng ngày này chưa bao giờ hợp lệ; nó không phải là một giá trị hợp lệ khi định dạng được chỉ định lần đầu tiên vào năm 1982 và thông số HTTP đã áp dụng một phiên bản hạn chế nghiêm ngặt hơn của định dạng bằng cách cấm sử dụng tất cả các giá trị "vùng" khác với "GMT".

Nếu người hỏi câu hỏi ở đây đã sử dụng một Expiresthuộc tính như thế này , thì:

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

sau đó nó có lẽ đã làm việc


15

Đặt "hết hạn" cho một ngày qua là cách tiêu chuẩn để xóa cookie.

Vấn đề của bạn có lẽ là do định dạng ngày không thông thường. IE có lẽ chỉ mong GMT.


2

Sử dụng Max-Age = -1 thay vì "Hết hạn". Nó ngắn hơn, ít kén chọn hơn về cú pháp và Max-Age được ưu tiên hơn Hết hạn.


-1

Để triển khai JAX-RS của GlassFish Jersey, tôi đã giải quyết vấn đề này bằng phương pháp phổ biến là mô tả tất cả các tham số phổ biến. Ít nhất ba tham số phải bằng nhau: name (= "name"), path (= "/") và domain (= null):

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

Và sử dụng nó theo cách phổ biến để đặt cookie:

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

và để xóa cookie:

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

đối với tôi khi tôi đặt maxAge thành 0, nó sẽ xuất ra một cookie có Max-Age = 0 mà Chrome dường như bỏ qua. Trong RFC 6265, phần 4.1.1, nó chỉ định cú pháp của Tuổi tối đa là "không có chữ số". Đó có thể là lý do. Mặc dù, như được đề cập bởi @ JoshC13, phần 5.2.2 không nói về việc diễn giải các giá trị nhỏ hơn hoặc bằng 0. Vì vậy, nó mâu thuẫn với chính nó ở đó ...
Matthijs Wessels

Tôi không biết chi tiết, nhưng các giá trị này theo cặp đang thực sự hoạt động trong Chrome và các trình duyệt khác: maxAgeInMinutes * 60, hết hạn.
RoutesMaps.com

1
@MatthijsWessels Bắt tốt! Tôi đã đào sâu hơn một chút, và mâu thuẫn rõ ràng trên thực tế là có chủ ý, như đã lưu ý trong errata tại rfc-editor.org/errata/eid3430 . Để "tối đa hóa khả năng tương tác", các tác nhân người dùng được yêu cầu diễn giải bằng 0 hoặc âm Max-Agelà ngày và thời gian biểu diễn sớm nhất, nhưng các máy chủ bị cấm gửi một Max-Agegiá trị như vậy . Tôi đoán các tác giả biết về cả các máy khách hiện tại không thể xử lý Max-Age=0và các máy chủ đã gửi nó vào thời điểm họ viết thông số kỹ thuật và cố gắng giảm thiểu vấn đề từ cả hai đầu.
Đánh dấu Amery

@ Crimean.us Tôi cũng không thể repro nữa. Có lẽ tôi đã làm sai điều gì đó
Matthijs Wessels

@MatthijsWessels Vấn đề bỏ qua Max-Age = 0 được khắc phục trong ví dụ của tôi bằng cách đặt ngày hết hạn thành ZiatedDateTime.now (). PlusMinutes (maxAgeInMinutes). Đối với maxAgeInMinutes = 0, đó là datetime hiện tại. Mã này hoạt động trong một thời gian dài trong ứng dụng web thực.
RoutesMaps.com 6/12/18
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.