乐闻世界logo
搜索文章和话题

什么是 SameSite Cookie?如何使用 SameSite Cookie 防止 CSRF 和 XSS 攻击?

2月21日 16:27

答案

SameSite Cookie 属性是防止 CSRF 和 XSS 攻击的重要安全机制。它控制浏览器是否在跨站请求中发送 Cookie,从而减少攻击面。

定义: SameSite 是 Cookie 的一个属性,用于控制浏览器在跨站请求中是否发送 Cookie。它可以帮助防止 CSRF 攻击,并在一定程度上减少 XSS 攻击的影响。

基本语法:

javascript
// 设置 SameSite Cookie res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' // 或 'lax' 或 'none' });

1. Strict 模式

定义: Strict 模式是最严格的 SameSite 策略。浏览器只会在同站请求(Same-Site)中发送 Cookie,跨站请求(Cross-Site)不会发送 Cookie。

使用场景:

  • 需要最高安全性的场景
  • 银行、金融等敏感应用
  • 不需要跨站访问的应用

示例:

javascript
// 设置 Strict 模式 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' });

行为:

shell
同站请求(Same-Site): - https://example.com/page1 → https://example.com/page2 - Cookie 会被发送 ✓ 跨站请求(Cross-Site): - https://attacker.com → https://example.com/api - Cookie 不会被发送 ✗

2. Lax 模式

定义: Lax 模式是相对宽松的 SameSite 策略。浏览器在同站请求和某些安全的跨站导航请求中发送 Cookie,但在大多数跨站请求中不发送 Cookie。

使用场景:

  • 需要平衡安全性和用户体验的场景
  • 电商、社交媒体等应用
  • 需要跨站导航的应用

示例:

javascript
// 设置 Lax 模式 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'lax' });

行为:

shell
同站请求(Same-Site): - https://example.com/page1 → https://example.com/page2 - Cookie 会被发送 ✓ 安全的跨站导航(Top-Level Navigation): - 用户点击链接:https://attacker.com → https://example.com/page - Cookie 会被发送 ✓ 不安全的跨站请求: - https://attacker.com 中的 <img> 标签请求 https://example.com/api - Cookie 不会被发送 ✗ - https://attacker.com 中的 fetch 请求 https://example.com/api - Cookie 不会被发送 ✗

3. None 模式

定义: None 模式是最宽松的 SameSite 策略。浏览器在所有请求(包括跨站请求)中都会发送 Cookie。

使用场景:

  • 需要跨站访问的应用
  • 第三方集成应用
  • 需要在 iframe 中访问的应用

示例:

javascript
// 设置 None 模式 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, // None 模式必须设置 secure sameSite: 'none' });

行为:

shell
所有请求: - 同站请求:Cookie 会被发送 ✓ - 跨站请求:Cookie 会被发送 ✓ - iframe 中的请求:Cookie 会被发送 ✓

1. 服务器端设置

Node.js Express:

javascript
// 设置 SameSite Cookie app.use(session({ secret: 'your-secret-key', cookie: { httpOnly: true, secure: true, sameSite: 'strict' // 或 'lax' 或 'none' } })); // 单独设置 Cookie res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' });

PHP:

php
// 设置 SameSite Cookie setcookie('sessionId', $sessionId, [ 'expires' => time() + 3600, 'path' => '/', 'domain' => 'example.com', 'secure' => true, 'httponly' => true, 'samesite' => 'Strict' // 或 'Lax' 或 'None' ]);

Python Flask:

python
from flask import Flask, make_response app = Flask(__name__) @app.route('/login') def login(): resp = make_response('Login successful') resp.set_cookie('sessionId', session_id, httponly=True, secure=True, samesite='Strict') # 或 'Lax' 或 'None' return resp

Java Spring Boot:

java
import javax.servlet.http.Cookie; @GetMapping("/login") public String login(HttpServletResponse response) { Cookie cookie = new Cookie("sessionId", sessionId); cookie.setHttpOnly(true); cookie.setSecure(true); cookie.setAttribute("SameSite", "Strict"); // 或 "Lax" 或 "None" response.addCookie(cookie); return "Login successful"; }

2. 配置示例

Nginx 配置:

nginx
server { listen 443 ssl; server_name example.com; location / { proxy_set_header Set-Cookie "sessionId=$upstream_http_set_cookie; HttpOnly; Secure; SameSite=Strict"; proxy_pass http://backend; } }

Apache 配置:

apache
<VirtualHost *:443> ServerName example.com DocumentRoot /var/www/html Header edit Set-Cookie "(^.*; HttpOnly; Secure; SameSite=Strict)$" "$1" </VirtualHost>

1. 防止 CSRF 攻击

攻击场景:

html
<!-- 攻击者构造的恶意页面 --> <html> <body> <form action="http://bank.com/transfer" method="POST" style="display:none;"> <input type="hidden" name="to" value="attacker"> <input type="hidden" name="amount" value="10000"> </form> <script> document.forms[0].submit(); </script> </body> </html>

SameSite=Strict 防护:

javascript
// 服务器端设置 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' }); // 攻击结果: // - 恶意页面发起的跨站 POST 请求 // - 浏览器不会发送 Cookie // - 攻击失败 ✓

SameSite=Lax 防护:

javascript
// 服务器端设置 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'lax' }); // 攻击结果: // - 恶意页面发起的跨站 POST 请求 // - 浏览器不会发送 Cookie // - 攻击失败 ✓

2. 允许安全的跨站导航

SameSite=Lax 的优势:

javascript
// 服务器端设置 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'lax' }); // 用户行为: // - 用户在邮件中点击链接:https://example.com/page // - 这是安全的跨站导航(Top-Level Navigation) // - 浏览器会发送 Cookie // - 用户正常访问 ✓

1. 减少 XSS 攻击的影响

攻击场景:

javascript
// 攻击者通过 XSS 注入恶意脚本 <script> fetch('http://bank.com/transfer', { method: 'POST', body: JSON.stringify({ to: 'attacker', amount: 10000 }), credentials: 'include' }); </script>

SameSite=Strict 防护:

javascript
// 服务器端设置 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' }); // 攻击结果: // - XSS 脚本发起的跨站请求(从攻击者的网站) // - 浏览器不会发送 Cookie // - 攻击失败 ✓

SameSite=Lax 防护:

javascript
// 服务器端设置 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'lax' }); // 攻击结果: // - XSS 脚本发起的跨站请求(从攻击者的网站) // - 浏览器不会发送 Cookie // - 攻击失败 ✓

2. 限制同站 XSS 的影响

SameSite 的局限性:

javascript
// 服务器端设置 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' }); // 攻击场景: // - 攻击者在同站页面注入 XSS // - XSS 脚本发起同站请求 // - 浏览器会发送 Cookie // - 攻击可能成功 ✗

解决方案:

javascript
// 结合 HttpOnly Cookie res.cookie('sessionId', sessionId, { httpOnly: true, // 防止 JavaScript 访问 Cookie secure: true, sameSite: 'strict' }); // 结合 Content Security Policy app.use((req, res, next) => { res.setHeader('Content-Security-Policy', "default-src 'self'; " + "script-src 'self'; " + "style-src 'self' 'unsafe-inline';" ); next(); });

1. 根据应用类型选择模式

高安全性应用(银行、金融):

javascript
// 使用 Strict 模式 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' });

一般应用(电商、社交媒体):

javascript
// 使用 Lax 模式 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'lax' });

需要跨站访问的应用(第三方集成):

javascript
// 使用 None 模式 res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, // 必须设置 sameSite: 'none' });

2. 结合其他安全措施

多层防护:

javascript
// 1. 设置 SameSite Cookie res.cookie('sessionId', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' }); // 2. 设置 Content Security Policy app.use((req, res, next) => { res.setHeader('Content-Security-Policy', "default-src 'self'; " + "script-src 'self'; " + "style-src 'self' 'unsafe-inline';" ); next(); }); // 3. 使用 CSRF Token app.post('/api/transfer', csrfProtection, (req, res) => { // 处理转账请求 });

3. 测试和验证

测试 SameSite Cookie:

javascript
// 测试 Strict 模式 async function testStrictMode() { // 同站请求 const sameSiteResponse = await fetch('https://example.com/api/data'); console.log('Same-Site Request:', sameSiteResponse.status); // 跨站请求 const crossSiteResponse = await fetch('https://example.com/api/data', { mode: 'cors', credentials: 'include' }); console.log('Cross-Site Request:', crossSiteResponse.status); } // 测试 Lax 模式 async function testLaxMode() { // 测试安全的跨站导航 const link = document.createElement('a'); link.href = 'https://example.com/page'; link.click(); }

1. 浏览器支持

支持的浏览器:

  • Chrome 51+(2016年)
  • Firefox 60+(2018年)
  • Safari 12+(2018年)
  • Edge 79+(2020年)
  • Opera 39+(2016年)

不支持的浏览器:

  • Internet Explorer(所有版本)
  • 旧版本的移动浏览器

2. 兼容性处理

降级策略:

javascript
// 检测浏览器是否支持 SameSite function supportsSameSite() { try { document.cookie = 'testCookie=1; SameSite=Strict'; return document.cookie.includes('testCookie'); } catch (e) { return false; } } // 根据浏览器支持设置 Cookie function setSecureCookie(name, value) { if (supportsSameSite()) { res.cookie(name, value, { httpOnly: true, secure: true, sameSite: 'strict' }); } else { // 降级策略:使用其他安全措施 res.cookie(name, value, { httpOnly: true, secure: true }); // 使用 CSRF Token generateCSRFToken(); } }

实际案例分析

案例 1:在线银行

问题: 在线银行频繁遭受 CSRF 攻击,导致用户资金被盗。

解决方案:

javascript
// 设置 Strict 模式 app.use(session({ secret: 'bank-secret-key', cookie: { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 3600000 // 1小时过期 } })); // 结果: // - CSRF 攻击被阻止 ✓ // - 用户需要从银行网站内部发起转账 // - 安全性大幅提高 ✓

案例 2:电商平台

问题: 电商平台需要允许用户从邮件链接访问,但又要防止 CSRF 攻击。

解决方案:

javascript
// 设置 Lax 模式 app.use(session({ secret: 'ecommerce-secret-key', cookie: { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 86400000 // 24小时过期 } })); // 结果: // - 用户可以从邮件链接正常访问 ✓ // - CSRF 攻击被阻止 ✓ // - 用户体验和安全性得到平衡 ✓

总结

SameSite Cookie 是防止 CSRF 和减少 XSS 影响的重要安全机制:

SameSite 的三种模式:

  1. Strict:最严格,只允许同站请求发送 Cookie
  2. Lax:相对宽松,允许安全的跨站导航发送 Cookie
  3. None:最宽松,允许所有请求发送 Cookie

SameSite 的最佳实践:

  1. 根据应用类型选择合适的模式
  2. 结合 HttpOnly Cookie 和 CSP
  3. 使用 CSRF Token 作为额外防护
  4. 测试和验证 SameSite 设置
  5. 处理浏览器兼容性问题

SameSite 的局限性:

  1. 不能完全防止同站 XSS 攻击
  2. 不支持旧版本浏览器
  3. None 模式需要设置 secure 属性
  4. 可能影响某些跨站功能

通过正确使用 SameSite Cookie 并结合其他安全措施,可以有效地防止 CSRF 攻击,减少 XSS 攻击的影响,提高 Web 应用的安全性。

标签:XSS