滚动新闻 →
Windows 11 文件夹怎么批量重命名?不用逐个修改文件名称 诺贝尔奖得主警告:法国债务“大到救不起” PHP Cookie 怎么使用?网站记住用户状态时需要注意哪些问题 从王维诗歌看中国传统审美 五味与传统饮食观念 华为刹车板断裂事件持续发酵 业内专家判断一致 崩溃!小伙子上山采蘑菇 误用粪瓢舀泉水喝 行书究竟介于楷书和草书之间吗 天津武清半马赛 42岁男子猝死 家属要真相 湖北烟花爆燃12人死 顾客试放“震天雷”所致 如何培养孩子尊重清洁工和普通劳动者 川普放宽俄柴油制裁 泽连斯基呛:送普京大礼 广州“砍树书记”落马 湖南帮传闻再受关注 高帧率视频适合拍什么 巴拿马7.7强震 路毁屋塌 全国学校停课 涉转运英伟达AI晶片服务器至中国 美超微包商认罪 曾带百车进死胡同 网红车出游获“隔离保护” 烂柯杯战火重燃 韩国反客为主 八强占五席 三国时代为什么会形成 北京一景区小马被游客骑断腰椎 瘫坐在地死亡 115年国庆大会登场 展现台湾民主活力团结韧性 华为百万豪车刹车断裂 测评视频接连下架惹议 川普高调庆祝哥伦布日 批共产主义议程 “星链”挑战三大电信巨头 或颠覆美通讯市场 伊萨亚斯升级三级飓风 佛州阿拉巴马严阵以待 卫生间洗手台下面的空间如何利用 南非法官皮莱获诺贝尔和平奖 美国同日制裁ICC ICE抓移民 纽约首爆枪案 市长与部长隔空激辩 干燥地区为什么会形成独特的肉类保存方式 中国籍大学篮球运动员 因签证过期被ICE拘留 到达陌生城市后如何安排第一天 涉与中共退役少将长期接触 德前情报局长被捕 俄伊用AI伪造记者身份散播假新闻 欲影响政治 中共科研船频接近关键海缆 恐成“水下间谍” 检方:华为故意向巴黎银行隐瞒与星通的关系 汽车防冻液多久需要检查一次 纽约ICE开枪执法惹议 ICE:嫌犯涉多项犯罪 美推动俄乌局部停火 俄是否配合成关键 加国渥太华庆双十 吁深化合作应对中共威胁 电动车高压平台为什么能够提高充电效率

PHP Cookie 怎么使用?网站记住用户状态时需要注意哪些问题

发布时间: 2026-10-10 00:00:02    最后更新: 2026-10-10 01:05:18    阅读:7  约13 分钟阅读     

PHP Cookie 怎么使用?网站记住用户状态时需要注意哪些问题
图片说明:示意图   图片来源:Public Domain(公有领域)
打开一个网站,过几天回来以后发现自己仍然登录着,或者网站记住了语言、主题和其他个人设置,这背后往往都离不开Cookie。对PHP开发者来说,Cookie并不是什么神秘的“浏览器数据库”,它本质上是一种由浏览器保存、并按照规则自动附加到后续HTTP请求中的少量数据。服务器通过HTTP响应头里的Set-Cookie告诉浏览器保存什么,浏览器以后再通过请求头里的Cookie把符合条件的数据发送回来,PHP最终通过$_COOKIE读取。

最基本的PHP Cookie非常简单:

setcookie('theme', 'dark', time() + 86400, '/');

执行以后,浏览器会收到一个Cookie。以后访问符合条件的页面时,浏览器会自动把它发送给服务器,PHP则可以通过:

$theme = $_COOKIE['theme'] ?? 'light';

读取。如果Cookie只是保存网站显示偏好,这样已经足够。但涉及登录、支付、账户权限等场景,就不能把Cookie当成一个普通变量处理。

首先要理解一个非常容易搞错的概念:Cookie存储在浏览器,Session数据通常存储在服务器。PHP Session常见的工作方式实际上也是浏览器保存一个Session ID,例如PHP通过名为PHPSESSID的Cookie保存会话标识,真正的Session数据则保存在服务器端。因此,“Session一定比Cookie安全”这种说法并不准确。安全性取决于你到底把什么东西放在哪里,以及认证和Cookie属性如何配置。

例如,如果Cookie里面直接保存:

user_id=1001

然后服务器收到这个值以后就直接认为“这是1001号用户”,这种设计存在严重问题。用户完全可以修改自己的Cookie。如果服务器没有进一步验证,攻击者就可能把1001改成1002,从而尝试访问另一个账户。

更合理的设计是Cookie保存一个不可预测的随机会话标识,服务器根据这个标识查找登录会话。例如:

session_id=随机高熵字符串

服务器数据库或Session存储中再记录这个Session对应的用户ID、创建时间、过期时间和其他状态。这样用户修改Cookie中的Session ID也不能直接把自己变成另一个用户,因为有效Session ID应该是不可猜测的随机值。

PHP提供了非常方便的Session机制:

session_start();

$_SESSION['user_id'] = 1001;
$_SESSION['logged_in'] = true;

浏览器通常只保存Session ID,而不是整个$_SESSION数组。后续请求到达服务器后,PHP根据Session ID找到服务器端Session数据。因此,登录系统通常应该优先采用经过设计的Session机制,而不是把用户ID、权限等级等认证信息直接塞进Cookie。

Cookie属性同样非常重要。对于登录Session这类敏感Cookie,通常应该考虑Secure、HttpOnly和SameSite。

例如:

setcookie('session_id', $sessionId, [
'expires' => time() + 86400,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);

Secure意味着浏览器只应通过HTTPS发送这个Cookie。在今天的生产网站中,涉及登录凭证的Cookie通常应该启用它。HttpOnly则阻止页面中的JavaScript通过document.cookie读取该Cookie,这可以降低某些XSS攻击窃取Session Cookie的风险。但它并不能阻止XSS本身,也不能把XSS变成“不存在的问题”。

SameSite则控制Cookie在跨站请求场景中的发送行为。Lax通常是许多普通网站登录Session的实际选择;Strict限制更加严格,而None允许跨站发送,但现代浏览器通常要求同时启用Secure。具体设置必须根据网站是否存在跨站登录、第三方嵌入、支付回调等需求决定。

path决定Cookie在哪些URL路径下发送。设置成/意味着整个网站都可以收到它,因此登录Session通常使用根路径。设置成/admin/则可以把Cookie限制在相应路径范围内。

而domain并不是必须设置的参数。很多网站根本不需要它。默认情况下,Cookie属于设置它的主机名,也就是所谓的host-only Cookie。只有确实需要让多个子域名共享Cookie时,才考虑设置Domain。例如某个网站需要让app.example.com和admin.example.com共享同一个Cookie,才可能使用:

setcookie('session_id', $sessionId, [
'expires' => time() + 86400,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);

这里还要区分“跨子域”和“跨域”。app.example.com与admin.example.com属于同一个注册域下的不同子域,可以通过Domain属性实现一定程度的Cookie共享;example.com与another-site.com则属于不同站点,不能靠设置一个Domain让Cookie跨到另一个网站。浏览器的同源策略、Cookie规则和SameSite策略都会参与限制。

因此,原稿中所说的“通过document.cookie设置跨域Cookie”是不准确的。JavaScript不能随意把Cookie设置给另一个不属于当前域的站点。跨域应用之间如果需要共享登录状态,通常应该设计正规的认证机制,例如OAuth 2.0、OpenID Connect或服务器之间的Token交换,而不是试图绕过浏览器的Cookie安全边界。

Cookie的生命周期也需要区分Session Cookie和持久Cookie。没有设置明确的expires或Max-Age时,通常属于会话Cookie,其生命周期由浏览器的会话管理决定,并不应该简单理解成“关闭浏览器必然立即删除”。现代浏览器可能存在会话恢复机制,因此不要把它当作严格的安全边界。

需要长期保存的数据则可以设置过期时间,例如用户的非敏感显示偏好。但“登录30天”并不意味着一定应该让一个永久有效的登录凭证存在30天。对于高价值账户,更合理的设计包括Session过期、绝对生命周期、空闲超时、重新认证以及登录状态撤销等机制。

Cookie还有大小限制,因此不适合拿来存储大量数据。实际开发中经常引用“单个Cookie约4KB”作为经验值,但具体限制由浏览器和实现决定,不能把4KB理解成一个所有环境都绝对相同的协议数字。Cookie数量和总大小也有限制,浏览器超过限制后可能出现删除或无法保存等问题。

更重要的是,不要因为Cookie可以保存字符串,就把密码、信用卡信息或者完整用户资料直接放进去。尤其不要认为“使用AES加密以后把敏感数据放Cookie里就安全了”。加密可以解决部分机密性问题,却没有解决Cookie被复制、重放、失效管理、密钥管理以及服务器授权等问题。对于认证凭证,通常更好的方案是让Cookie只携带随机、不可预测的Session标识,而真正的用户状态保存在服务器端。

Cookie还不能替代CSRF防护。SameSite能够降低部分跨站请求风险,但对于修改密码、转账、删除账户等敏感操作,不能简单地认为设置SameSite=Lax以后就万事大吉。根据应用架构,还可能需要CSRF Token、Origin/Referer检查以及重新认证等措施。

PHP操作Cookie还有一个非常实际的问题:HTTP响应头必须在响应发送之前设置。也就是说:

setcookie('theme', 'dark', time() + 86400, '/');

应该发生在输出HTML之前。如果代码已经输出内容,甚至已经因为BOM、空格或错误信息导致响应头发送,再调用setcookie()就可能出现“headers already sent”错误。

删除Cookie也不是简单调用一个“deleteCookie”函数。通常需要使用与原Cookie匹配的路径和Domain,并把过期时间设置到过去:

setcookie('theme', '', [
'expires' => time() - 3600,
'path' => '/',
]);

如果当初设置Cookie时使用了不同的Domain或Path,删除时参数不匹配,就可能出现“明明删除了但浏览器里面还存在”的情况,因为实际上操作的是另一个Cookie。

调试Cookie时,现代浏览器开发者工具中的Application或Storage区域非常有用,可以直接查看Cookie的Domain、Path、Expires、Secure、HttpOnly和SameSite等属性。Network面板则更加重要,因为它可以观察服务器到底发送了什么Set-Cookie响应头,以及后续请求到底有没有带上Cookie。遇到“Cookie没有生效”,不要只看$_COOKIE,应该从HTTP请求和响应两端同时检查。

还需要纠正一个常见说法:Cookie值并不是简单地“传输过程中自动进行URL编码,所以必须使用rawurlencode()”。PHP的setcookie()对Cookie值有自己的处理规则,开发者不应该无条件再进行一次URL编码,否则读取时可能得到经过双重编码的数据。真正需要保存复杂结构时,应明确采用可靠的序列化和编码方式,并理解Cookie允许的字符规则,而不是见到Cookie就习惯性调用urlencode()。

如果网站使用HTTPS,还应该关注HSTS、TLS配置和整个登录链路的安全性。因为Secure只能告诉浏览器不要通过HTTP发送这个Cookie,并不能修复一个本身仍然允许HTTP登录、存在XSS或者Session固定攻击漏洞的网站。

登录系统还有一个非常重要的步骤叫Session Rotation。用户成功登录以后,服务器应该重新生成Session ID,避免攻击者提前让受害者使用一个已知Session ID,再等待受害者登录后接管会话。PHP可以使用:

session_regenerate_id(true);

在适当的登录流程中更新Session ID。

最终可以把PHP Cookie理解成一个“浏览器帮服务器携带的小型状态标识”。它非常方便,但它本身并不负责判断用户是不是好人,也不负责判断用户有没有权限。Cookie只是运输工具,真正的安全边界来自服务器端的认证、授权、Session管理、CSRF防护、XSS防护以及合理的Cookie属性。

一个成熟的PHP登录系统通常不是“把user_id写进Cookie”这么简单,而是用户登录后生成不可预测的Session ID,Cookie使用Secure、HttpOnly和合适的SameSite策略,服务器保存真正的会话状态,敏感操作进行授权检查,并在登录、登出、密码修改等关键节点正确轮换或撤销Session。这样,Cookie才真正成为网站“记住用户”的可靠基础,而不是一个藏在浏览器里的可篡改身份标签。

喜欢这篇报道?

使用下面的功能,方便以后继续阅读和分享 MNewsTV

设为 Google 新闻首选来源 让 Google 新闻优先显示 MNewsTV 的最新报道 ›
★ 我的收藏 查看已经收藏的文章
关于文章收藏 收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。 删除收藏请进入「我的收藏」进行管理。
分享这篇报道

捐助(Paypal): https://www.paypal.me/observeccp
订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP