核心概念
HttpOnly 与客户端存储
标记为 HttpOnly 的 Cookie 无法通过客户端 JavaScript(cookieStore 或 document.cookie)访问或修改。但是,浏览器**会自动将有效的 HttpOnly Cookie 附加到出站 HTTP 请求头(Cookie)**中。
- 检查当前
HttpOnly值:通过get_network_request查看任何出站 HTTP 请求的Cookie请求头。 - 检查 Cookie 的创建或配置方式:查看登录/认证响应的
Set-Cookie响应头。 - 检查非
HttpOnlyCookie:使用带有现代cookieStoreAPI 的evaluate_script(async () => await cookieStore.getAll())。
会话策略:活动标签页与隔离上下文
选择合适的会话环境,避免状态污染(例如残留的分析或认证令牌):
| 策略 | 使用场景 | 设置/拆除 |
|---|---|---|
| 活动标签页(当前页面) | 诊断活动用户会话、实时 401/403 错误或当前状态。 | 直接在当前选定的页面上操作。 |
全新环境(isolatedContext) | 测试 Cookie 同意横幅、首次访问或零 Cookie 保证。 | 使用唯一的 isolatedContext(例如 "consent-audit-1")调用 new_page。完成后调用 close_page。 |
客户端能力与限制
| 操作 | 客户端 JavaScript(cookieStore / document.cookie) | DevTools 网络和上下文工具 |
|---|---|---|
| 读取非 HttpOnly | ✅ async () => await cookieStore.getAll() | ✅ get_network_request(请求 Cookie) |
| 读取 HttpOnly | ❌ 被浏览器安全阻止 | ✅ get_network_request(请求 Cookie) |
检查属性(Domain、Path、SameSite、Expires) | ✅ async () => await cookieStore.getAll() | ✅ get_network_request(响应 Set-Cookie) |
| 修改/删除非 HttpOnly | ✅ async () => await cookieStore.set(...) | 不适用 |
| 修改/删除 HttpOnly | ❌ JavaScript 中静默失败 | ✅ 使用 new_page(isolatedContext: ...) 获得干净状态 |
[!WARNING] 尝试通过 JavaScript(
cookieStore.delete或document.cookie = "...; max-age=0")清除HttpOnlyCookie 将静默失败。要在未认证或全新状态下测试,请始终使用new_page和isolatedContext创建一个新的隔离上下文。
工作流模式
1. 诊断认证失败与重定向(401/403)
当经过身份验证的页面请求失败、返回 401/403 或重定向到登录页面时:
- 列出最近的请求:调用
list_network_requests并设置includePreservedRequests: true。 - 查找目标请求:定位失败请求(401/403)或重定向请求(302/307)。
- 检查出站
Cookie头:使用reqid调用get_network_request。- 验证
Cookie头是否已附加,以及是否发送了必需的令牌(例如SESSION_ID、auth_token)。
- 验证
- 触发主动检查(如果没有最近的请求):
- 如果 Cookie 是在之前会话中设置的,并且没有列出网络调用,则触发一个请求:
- 使用
navigate_page并设置reload: true,或 - 调用
evaluate_script并执行() => fetch(window.location.href)
- 使用
- 然后调用
get_network_request检查新请求的活跃Cookie头。
- 如果 Cookie 是在之前会话中设置的,并且没有列出网络调用,则触发一个请求:
- 追溯设置请求:如果 Cookie 缺失或被拒绝:
- 检查早期登录/握手响应中的
Set-Cookie指令:- 路径不匹配:例如
Path=/api但请求是针对/。 - 域名不匹配:例如
Domain=api.example.com导致 Cookie 无法用于sub.example.com。 - HTTP 上的 Secure 标志:
SecureCookie 永远不会通过未加密的http://发送。 - SameSite 阻止:
SameSite=StrictCookie 在跨站点导航中被省略。 - 过期:检查
Expires或Max-Age是否已过。
- 路径不匹配:例如
- 检查早期登录/握手响应中的
2. Cookie 横幅与同意合规性测试
验证在同意前或拒绝后没有设置非必要或跟踪 Cookie:
- 全新开始:使用专用名称打开一个隔离上下文:
{"url": "<PAGE_URL>", "isolatedContext": "consent-test-1"} - 记录基准 Cookie:在与横幅交互之前,运行
evaluate_script并执行async () => await cookieStore.getAll()。 - 检查过早的网络请求和问题:
- 调用
list_network_requests以确保在同意前没有触发第三方跟踪信标。 - 调用
list_console_messages并设置types: ["issue"]以检查跟踪警告。
- 调用
- 与同意横幅交互:
- 使用
take_snapshot捕获快照,找到“拒绝”或“全部拒绝”按钮的uid。 - 使用
click点击按钮。
- 使用
- 验证 Cookie 差异:
- 点击后运行
evaluate_script并执行async () => await cookieStore.getAll(),断言只存在严格必要的或同意状态 Cookie。
- 点击后运行
- 测试同意撤销(生命周期审计):
- 审计同意撤回或偏好更改时:
- 定位并点击“Cookie 设置”、“管理偏好”或页脚隐私触发器(
take_snapshot→click)。 - 取消选择非必要类别,或点击“全部撤销”/“保存偏好”。
- 重新查询
cookieStore.getAll(),验证先前接受的非必要 Cookie 已被清除或过期。 - 在后续操作上调用
list_network_requests,确保不再触发跟踪信标。
- 定位并点击“Cookie 设置”、“管理偏好”或页脚隐私触发器(
- 审计同意撤回或偏好更改时:
- 拆除上下文:审计完成后调用
close_page,防止残留 Cookie 影响后续任务。
3. 审计 Cookie 安全、SameSite 和 CHIPS(分区 Cookie)
- 快速通道:原生 DevTools 问题(推荐):
- 调用
list_console_messages并设置:{ "types": ["issue"], "includePreservedMessages": true } - 检查
CookieIssue条目,例如:SameSiteNoneInsecure:SameSite=None未设置Secure。ThirdPartyCookiePhaseout:第三方 Cookie 被阻止或限制。SchemefulSameSite:跨方案 Cookie 问题。PartitionedCookies:无效的 CHIPS 分区属性。
- 调用
- 深度审计:Lighthouse 第三方 Cookie:
- 运行
lighthouse_audit并设置mode: "navigation"和outputDirPath: "/tmp/lh-report"。 - 提取特定的 Cookie 审计结果,无需将完整报告加载到上下文中:
node -e "const r=require('/tmp/lh-report/report.json'); const a=r.audits['third-party-cookies']; console.log(JSON.stringify({score: a?.score, display
- 运行