什么是Cookie?
HTTP cookie(也称为 web cookie、浏览器 cookie)是服务器存储在用户浏览器中的一小段信息。服务器在返回浏览器发出的请求的响应时设置 Cookie。浏览器存储 Cookie 并将其与后续请求一起发送回同一服务器。
Cookie有什么作用?
用户跟踪:
存储用户偏好:
跨请求识别客户端:
等等
在SpringBoot中创建Cookie
1、创建cookie
@RestController
@RequestMapping("/cookie")
public class CookieController {
@GetMapping("/set")
public String setCookie(HttpServletResponse response) {
Cookie userNameCookie = new Cookie("username", "not500");
userNameCookie.setPath("/");
response.addCookie(userNameCookie);
// 创建一个 cookie
Cookie passwordCookie = new Cookie("password", "123456");
//设置 cookie过期时间
passwordCookie.setMaxAge(7 * 24 * 60 * 60); // expires in 7 days
//添加到 response 中
response.addCookie(passwordCookie);
return "cookie is changed";
}
}
2、发送请求
然后在浏览器中发送请求,可以在响应体中看到设置cookie的操作
3、常见属性
cookie有几个常见的属性。name、value、domain、path、max-age、httponly、scure、sameSite
| 属性 | 作用 | 示例 |
|---|---|---|
name=value | 必填。Cookie的键值对 | lang=zh-CN |
Domain | 指定Cookie适用的域名(含子域) | Domain=.example.com(适用于example.com及其子域) |
Path | 指定Cookie生效的路径 | Path=/account(只在/account及其子路径生效) |
Expires | 绝对过期时间(GMT格式) | Expires=Wed, 21 Oct 2025 07:28:00 GMT |
Max-Age | 相对过期时间(单位:秒),比Expires优先 | Max-Age=3600(1小时后过期) |
Secure | 仅在HTTPS协议下发送 | Secure |
HttpOnly | 禁止JS通过document.cookie访问(防止XSS) | HttpOnly |
SameSite | 跨站点请求时的Cookie发送策略(防CSRF) | SameSite=Strict |
name 和 value
cookie是以键值对的方式存储的,name也就是名称,value就是内容
domain 和 path
这两个属性可以控制cookie的访问范围
我们再发一次请求,可以看到在 请求体 中带了cookie
但若将域名改成 127.0.0.1 ,就看不到刚刚设置的cookie了。 **不同域名下的 Cookie 默认不共享。**在该域名下发送之前的 /set,然后再 /get 就可以看到cookie 了。
我们再看 path 属性,新建一个类,添加以下代码,然后在浏览器发送请求。
@RestController
@RequestMapping("/cookie2")
public class CookieController2 {
@GetMapping("/get")
public String readCookie(@CookieValue(value = "username", defaultValue = "null") String username
,@CookieValue(value = "password", defaultValue = "null") String password) {
return "Hey! My username is " + username + "<br/>" + "My password is " + password;
}
}
可以看到能读到 username,但是读不到 password,因为我们当前的路径是在 /cookie2下,username的有效路径是 /,password 的有效路径是 /cookie
expires 和 max-age
我们之前设置的cookie中,password的过期时间是一个普通的时间,表示时间一到,该cookie就会被清楚,需要用户重新进行相关操作,例如登录。而username的过期时间是‘会话’,表面 一旦关闭浏览器,Cookie自动消失。
此外,因为 Servlet 规范遵循更现代的 HTTP/1.1 标准,采用 Max-Age 取代了 Expires,所以没有提供 setExpires() 方法。
secure + httpOnly + sameSite
secure
安全 Cookie 仅通过加密的 HTTPS 连接发送到服务器。安全 Cookie 无法通过未加密的 HTTP 连接传输到服务器。然后在浏览器发送之前的 /get 请求。
// 创建一个 cookie
Cookie secure = new Cookie("secure", "1");
//设置 cookie过期时间
secure.setMaxAge(7 * 24 * 60 * 60); // expires in 7 days
secure.setSecure(true);
//添加到 response 中
response.addCookie(secure);
但是却请求到了 scure 的cookie?
浏览器在localhost 或 127.0.0.1上,出于开发便利,部分浏览器放宽了Secure的限制。
我们可以在 命令提示符(win + r,输入cmd)中使用 ipconfig 命令,查看自己的ip,然后在浏览器中 /get,就看不到了。在/get 前记得先 /set一下
httpOnly
Cookie 设置了 HttpOnly 属性,客户端脚本就无法访问该 Cookie。例如,不能使用 Document.cookie 属性访问 JavaScript 中的 HttpOnly Cookie。
sameSite
| 值 | 含义 | 举例 |
|---|---|---|
Strict | 最严格,完全不允许跨站点发送(即便用户点击链接跳转也不会带Cookie) | 假如你现在在浏览一个博客网站,里面有一个github的链接,但github下的cookie设置了sameSite=Strict,那么你跳转过去后需要重新登录。 |
Lax | 默认。允许”导航行为”(比如点击链接)带上Cookie,但不允许跨站请求(如图片、iframe、Ajax、表单) | 设置为Lax,上面的案例中,就不需要重新登录了,但如果现在有按钮,点击按钮时向 github的开发api 发送ajax请求,那么cookie就带不过去了。 |
None | 允许完全的跨站请求,但必须与Secure一起使用(即HTTPS下) | 使用Https,且,任何请求都可以携带cookie |
Lax下,各种请求发送Cookie的情况
| 请求类型 | 示例 | 正常情况 | Lax | 同源策略 |
|---|---|---|---|---|
| 链接 | <a href="..."></a> | 发送 Cookie | 发送 Cookie | ❌ 不受限制 |
| 预加载 | <link rel="prerender" href="..."/> | 发送 Cookie | 发送 Cookie | ❌ 不受限制 |
| GET 表单 | <form method="GET" action="..."> | 发送 Cookie | 发送 Cookie | ❌ 不受限制 |
| POST 表单 | <form method="POST" action="..."> | 发送 Cookie | 不发送 | ❌ 不受限制 |
| iframe | <iframe src="..."></iframe> | 发送 Cookie | 不发送 | ✅ 部分限制 |
| AJAX | $.get("...") | 发送 Cookie | 不发送 | ✅ 完全限制 |
| Image | <img src="..."> | 发送 Cookie | 不发送 | ❌ 不受限制 |
CSRF
关于CSRF,可以阅读这篇文章——前端安全系列(二):如何防止CSRF攻击?