Cookie 的主要属性
- 名称(Name): Cookie的唯一标识符。
- 值(Value): 存储的数据。
- 域(Domain): 指定Cookie的作用域,即哪些域名下的请求会携带该Cookie。
- 路径(Path): 指定Cookie的作用路径,即哪些路径下的请求会携带该Cookie。
- 过期时间(Expires/Max-Age): 指定Cookie的有效期,超过过期时间,Cookie将失效。
- 安全标志(Secure): 如果设置了Secure标志,Cookie只会在HTTPS连接中传输。
- HttpOnly标志: 如果设置了HttpOnly标志,JavaScript无法访问该Cookie。
- SameSite: 限制Cookie在跨站请求中的发送行为,帮助防止跨站请求伪造(CSRF)攻击。
Cookie 的工作原理
HTTP Cookies 的工作原理是通过服务器和客户端之间的交互,来存储和传递小块数据,以便管理用户会话和偏好设置。以下是详细的工作原理:
1. 服务器设置 Cookie
当用户首次访问网站时,服务器会通过HTTP响应头 Set-Cookie
向浏览器发送一个Cookie。这个Cookie包含了名称、值、过期时间、路径、域、安全标志等属性。
示例响应头:
http
HTTP/1.1 200 OK
Set-Cookie: sessionId=abc123; Expires=Wed, 21 Oct 2025 07:28:00 GMT; Path=/; Domain=example.com; Secure; HttpOnly
Content-Type: text/html
<html>
<body>...</body>
</html>
在这个示例中,服务器设置了一个名为 sessionId
的Cookie,值为 abc123
,并包含多个属性:
- Expires: 指定Cookie的过期时间。
- Path: 指定Cookie的作用路径。
- Domain: 指定Cookie的作用域。
- Secure: 指定Cookie只能通过HTTPS连接传输。
- HttpOnly: 指定Cookie只能通过服务器端脚本访问,无法通过客户端JavaScript访问。
2. 浏览器存储 Cookie
浏览器接收到 Set-Cookie
头后,会将Cookie存储在本地,根据属性将其应用于指定的域名和路径。
3. 浏览器发送 Cookie
每次用户向该网站发送请求时,浏览器会自动将符合条件的Cookie附加到请求头中,发送给服务器。请求头中的 Cookie
字段包含了所有匹配的Cookie。
示例请求头:
http
GET /resource HTTP/1.1
Host: example.com
Cookie: sessionId=abc123
4. 服务器读取 Cookie
服务器接收到请求后,会从请求头中的 Cookie
字段提取Cookie信息,根据这些信息来处理请求。例如,服务器可以根据 sessionId
来识别用户会话,验证用户身份。
使用Angular和Express设置和读取Cookies的例子
后端:Express.js
在Express.js中,我们可以使用 cookie-parser
中间件来处理HTTP Cookies。以下是一个示例,展示了如何在Express.js中设置和读取Cookies。
安装依赖:
bash
npm install express cookie-parser
服务器代码(server.js):
javascript
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
const port = 3000;
// 使用cookie-parser中间件
app.use(cookieParser());
// 设置Cookie的路由
app.get('/set-cookie', (req, res) => {
res.cookie('username', 'john_doe', { maxAge: 900000, httpOnly: true });
res.send('Cookie has been set');
});
// 读取Cookie的路由
app.get('/get-cookie', (req, res) => {
const username = req.cookies.username || 'Guest';
res.send(`Hello, ${username}`);
});
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
在这个示例中:
/set-cookie
路由设置一个名为username
的Cookie,值为john_doe
,有效期为15分钟,并设置为HttpOnly
。/get-cookie
路由读取username
Cookie,如果不存在则返回Guest
。
前端:Angular
在Angular中,我们可以使用 ngx-cookie-service
库来处理Cookies。以下是一个示例,展示了如何在Angular中设置和读取Cookies。
安装依赖:
bash
npm install ngx-cookie-service
模块配置(app.module.ts):
typescript
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { CookieService } from 'ngx-cookie-service';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [CookieService],
bootstrap: [AppComponent]
})
export class AppModule { }
组件代码(app.component.ts):
typescript
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { CookieService } from 'ngx-cookie-service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private http: HttpClient, private cookieService: CookieService) {}
ngOnInit(): void {
// 设置Cookie
this.cookieService.set('clientCookie', 'angular_user', 1, '/');
// 发送请求并包含Cookie
this.http.get('http://localhost:3000/get-cookie', { withCredentials: true }).subscribe(response => {
console.log(response);
});
}
setServerCookie(): void {
// 发送请求以设置服务器端Cookie
this.http.get('http://localhost:3000/set-cookie', { withCredentials: true }).subscribe(response => {
console.log(response);
});
}
}
在这个示例中:
- 使用
ngx-cookie-service
设置一个名为clientCookie
的Cookie,值为angular_user
,有效期为1天。 - 通过
HttpClient
发送请求到服务器,设置和读取服务器端的Cookie。withCredentials: true
表示请求会携带跨域Cookie。 Cookie的过期是指当一个Cookie超过其设定的有效期后,浏览器会自动删除该Cookie。以下是Cookie过期过程的详细解释:
设置Cookie的过期时间
-
Expires 属性:
-
Expires
属性指定了Cookie的过期日期和时间。格式通常为UTC时间。 -
示例 :
httpSet-Cookie: sessionId=abc123; Expires=Wed, 21 Oct 2025 07:28:00 GMT
-
-
Max-Age 属性:
-
Max-Age
属性指定了Cookie的有效期(以秒为单位)。当该时间过去后,Cookie会过期并被删除。 -
示例 :
httpSet-Cookie: sessionId=abc123; Max-Age=3600
-
Cookie的过期过程
-
设置Cookie:
- 当服务器通过
Set-Cookie
头部设置一个Cookie时,可以指定该Cookie的过期时间或有效期。 - 浏览器接收到
Set-Cookie
头部后,会根据指定的Expires
或Max-Age
属性来存储Cookie。
- 当服务器通过
-
Cookie的存储:
- 浏览器会将Cookie存储在本地,并记录其过期时间或剩余的有效期。
-
检查过期时间:
- 每次浏览器发送请求时,都会检查已存储的Cookie的有效期。如果Cookie的过期时间已经到达或剩余的有效期已经为0,浏览器将不再发送该Cookie,并从本地存储中删除它。
示例代码
以下是一个示例,展示了如何通过JavaScript设置和检查Cookie的过期时间:
设置Cookie的函数:
javascript
function setCookie(name, value, expires) {
let cookieString = `${name}=${value}; path=/`;
if (expires) {
cookieString += `; expires=${expires.toUTCString()}`;
}
document.cookie = cookieString;
}
// 设置一个有效期为1天的Cookie
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 1);
setCookie('username', 'john_doe', expiryDate);
读取和检查Cookie的函数:
javascript
function getCookie(name) {
const cookieArray = document.cookie.split('; ');
for (let i = 0; i < cookieArray.length; i++) {
const cookiePair = cookieArray[i].split('=');
if (cookiePair[0] === name) {
return cookiePair[1];
}
}
return null;
}
// 检查Cookie是否存在
const username = getCookie('username');
if (username) {
console.log(`Username Cookie: ${username}`);
} else {
console.log('Username Cookie has expired or does not exist');
}
使用HTTP Cookies存在一定的安全问题,可能会导致数据泄露和攻击。以下是一些常见的Cookie安全问题及其解决方案:
常见的Cookie安全问题
-
跨站脚本攻击(XSS):
- 描述:攻击者通过注入恶意脚本,窃取Cookie数据。
- 解决方案 :设置
HttpOnly
属性,防止JavaScript访问Cookie。此外,确保应用程序对用户输入进行充分的验证和过滤,防止恶意脚本注入。
-
跨站请求伪造(CSRF):
- 描述:攻击者伪造用户请求,利用用户的身份进行恶意操作。
- 解决方案 :设置
SameSite
属性,限制Cookie在跨站请求中的发送行为。使用CSRF令牌来验证请求的合法性。
-
会话劫持:
- 描述:攻击者截获用户会话信息,冒充合法用户进行操作。
- 解决方案 :设置
Secure
属性,确保Cookie只能通过HTTPS连接传输,防止在未加密的连接中被截获。使用强加密的会话令牌,并定期更新。
-
Cookie欺骗:
- 描述:攻击者伪造Cookie数据,冒充合法用户。
- 解决方案:对Cookie数据进行签名和加密,防止被篡改和伪造。
-
Cookie固定攻击(Session Fixation):
- 描述:攻击者强制用户使用已知的会话ID,随后劫持会话。
- 解决方案:在用户登录成功后生成新的会话ID,避免会话固定攻击。确保会话ID的复杂性和随机性。
安全解决方案
-
HttpOnly 属性:
-
描述:防止客户端脚本(如JavaScript)访问Cookie,从而避免XSS攻击。
-
示例 :
httpSet-Cookie: sessionId=abc123; HttpOnly
-
-
Secure 属性:
-
描述:确保Cookie只能通过HTTPS连接传输,防止在未加密的连接中被截获。
-
示例 :
httpSet-Cookie: sessionId=abc123; Secure
-
-
SameSite 属性:
-
描述:限制Cookie在跨站请求中的发送行为,帮助防止CSRF攻击。
-
选项 :
Strict
:完全禁止跨站请求发送Cookie。Lax
:允许部分跨站请求(如GET请求)发送Cookie。None
:允许所有跨站请求发送Cookie。
-
示例 :
httpSet-Cookie: sessionId=abc123; SameSite=Strict
-
-
加密和签名:
- 描述:对Cookie数据进行加密和签名,防止被篡改和伪造。
- 实现:可以使用JWT(JSON Web Token)或其他加密算法来实现。
-
CSRF令牌:
-
描述:在每个敏感操作的请求中包含一个唯一的CSRF令牌,以验证请求的合法性。
-
示例 :在表单中包含一个隐藏字段,用于存储CSRF令牌。
html<input type="hidden" name="csrf_token" value="unique_token_value">
-
以下是如何在JavaScript中实现前面提到的Cookie安全措施的示例。我们将使用Express.js作为服务器框架,并在前端使用纯JavaScript来演示如何设置和读取Cookie。
1. 安装和配置Express.js
首先,确保你已经安装了Node.js和npm,然后创建一个新的项目并安装Express和cookie-parser中间件。
bash
npm init -y
npm install express cookie-parser
创建一个名为server.js
的文件,设置Express服务器并配置Cookie安全措施。
服务器代码(server.js):
javascript
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
const port = 3000;
// 使用cookie-parser中间件
app.use(cookieParser());
// 设置安全的Cookie
app.get('/set-cookie', (req, res) => {
res.cookie('sessionId', 'abc123', {
maxAge: 900000,
httpOnly: true,
secure: true,
sameSite: 'Strict'
});
res.send('Secure cookie has been set');
});
// 读取Cookie
app.get('/get-cookie', (req, res) => {
const sessionId = req.cookies.sessionId || 'No session';
res.send(`Session ID: ${sessionId}`);
});
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
在这个示例中,我们设置了一个名为sessionId
的Cookie,具有以下安全属性:
httpOnly
: 确保Cookie只能通过服务器端脚本访问。secure
: 确保Cookie只能通过HTTPS连接传输。sameSite: 'Strict'
: 限制Cookie在跨站请求中的发送行为,防止CSRF攻击。
2. 前端代码
在前端,我们可以使用纯JavaScript来设置和读取Cookies。以下是一个示例,展示了如何在前端设置和读取Cookie。
创建一个名为index.html
的文件,并编写以下代码:
前端代码(index.html):
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cookie Example</title>
</head>
<body>
<h1>Cookie Example</h1>
<button onclick="setClientCookie()">Set Client Cookie</button>
<button onclick="getClientCookie()">Get Client Cookie</button>
<button onclick="setServerCookie()">Set Server Cookie</button>
<button onclick="getServerCookie()">Get Server Cookie</button>
<p id="output"></p>
<script>
// 设置客户端Cookie
function setClientCookie() {
document.cookie = "clientCookie=javascript_user; max-age=3600; path=/";
document.getElementById('output').innerText = "Client cookie has been set";
}
// 读取客户端Cookie
function getClientCookie() {
const cookies = document.cookie.split('; ').reduce((prev, current) => {
const [name, value] = current.split('=');
prev[name] = value;
return prev;
}, {});
const clientCookie = cookies.clientCookie || 'No client cookie';
document.getElementById('output').innerText = `Client Cookie: ${clientCookie}`;
}
// 设置服务器端Cookie
function setServerCookie() {
fetch('http://localhost:3000/set-cookie', {
credentials: 'include'
})
.then(response => response.text())
.then(data => {
document.getElementById('output').innerText = data;
});
}
// 读取服务器端Cookie
function getServerCookie() {
fetch('http://localhost:3000/get-cookie', {
credentials: 'include'
})
.then(response => response.text())
.then(data => {
document.getElementById('output').innerText = data;
});
}
</script>
</body>
</html>
在这个示例中:
setClientCookie
函数设置一个名为clientCookie
的客户端Cookie。getClientCookie
函数读取并显示客户端Cookie。setServerCookie
函数向服务器发送请求,设置服务器端的安全Cookie。getServerCookie
函数向服务器发送请求,读取服务器端的Cookie。
Cookie的过期是指当一个Cookie超过其设定的有效期后,浏览器会自动删除该Cookie。以下是Cookie过期过程的详细解释:
设置Cookie的过期时间
-
Expires 属性:
-
Expires
属性指定了Cookie的过期日期和时间。格式通常为UTC时间。 -
示例 :
httpSet-Cookie: sessionId=abc123; Expires=Wed, 21 Oct 2025 07:28:00 GMT
-
-
Max-Age 属性:
-
Max-Age
属性指定了Cookie的有效期(以秒为单位)。当该时间过去后,Cookie会过期并被删除。 -
示例 :
httpSet-Cookie: sessionId=abc123; Max-Age=3600
-
Cookie的过期过程
-
设置Cookie:
- 当服务器通过
Set-Cookie
头部设置一个Cookie时,可以指定该Cookie的过期时间或有效期。 - 浏览器接收到
Set-Cookie
头部后,会根据指定的Expires
或Max-Age
属性来存储Cookie。
- 当服务器通过
-
Cookie的存储:
- 浏览器会将Cookie存储在本地,并记录其过期时间或剩余的有效期。
-
检查过期时间:
- 每次浏览器发送请求时,都会检查已存储的Cookie的有效期。如果Cookie的过期时间已经到达或剩余的有效期已经为0,浏览器将不再发送该Cookie,并从本地存储中删除它。
示例代码
以下是一个示例,展示了如何通过JavaScript设置和检查Cookie的过期时间:
设置Cookie的函数:
javascript
function setCookie(name, value, expires) {
let cookieString = `${name}=${value}; path=/`;
if (expires) {
cookieString += `; expires=${expires.toUTCString()}`;
}
document.cookie = cookieString;
}
// 设置一个有效期为1天的Cookie
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 1);
setCookie('username', 'john_doe', expiryDate);
读取和检查Cookie的函数:
javascript
function getCookie(name) {
const cookieArray = document.cookie.split('; ');
for (let i = 0; i < cookieArray.length; i++) {
const cookiePair = cookieArray[i].split('=');
if (cookiePair[0] === name) {
return cookiePair[1];
}
}
return null;
}
// 检查Cookie是否存在
const username = getCookie('username');
if (username) {
console.log(`Username Cookie: ${username}`);
} else {
console.log('Username Cookie has expired or does not exist');
}
Expires
和 Max-Age
属性可以在不同的上下文中使用,即在HTTP响应头和Cookie设置中。这两个属性虽然有相似的名字,但它们的作用和使用场景有所不同。让我们详细比较它们在HTTP响应头和Cookie设置中的关系和区别:
Cookie 的 Expires
和 Max-Age
属性
作用: 控制Cookie的有效期。
-
Expires: 指定Cookie的过期日期和时间。格式通常为UTC时间。
-
示例 :
httpSet-Cookie: sessionId=abc123; Expires=Wed, 21 Oct 2025 07:28:00 GMT
-
-
Max-Age: 指定Cookie的有效期(以秒为单位)。当该时间过去后,Cookie会过期并被删除。
-
示例 :
httpSet-Cookie: sessionId=abc123; Max-Age=3600
-
解释:
Expires
:绝对时间,到达指定日期和时间后,Cookie将失效。Max-Age
:相对时间,从设置Cookie的时间开始计时,经过指定的秒数后,Cookie将失效。
HTTP 响应头 的 Expires
和 Max-Age
属性
作用: 控制HTTP响应的缓存行为。
-
Expires: 指定资源的过期日期和时间。浏览器在这个时间之前,可以直接从缓存中获取资源,而不需要向服务器发送请求。格式通常为UTC时间。
-
示例 :
httpExpires: Wed, 21 Oct 2025 07:28:00 GMT
-
-
Cache-Control: max-age: 指定资源的最大缓存时间(以秒为单位)。浏览器在这个时间段内,可以直接从缓存中获取资源,而不需要向服务器发送请求。
-
示例 :
httpCache-Control: max-age=3600
-
解释:
Expires
:绝对时间,到达指定日期和时间后,资源被认为是过期的,需要重新从服务器获取。Cache-Control: max-age
:相对时间,从接收到响应的时间开始计时,经过指定的秒数后,资源被认为是过期的,需要重新从服务器获取。
区别和联系
-
作用对象不同:
Cookie的Expires和Max-Age
:控制Cookie的有效期,决定浏览器何时删除Cookie。HTTP响应头的Expires和Max-Age
:控制资源的缓存行为,决定浏览器何时重新请求资源。
-
时间表示方式不同:
Expires
:使用绝对时间(UTC时间)。Max-Age
:使用相对时间(以秒为单位)。
-
使用场景不同:
Cookie的Expires和Max-Age
:用于设置和管理Cookie的生命周期。HTTP响应头的Expires和Max-Age
:用于管理资源的缓存策略,提高网页的加载速度和性能。
示例
设置Cookie过期时间:
http
Set-Cookie: username=johndoe; Expires=Wed, 21 Oct 2025 07:28:00 GMT; Path=/
Set-Cookie: sessionId=abc123; Max-Age=3600; Path=/
设置HTTP响应头的缓存策略:
http
HTTP/1.1 200 OK
Expires: Wed, 21 Oct 2025 07:28:00 GMT
Cache-Control: max-age=3600
Content-Type: application/json
{ "id": 1, "name": "John Doe" }