Front-End Checklist Cookie Consent 规则:GDPR 合规的 Cookie 同意机制从审查到实现
2026/9/18 16:44:53 网站建设 项目流程

Front-End Checklist Cookie Consent 规则:GDPR 合规的 Cookie 同意机制从审查到实现

【免费下载链接】Front-End-Checklist🗂 The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-Checklist

本文基于 Front-End Checklist 仓库中的cookie-consent技能文档(skills/cookie-consent/SKILL.md)及其完整规则正文(skills/cookie-consent/references/rule.md),系统讲解“展示 Cookie 同意提示”这一隐私审查规则:它要求网站在放置非必要 Cookie(分析、广告、个性化)之前必须先获得用户知情同意。读完后,你将掌握 Cookie 分类与同意要求、符合 GDPR 的手动实现代码(TypeScript 同意存储 + React 同意横幅 + Google Consent Mode v2),以及一套可执行的验证清单,能够对真实站点或代码库进行合规审查并落地修复。

一、这条规则在仓库中的定位

cookie-consent是 Front-End Checklist 面向“人类与 AI Agent”的规则语料中的一条privacy类别规则,其元数据在 SKILL.md 的 frontmatter 中声明:

  • category: privacypriority: highdifficulty: intermediateestimatedTime: "30"(分钟);
  • aiContext说明了适用场景:审查网站 GDPR/CCPA 合规性时,确认是否在设置非必要 Cookie 之前获得了同意。

该技能文件是由规则源文件 packages/content/rules/en/privacy/cookie-consent.mdx 自动生成而来。生成脚本 scripts/generate/generate-skills.ts 会把每条规则 MDX 转换为skills/{slug}/SKILL.md(frontmatter + check/fix/explain/codeReview 提示词)与references/rule.md(MDX 正文剥离 JSX 后的纯 Markdown)两个产物,仓库通过pnpm generate:skills重新生成。因此本文所讲的每一条内容都能在 MDX 源规则中找到对应依据,两处表述一致。

技能可被 Agent 直接安装使用(见 README.md 与生成脚本头部注释):

npx skills add frontendchecklist/skills npx skills add frontendchecklist/skills --skill cookie-consent

二、合规背景与风险:为什么这条规则优先级为 high

GDPR 违规最高可处以2000 万欧元或全球年营业额 4%(取较高者)的罚款,欧盟各监管机构已实际对“未经有效同意部署追踪 Cookie”的组织开出罚单。这一风险说明同时出现在 SKILL.md 与 references/rule.md 的 “Why It Matters” 部分,也是规则 frontmatter 中priority: high的依据。

适用范围不止于欧盟。规则原文指出:

  • 欧盟GDPRePrivacy 指令要求网站在放置非必要 Cookie 前获得知情同意;
  • 类似要求存在于CCPA(美国加州)、LGPD(巴西)、PIPEDA(加拿大)、PECR(英国)。

规则引用的权威标准(见 cookie-consent.mdx 的sources元数据)包括 GDPR Article 6(处理的合法性)、GDPR Recital 32(同意)以及 ICO 的 PECR Cookie 指南——在判定规则“已满足”之前,实现必须对照这些条款逐项核对。

三、Cookie 分类:哪些需要同意,哪些不需要

规则给出的快速参考(Quick Reference)要点,全部继承自 references/rule.md:

  • GDPR 要求在设置非必要 Cookie(分析、广告、个性化)之前获得同意;
  • 必要/严格必需 Cookie(会话、安全、登录)不需要同意;
  • 同意必须是自由给予(freely given)、具体(specific)、知情(informed)、无歧义(unambiguous)的——预勾选框无效
  • 用户必须能够像给出同意一样容易地撤回同意;
  • 脚本与像素(pixel)必须在用户主动接受对应类别之前不得加载;
  • 非必要追踪器在“同意前”和“撤回后”都必须保持阻断。

完整的 Cookie 分类表如下:

类别示例是否需要同意
Strictly necessary(严格必需)会话 Cookie、CSRF Token、登录状态
Functional(功能性)语言偏好、无障碍设置视情况——若为服务核心则视为必需
Analytics(分析类)Google Analytics、Mixpanel
Advertising(广告类)Google Ads、Facebook Pixel、再营销
Social media(社交媒体)Twitter/LinkedIn 分享按钮、嵌入内容

注意“功能性”这一灰色地带:语言偏好、无障碍开关等,如果它们构成服务本身的核心(例如多语言站点切换语言是服务前提),可能被视为严格必需而豁免;但规则建议从保守侧判定,能分类到“需同意”的就不放进“必需”。

四、什么才算有效同意

规则依据 GDPR 第 4(11) 条对“同意”的定义,给出四项硬性要求:

  1. 自由给予(Freely given)——拒绝必须和接受一样容易,不允许用 cookie wall(不同意就封锁访问)逼迫用户
  2. 具体(Specific)——不同目的必须分开授权(分析类与广告类是两个独立的同意项,不能一揽子打包);
  3. 知情(Informed)——用户必须清楚自己在为什么授权;
  4. 无歧义(Unambiguous)——需要一个明确的肯定性动作,预勾选的复选框不构成有效同意

此外,用户必须能在之后随时重新审视并修改选择,入口应当稳定,例如页脚链接、账户设置或隐私中心。这一点与 SKILL.md Code Review 提示词中“横幅消失后仍存在持久的『修改 Cookie 设置』路径”相互印证。

五、审查清单:Check 与 Code Review 怎么做

规则提供了四组面向 Agent 的提示词(Check / Fix / Explain / Code Review),审查动作上重点关注三件事:

Check(检查)——见 SKILL.md:

  • 站点是否在设置非必要 Cookie 之前展示了 Cookie 同意提示;
  • 分析、广告、追踪脚本是否确实等到用户主动接受后才加载;
  • 用户拒绝非必要 Cookie 后,是否仍能正常访问内容(无 cookie wall)。

Code Review(代码审查)——审查范围覆盖服务端配置、响应头、表单及相关集成点,重点核对:

  • 标记出违反规则的具体响应、Cookie 或浏览器行为,并对照类生产环境(而非本地)的实际响应验证;
  • 追踪器的初始化是否被同意状态“门控”(gated on consent);
  • 横幅关闭之后,是否仍存在可见的“修改 Cookie 设置”持久入口。

Explain(解释)——向非技术干系人说明 GDPR 对 Cookie 同意的要求、必要与非必要 Cookie 的区别、预勾选框为何无效,以及技术上的合规实现长什么样。

六、Fix:CMP 方案与手动实现

规则给出的修复方向有三层:实现一个在获得同意前阻断非必要脚本的 CMP(Consent Management Platform);把分析与追踪标签配置为仅在明确同意后初始化;提供用户随时修改同意偏好的机制。

6.1 使用现成 CMP

规则推荐的合规 CMP 包括:

  • Cookiebot— 自动 Cookie 扫描 + 同意管理;
  • OneTrust— 企业级合规;
  • CookieYes— 面向中小站点;
  • Osano— 对开源友好。

6.2 手动实现:同意必须先于脚本加载

最典型的违规形态是把分析脚本直接写在 HTML 头部、无条件加载。规则给出的正确/错误对照:

<!-- Do NOT load analytics before consent --> <!-- ❌ Wrong: loads before consent --> <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"></script> <!-- ✅ Correct: analytics loaded only after consent --> <script> // Check consent before loading analytics if (getConsentStatus('analytics') === 'granted') { loadGoogleAnalytics() } </script> </code>

6.3 同意存储与版本失效:consent.ts 完整实现

下面是规则中的 TypeScript 实现(以 MDX 源文件 cookie-consent.mdx 中的完整版为准,其中CONSENT_VERSION是关键细节——当同意目的发生变化时必须升级版本号,旧版本的存量同意即被自动作废,用户需要重新被征询同意):

// consent.ts const CONSENT_KEY = 'cookie-consent' const CONSENT_VERSION = 'v2' // Bump when purposes change interface ConsentPreferences { version: string analytics: boolean advertising: boolean functional: boolean timestamp: number } export function getConsent(): ConsentPreferences | null { try { const stored = localStorage.getItem(CONSENT_KEY) if (!stored) return null const parsed = JSON.parse(stored) as ConsentPreferences // Invalidate old consent versions if (parsed.version !== CONSENT_VERSION) return null return parsed } catch { return null } } export function setConsent(preferences: Omit<ConsentPreferences, 'version' | 'timestamp'>) { const consent: ConsentPreferences = { ...preferences, version: CONSENT_VERSION, timestamp: Date.now(), } localStorage.setItem(CONSENT_KEY, JSON.stringify(consent)) applyConsentDecision(consent) } function applyConsentDecision(consent: ConsentPreferences) { if (consent.analytics) { loadGoogleAnalytics() } else { disableAnalyticsCookies() } if (consent.advertising) { loadAdvertisingPixels() } else { disableAdvertisingCookies() } } function loadGoogleAnalytics() { const script = document.createElement('script') script.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXX' script.async = true document.head.appendChild(script) }

从源码结构看,这里的设计要点值得注意:

  • 拒绝即落盘setConsent对“拒绝”同样写入 localStorage。这样下次访问时getConsent()返回非空,横幅不再重复弹出——拒绝本身也是一种需要持久化的决定,且保证“撤回后追踪器保持阻断”这一要求(Quick Reference 第 6 条)成立;
  • 读取即校验版本parsed.version !== CONSENT_VERSION时返回null,等价于把旧同意视为“从未同意”,触发重新征询;
  • 决策集中应用applyConsentDecision是唯一的副作用入口,每个类别都有load*disable*两条路径,保证同意变更(包括撤回)能即时反映到脚本状态。

6.4 React 同意横幅组件

规则给出的 React(客户端组件)实现要点:仅在getConsent()为空时显示横幅;“拒绝非必要”“管理偏好”“接受全部”三条路径对称提供(体现“拒绝与接受同样容易”);“严格必需”复选框checked disabled readOnly,只展示不可取消,因为该类别豁免同意;整个横幅使用role="dialog"aria-modal="true"aria-labelledby保证可访问性:

'use client' import { useState, useEffect } from 'react' import { getConsent, setConsent } from './consent' export function CookieConsentBanner() { const [visible, setVisible] = useState(false) const [showDetails, setShowDetails] = useState(false) const [analytics, setAnalytics] = useState(false) const [advertising, setAdvertising] = useState(false) useEffect(() => { // Show banner only if no consent has been recorded if (!getConsent()) { setVisible(true) } }, []) const acceptAll = () => { setConsent({ analytics: true, advertising: true, functional: true }) setVisible(false) } const rejectAll = () => { setConsent({ analytics: false, advertising: false, functional: false }) setVisible(false) } const savePreferences = () => { setConsent({ analytics, advertising, functional: true }) setVisible(false) } if (!visible) return null return ( <div role="dialog" aria-modal="true" aria-labelledby="consent-title" className="cookie-consent-banner" > <h2 id="consent-title">We use cookies</h2> <p> We use cookies to improve your experience. Some are essential; others help us understand how you use our site.{' '} <a href="/privacy">Privacy Policy</a> </p> {showDetails && ( <div className="consent-details"> <label> <input type="checkbox" checked disabled readOnly /> <strong>Strictly necessary</strong> — required for the site to work </label> <label> <input type="checkbox" checked={analytics} onChange={(e) => setAnalytics(e.target.checked)} /> <strong>Analytics</strong> — helps us understand usage patterns </label> <label> <input type="checkbox" checked={advertising} onChange={(e) => setAdvertising(e.target.checked)} /> <strong>Advertising</strong> — personalised ads </label> </div> )} <div className="consent-actions"> <button onClick={rejectAll}>Reject non-essential</button> <button onClick={() => setShowDetails(!showDetails)}> {showDetails ? 'Hide' : 'Manage preferences'} </button> {showDetails && ( <button onClick={savePreferences}>Save preferences</button> )} <button onClick={acceptAll} className="primary"> Accept all </button> </div> </div> ) }

一个值得对照实现的细节:savePreferencesfunctional: true是硬编码的——因为本例把“功能性”视为站点运转所需(与分类表中“Functional:若为服务核心则视为必需”的判定一致)。如果你的场景里语言偏好不属于服务核心,应改为独立的偏好开关。

6.5 Google Consent Mode v2

如果站点使用 Google Analytics 或 Google Ads,还需要通过 Consent Mode 向 Google 上报同意状态。初始化必须在加载 GTM 或 gtag.js之前完成,默认状态一律denied

// Initialize consent mode BEFORE loading GTM or GA window.dataLayer = window.dataLayer || [] function gtag() { dataLayer.push(arguments) } // Set default state — deny all until consent is given gtag('consent', 'default', { analytics_storage: 'denied', ad_storage: 'denied', ad_user_data: 'denied', ad_personalization: 'denied', wait_for_update: 500, // milliseconds to wait for consent update })

用户在 CMP 中做出选择后,再调用update同步真实状态:

// After user grants consent gtag('consent', 'update', { analytics_storage: userConsent.analytics ? 'granted' : 'denied', ad_storage: userConsent.advertising ? 'granted' : 'denied', })

wait_for_update: 500表示 gtag 在初始化后等待 500ms,给同步脚本(例如从 localStorage 恢复已存同意并调用update)一个时间窗口。仓库中另有一条专门的性能类规则 packages/content/rules/en/performance/consent-mode.mdx,补充了update的完整字段写法(ad_user_dataad_personalization也一并置为granted)与数据建模等要点,可与本规则配合使用。

七、最常见的反模式与验证清单

最典型的反模式(规则中的 Warning 原文强调):许多站点弹出了 Cookie 横幅,但页面里无论用户怎么选,分析与广告脚本照样加载——这不构成 GDPR 合规。横幅只是“告知”,脚本执行才是“行为”;脚本必须在用户主动接受对应类别之后才允许执行。

验证(Verification)分两部分:

自动化检查:

  • 类生产环境(而非本地开发)中测试受影响流程;
  • 任何有意为之的例外都要显式记录在案。

手动检查:

  • 检查最终 HTTP 响应或浏览器行为,确认控制确实被执行(而不只是横幅存在);
  • 确认第三方集成与嵌入在限制生效之后仍然正常工作;
  • 先接受分析类 Cookie,再撤回,确认下一次页面加载时追踪器不再初始化;
  • 确认横幅消失后,仍然可见“Cookie settings”或等价控制入口。

这套验证方法也可以直接用作 CI 或 E2E 断言的设计输入:拒绝态下断言document.querySelectorAll('script[src*="googletagmanager.com"]')为空、撤回后刷新页面再次断言、以及 DOM 中断言“Cookie settings”链接可见。

八、在整套检查清单中的位置

cookie-consent并不是孤立的一条规则。在 packages/content/checklists/en/privacy-and-consent.mdx(Privacy & Consent 检查清单)中,它与数据最小化、隐私政策、被遗忘权、第三方 Cookie、Consent Mode、HTTPS、Referrer-Policy、CSP 等规则组成一次约 35 分钟的隐私专项审查;该清单的审查提示也强调:要“在给出同意之前和之后分别测试站点”,“检查网络请求与存储键,而不只是横幅 UI”,“把第三方脚本纳入隐私审查范围,而不是例外”。

规则 frontmatter 中还声明了四条关联规则,审查时可一并覆盖:

  • third-party-cookies——同属 privacy 领域,常与 Cookie 同意一起审查;
  • privacy-policy——隐私政策文案必须与前端实际行为一致;
  • interstitials(插入层)与 import-on-interaction(交互时再加载)——在真实审计中频繁与本规则交叉,共同影响同一批实现决策。

九、小结

cookie-consent这条规则的核心可以压缩成三句话:同意必须先于行为(脚本不得先于同意加载)、同意必须可撤回且入口持久(横幅之后仍有“修改设置”)、拒绝必须与接受等价(无 cookie wall、无预勾选)。仓库通过“MDX 源规则 → 自动生成的 SKILL.md + references/rule.md → Agent 可安装技能”这条管线,把这套隐私审查标准变成了人和 AI 都能直接执行的检查项;而 references/rule.md 中的consent.ts版本控制、applyConsentDecision双侧决策与 Consent Mode v2 三段式配置,则给出了从零落地一套合规同意机制的完整代码骨架。

【免费下载链接】Front-End-Checklist🗂 The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-Checklist

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询