关于 consent-record-keeping
用于设计 GDPR 同意记录流程的技能,面向负责隐私与数据治理的团队。内容涵盖记录字段、不可变存储和 Kantara 机器可读收据格式。
主要功能
- 01规定必需与建议记录字段
- 02说明追加写入与哈希链
- 03介绍 Kantara 收据格式
- 04提供数据库与审计查询示例
适用场景
- 01设计同意记录数据库结构
- 02核验同意记录的完整性
- 03按时间重建用户同意状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mukul975/ privacy-data-protection-skills --skill consent-record-keeping安装后在 Claude Code 中输入/consent-record-keeping确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/template.mdreferences/standards.mdworkflows.mdscripts/process.py详细介绍
构建同意记录系统
概述
GDPR 第 7(1) 条规定:“当处理基于同意时,控制者应能够证明数据主体已同意处理其个人数据。”证明同意的义务要求进行全面的记录保存,不仅要记录同意决定,还要记录作出决定时的背景。
Kantara Initiative Consent Receipt Specification(v1.1)为同意回执提供了标准化的机器可读格式,既满足监管要求,也支持互操作性。
必需的记录字段
根据 EDPB Guidelines 05/2020(第 89-107 段),证明同意需要保留以下证据:
核心字段(必填)
| 字段 | 描述 | GDPR 参考 | 格式 |
|---|---|---|---|
| consent_id | 此同意决定的唯一标识符 | Art. 7(1) | UUID v4 |
| subject_id | 数据主体的标识符 | Art. 7(1) | UUID v4 |
| purpose_id | 处理目的的标识符 | Art. 6(1)(a) | 目的代码 |
| purpose_description | 对目的的通俗描述 | Art. 13(1)(c) | 文本 |
| decision | 是否授予同意 | Art. 7(1) | 枚举:granted、not_granted |
| timestamp | 作出决定的时间 | Art. 7(1) | ISO 8601 UTC |
| mechanism | 表达同意的方式 | Art. 4(11) | 枚举:checkbox_tick、toggle_switch、typed_statement、signature |
| consent_text_version | 所显示确切同意文本的哈希值 | Art. 7(1) | SHA-256 十六进制 |
| consent_text | 向数据主体呈现的确切文本 | Art. 7(2) | 完整文本 |
| controller_name | 数据控制者的法定名称 | Art. 13(1)(a) | 文本 |
| controller_contact | 控制者的联系信息 | Art. 13(1)(a) | 文本 |
上下文字段(建议)
| 字段 | 描述 | GDPR 参考 | 格式 |
|---|---|---|---|
| ip_address | 同意时的 IP 地址 | Art. 7(1) 证明 | IPv4/IPv6 |
| user_agent | 浏览器/设备的 user agent 字符串 | Art. 7(1) 证明 | 文本 |
| session_id | 会话标识符 | Art. 7(1) 证明 | UUID |
| source | 收集同意的位置 | Art. 7(1) 证明 | 枚举:signup、preference_center、cookie_banner |
| data_categories | 此目的涉及的个人数据类别 | Art. 13(1)(d) | JSON 数组 |
| recipients | 列明的第三方接收方 | Art. 13(1)(e) | JSON 数组 |
| retention_period | 为此目的保留数据的时长 | Art. 13(2)(a) | 文本 |
| withdrawal_info | 撤回同意的说明 | Art. 7(3) | 文本 |
| dpo_contact | DPO 联系信息 | Art. 13(1)(b) | 文本 |
不可变性要求
同意记录必须不可变。记录同意决定后,不得更改。为此需要:
- 仅追加存储:使用仅追加数据库表或不可变日志存储。绝不 UPDATE 或 DELETE 同意记录。
- 完整性哈希:每条记录都包含其内容的 SHA-256 哈希值。任何篡改都可被检测。
- 链式哈希:每条记录的哈希值都包含上一条记录的哈希值,从而形成可验证的链(类似区块链概念,但无需分布式账本的开销)。
- 时间戳完整性:时间戳由服务端生成(而非由客户端提供),以防止被操纵。
Kantara Initiative Consent Receipt 格式
Kantara Initiative Consent Receipt Specification v1.1 定义了一种 JSON 格式:
{
"version": "KI-CR-v1.1.0",
"jurisdiction": "EU/GDPR",
"consentTimestamp": "2026-03-14T10:30:00Z",
"collectionMethod": "web form with unticked checkboxes",
"consentReceiptID": "cr_7f3a9b2e-41d8-4c76-b5e3-9a8d1c2f4e60",
"publicKey": "cloudvault-saas-public-key-fingerprint",
"language": "en",
"piiPrincipalId": "usr_7f3a9b2e-41d8-4c76-b5e3-9a8d1c2f4e60",
"piiControllers": [
{
"piiController": "CloudVault SaaS Inc.",
"onBehalf": false,
"contact": "42 Innovation Drive, Dublin, D02 YX88, Ireland",
"phone": "+353-1-555-0142",
"email": "[email protected]",
"piiControllerUrl": "https://cloudvault-saas.eu"
}
],
"policyUrl": "https://cloudvault-saas.eu/privacy-policy",
"services": [
{
"service": "CloudVault Cloud Storage",
"purposes": [
{
"purpose": "Service Improvement Analytics",
"purposeCategory": ["core function"],
"consentType": "explicit",
"piiCategory": ["file_metadata", "access_frequency", "storage_patterns"],
"primaryPurpose": true,
"termination": "https://app.cloudvault-saas.eu/settings/privacy",
"thirdPartyDisclosure": false
}
]
}
],
"sensitive": false,
"spiCat": []
}
数据库架构
-- Consent records table (append-only, never UPDATE or DELETE)
CREATE TABLE consent_records (
consent_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
subject_id UUID NOT NULL,
purpose_id VARCHAR(128) NOT NULL,
purpose_description TEXT NOT NULL,
decision VARCHAR(16) NOT NULL CHECK (decision IN ('granted', 'not_granted', 'withdrawn')),
mechanism VARCHAR(64) NOT NULL,
consent_text_version CHAR(64) NOT NULL,
timestamp_utc TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
ip_address INET,
user_agent TEXT,
session_id UUID,
source VARCHAR(64) NOT NULL,
controller_name VARCHAR(256) NOT NULL DEFAULT 'CloudVault SaaS Inc.',
record_hash CHAR(64) NOT NULL,
previous_hash CHAR(64),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
);
-- Index for efficient lookups per subject
CREATE INDEX idx_consent_records_subject ON consent_records(subject_id, purpose_id, timestamp_utc DESC);
-- Consent text versions (immutable)
CREATE TABLE consent_text_versions (
version_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
purpose_id VARCHAR(128) NOT NULL,
consent_text TEXT NOT NULL,
text_hash CHAR(64) NOT NULL UNIQUE,
approved_by VARCHAR(256) NOT NULL,
effective_from TIMESTAMP WITH TIME ZONE NOT NULL,
effective_until TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
);
-- Prevent modifications to consent records
REVOKE UPDATE, DELETE ON consent_records FROM app_user;
REVOKE UPDATE, DELETE ON consent_text_versions FROM app_user;
审计查询示例
重建某个主体在特定时间点的同意状态:
SELECT DISTINCT ON (purpose_id)
purpose_id, decision, timestamp_utc, consent_text_version, mechanism, source
FROM consent_records
WHERE subject_id = 'usr_7f3a9b2e-41d8-4c76-b5e3-9a8d1c2f4e60'
AND timestamp_utc <= '2026-02-15T00:00:00Z'
ORDER BY purpose_id, timestamp_utc DESC;
验证记录链的完整性:
SELECT consent_id, record_hash, previous_hash,
CASE WHEN LAG(record_hash) OVER (ORDER BY created_at) = previous_hash
THEN 'VALID' ELSE 'BROKEN'
END AS chain_status
FROM consent_records
WHERE subject_id = 'usr_7f3a9b2e-41d8-4c76-b5e3-9a8d1c2f4e60'
ORDER BY created_at;
关键监管参考
- GDPR 第 7(1) 条——控制者必须证明已获得同意
- GDPR 第 7(2) 条——同意文本要求(清晰、通俗易懂且易于区分)
- GDPR 第 5(2) 条——问责原则
- GDPR 第 30 条——处理活动记录(同意记录可为此提供支持)
- EDPB《05/2020 号指南》——第 89–107 段,关于证明已获得同意
- Kantara Initiative《Consent Receipt Specification v1.1》——机器可读的收据格式
- ISO/IEC 29184:2020——在线隐私声明和同意
评论
支持 Markdown