浏览器 Cookie 永不过期

2023-12-14

我第一次实施使用 HTTPOnly Cookie 登录身份验证。就我而言,当用户调用登录方法时创建的 cookiePython服务与 fastapi 和 uvicorn。

我读过MDN文档来实现expires属性,因此,浏览器会在时间到期时删除此cookie。

我已经用 Python 实现了 Cookie http.cookies 和Morsel来应用HttpOnly像这样的属性:

from http import cookies
from fastapi import FastAPI, Response, Cookie, Request
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

mytoken = 'blablabla'

def getUtcDate():
    sessionDate = datetime.now()
    sessionDate += timedelta(minutes=2)
    return sessionDate.strftime('%a, %d %b %Y %H:%M:%S GMT')

@app.get('cookietest')
def getCookie(response: Response):
   cookie = cookies.Morsel()
   cookie['httponly'] = True
   cookie['version'] = '1.0.0'
   cookie['domain'] = '127.0.0.1'
   cookie['path'] = '/'
   cookie['expires'] = getUtcDate()
   cookie['max-age'] = 120
   cookie['samesite'] = 'Strict'
   cookie.set("jwt", "jwt", mytoken)

   response.headers.append("Set-Cookie", cookie.output())

   return {'status':'ok'}

这样做,当我调用“cookietest”端点时,Cookie 在浏览器中看起来正确,证据如下:

Cookie with expiration date

如图所示,cookie 在 Expires / Max-Age 中有一个过期日期时间:“Wed, 12 Oct 2022 11:24:58 GMT”,登录后 2 分钟(如果用户在 14:05 登录: 00,cookie 于 14:07:00 过期)

我的问题是当超过过期时间时,任何浏览器都不会删除 cookie,所以这让我很困惑。如果我过了几分钟然后向另一个端点发出请求(例如http://127.0.0.1:8000/info),cookie 仍然存在于 http 标头中。

问题是什么?我做错了什么?我正在阅读大量有关 cookie 存储和过期的文档,但我看不到任何有关此问题的信息。

非常感谢 问候

编辑:问题已解决

As Chris说,使用 FastApi 的 set_cookie 方法解决了问题。

我仍然想知道为什么MSD文档指示日期格式必须是特定的格式,这不会导致浏览器删除Cookie,但指示以秒为单位的时间可以正常工作。

@app.get("/cookietest")
async def cookietest(response: Response):
    response.set_cookie(
        key='jwt', 
        value=getToken(), 
        max_age=120, 
        expires=120, 
        path='/', 
        secure=False, 
        httponly=True, 
        samesite="strict", 
        domain='127.0.0.1'
    )
    return {"Result": "Ok"}

当使用expires标志,日期必须完全符合您当前使用的格式以及GMT(格林威治标准时间)时区。您的 cookie 在创建后 2 分钟内不会过期的原因是您正在使用日期时间.now(),它返回当前的local日期和时间。

因此,例如,如果您当前的本地时区是GMT+2时间是20:30:00(因此,GMT时间是18:30:00),创建一个过期时间为20:32:00 GMT实际上会告诉浏览器在 2 小时 2 分钟内删除此 cookie(从创建之日起)。如果你查看 cookieExpires / Max-Age浏览器开发工具中的列(例如,在 Chrome 上,转到Network在 DevTools 中的选项卡中,单击请求的名称,然后单击Cookies选项卡),您会注意到Z在日期时间的末尾,这意味着UTC(协调世界时)——即与 UTC 的偏移量为零时-分-秒。您也可以检查响应标头,您可以在其中看到 cookieexpires标志设置为20:32:00 GMT。没有什么明显的之间的时间差UTC and GMT(如果您想了解更多关于它们的差异,请查看此post).

因此,您可以替换.now() with .utcnow()在你的代码中:

from datetime import timedelta, datetime

def get_expiry():
    expiry = datetime.utcnow()
    expiry += timedelta(seconds=120)
    return expiry.strftime('%a, %d-%b-%Y %T GMT')

or use 时间.gmtime(),传递为secs论证时间.time()(返回以秒为单位的时间)加上所需的租约时间(以秒为单位):

import time

def get_expiry():
    lease = 120  # seconds
    end = time.gmtime(time.time() + lease)
    return time.strftime('%a, %d-%b-%Y %T GMT', end)

对于上述两种方法之一,请使用:

cookie['expires'] = get_expiry()

您还可以使用未记录的方式直接以秒为单位传递到期时间。例如:

cookie['expires'] = 120

替代方案expires is the max-ageflag ,指定 cookie 从当前时刻起的过期时间(以秒为单位)(与上面的方式类似)。如果设置为零或负值,则 cookie 将被立即删除。例子:

cookie['max-age'] = 120

Note:

If both expires and max-age已设定,max-age具有优先权(参见相关MDN 上的文档).

另外,根据RFC 6265:

4.1.2.1.这Expires属性

The Expires属性表示cookie的最大生命周期, 表示为日期和时间cookie 过期的时间。用户 代理无需在指定日期之前保留 cookie 已经过去了。事实上,用户代理经常因内存问题而驱逐 cookie 压力或隐私问题。

4.1.2.2.这Max-Age属性

The Max-Age属性表示cookie的最大生命周期, 表示为数量seconds直到cookie过期。这 用户代理不需要保留指定的cookie 期间。事实上,用户代理经常因内存问题而驱逐 cookie 压力或隐私问题。

NOTE: Some existing user agents do not support the Max-Age 
attribute. User agents that do not support the Max-Age attribute 
ignore the attribute.

如果 cookie 有both the Max-AgeExpires属性,即Max-Age属性具有优先权并控制过期日期 饼干。如果 cookie 有neither the Max-Age也不Expires属性,用户代理将保留 cookie 直到“当前 会话结束”(由用户代理定义)。

另请注意,如中所述MDN 文档关于expires flag:

Warning:许多网络浏览器都有一个会话恢复功能将保存所有选项卡并在下次使用浏览器时恢复它们。 会话 cookies 也会被恢复,就好像浏览器从未恢复过一样 关闭。

另一件值得注意的是,自 2022 年 9 月以来,Chrome 限制 cookiemax-age至 400 天:

当cookies被显式设置时Expires/Max-Age归因于值现在限制为不超过 400 天将来。 以前,没有限制,cookie 的过期时间可以是 未来几千年。

使用 FastAPI/Starlette

还应该指出的是,FastAPI/Starlette 提供了一种更简单的方法来设置 cookieResponse对象,使用set_cookie方法,如中所述这个答案。按照星光文档:

  • max_age - An integer定义 cookie 的生命周期seconds。负整数或值0将丢弃 立即饼干。Optional
  • expires - An integer定义了数量seconds直到cookie过期。Optional

示例来自FastAPI文档:

from fastapi import FastAPI, Response

app = FastAPI()

@app.post('/')
def create_cookie(response: Response):
    response.set_cookie(key='token', value='token-value', max_age=120, expires=120, httponly=True)
    return {'message': 'success'}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

浏览器 Cookie 永不过期 的相关文章

随机推荐