出海隐私保护系列之 - 百万美金的教训
撰文/ Zheng Bu, Jenny Li, Youbang Wang
编辑/ Felix Wu
前几天和一个律师朋友吃饭的时候,我们说起来加州的消费者隐私法 CCPA,他在2020年的一起著名的隐私诉讼案作为辩方律师,亲身实战了 CCPA 的相当多的细节,最后是通过一个所有人都意想不到的证据赢得了关键的转折点,并且最终成功胜诉。
CCPA 全称是 California Consumer Privacy Act,自2020年1月生效,于同年7月份开始正式执法。CCPA 适用于很大一部分面向美国加州消费者的公司,是迄今为止美国最高的数据保护标准。虽然CCPA 在法律层面只保护加州居民的个人信息,但其影响力带动了整个美国甚至全世界公司对于隐私保护的意识提升。
当时听他讲的庭战的惊心动魄,大家在顶礼膜拜之余,也感慨说加州的隐私保护立法起步较晚,但是执法风暴可能即将到来,这才没过几天,第一个基于 CCPA 的巨额判例就诞生了。
2022年8月29日,加州的总检察长宣布了与国际美妆品牌丝芙兰 Sephora 达成和解协议,和解金额为120万美金(800万人民币)。丝芙兰作为LVMH集团旗下的美妆零售平台,在全世界范围内都有强大的吸金能力,并且在15年的时间里实现了线上线下的全渠道经营,成为在高端美妆行业第一个完成数字化转型的企业。而就是这样一个数据大户,这次在 CCPA 合规上翻了车。
案例详细分析
加州总检察长对丝芙兰的控告如下:
一、丝芙兰没有在隐私政策中写明消费者信息会被“出售”给第三方。(Civil Code Section 1798.130(a)(5))
CCPA 对于“出售”的定义比较宽泛。不光是以客户数据换钱,而是任何形式的以客户数据交换价值都可以被称为“出售”。此次事件中,丝芙兰同意 Google Analytics 以第三方 Cookie 的形式获取和使用丝芙兰的客户数据,作为交换 Google Analytics 为丝芙兰提供免费或者便宜的精准/个性化广告投放,顾客画像,消费者数据等服务,就是一种 CCPA 定义下的“出售”。而丝芙兰堂而皇之的在隐私条款中写道“我们不出售客户数据”,被执法部门逮个正着。
在这次执法之前,丝芙兰的做法可以说是业界正常操作。毕竟主动出售个人信息数据的公司是少数,大部分公司认为自己不主动卖个人信息就不算“出售”。而公司在使用第三方服务,尤其是广告和分析服务时,也会冠上“为了提升客户的体验”或“为了品牌宣传和营销”的正当理由。然而在 CCPA 这儿,这一套已然行不通。
那未来如果跟 Google Analytics 或类似的第三方数据处理合作从此都要被打上“出售“个人数据的标签了吗?这对于不少公司来说是个大麻烦,因为不光隐私合规要求会随之增加,客户心里也容易对公司留下不信任的印象。在这个问题上,加州总检察长 Rob Bonta 给出了两点建议,来降低公司被打上“出售用户资料”标签的风险:
二、丝芙兰没有在明显的位置为客户提供“Do Not Sell My Personal Information“(”不要出售我的信息“)选择。 (Civil Code Section 1798.135(a))
CCPA 的特点之一是为加州居民提供了退出的权利。公司在搜集用户信息时需要在明显的,容易接触到的网页/手机App/用户资料界面提供“Do Not Sell My Personal Information“的选择,并且要在后台落实,确保退出了的客户不会有信息流落到第三方。丝芙兰没能在官网中或App中提供有效的退出选择,从而被判不合规。
三、丝芙兰对Global Privacy Control (GPC)的“Do Not Sell My Personal Information“ 选项视而不见。 (Civil Code section 1798.120(a))
GPC 作为欧美主流浏览器通用的一款隐私保护功能,作用是在浏览各种网页时默认自带”用户不希望个人信息被追踪,搜集和出售“的标识。启用 GPC 后,被访问网站会自动收到警告,无需用户自己动手 Opt-out。虽然丝芙兰表示公司正确的处理了 GPC ,但在加州总检察长的数据监测中,大量启用了 GPC 的实验数据还是流向了 Google Analytics。在实验证据面前,丝芙兰无法不承认他们对 GPC 标识的处理漏洞。
四、丝芙兰没有在30天补救期内解决以上问题
两年前就开始执法的 CCPA,为何到直到今天才有了第一例执法行动?这很有可能与 CCPA 中的30天超长补救期有关。公司若在接受正式通知30天内解决问题,则执法部门不会提出控告。对于大部分公司,一个月的时间来完成调整和补救绰绰有余,但对于像丝芙兰这样数字化程度高的数据大户,牵一发而动全身,30天就略显紧张了。而且,从2023年1月1日起,加州新的隐私法CPRA(California Privacy Rights Act)将会代替 CCPA 开始生效。其中30天的补救期将会被取而代之,由检察官来决定要给予公司多久的补救期。所以,有些公司等到被抓了再改正的“偷懒”行为可能很快就要行不通了。
这次的消费者隐私权侵犯不仅将在未来两年大大加重丝芙兰的隐私合规要求,并且被罚款120万美金。目前丝芙兰官网已经紧急修改了隐私政策中关于销售客户数据的语言,并在官网页脚明显位置增添了”CA - Do Not Sell My Personal Information“链接。
接下来我们该怎么做?
这个问题的修复有两个部分。
一、在网站上正确地提供 Do Not Sell 的用户告知和用户选择
企业可以自己对照如下样本,看看自己的实现是否需要进一步加强,避免犯同样的错误。
1. 明确告诉客户 "Do Not Sell or Share My Personal Information" 的权利和行使方式:
2. Cookie设置提供 opt-out 选项:
二、网站上使用 Google Analytics 等服务时,需要检测用户是否做出了 Do Not Sell 的选择并且正确地配置 Google Analytics
这个地方有些复杂,因为有很多个地方都可以做出选择,坑比较多,一个不留神就会漏掉一个场景,前功尽弃。下面我们分别讲一下几个常见的检查项,退出权 (Opt-out)、受限数据处理 (RDP,Restricted data processing) 以及全球隐私控制 (GPC,Global Privacy Control)。
1. 用户选择退出(Opt-out):
根据 Google 文档,用户选择停用 Google Analytics,您可能就需要这样做。gtag.js 库包含一个 window 属性,您只要将其设为 true,就可以禁止 gtag.js 向 Google Analytics(分析)发送数据。当 Google Analytics(分析)要设置 Cookie 或将数据发回到 Google Analytics(分析)服务器时,会首先检查此属性的设置情况,如果值设置为 true,则不采取任何操作。针对 GA4 用户选择退出,你可以window['ga-disable-G-XXXXXXXXXX'] = true;
将 G-xxxxxxx 替换为 GA4 ID。针对普通用户选择退出,你可以 window['ga-disable-UA-XXXXXXX-Y'] = true;
将 UA-xxxxxxx-Y 替换为普通用户的 ID。要以编程方式停用 Google Analytics(分析),请将 window['ga-disable-MEASUREMENT_ID'] 设置为 true。代码如下:
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=MEASUREMENT_ID">
</script>
<script>
window['ga-disable-MEASUREMENT_ID'] = true;
// 将 MEASUREMENT_ID 替换为有效的 ID
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'MEASUREMENT_ID');
</script>
注意:必须在对 gtag() 进行任何调用之前设置此 window 属性,并且必须在要停用 Google Analytics(分析)的所有网页上设置此属性。如果该属性未设置或设置为 false,则Google Analytics(分析)会正常工作。
2. 受限数据处理(RDP,Restricted data processing):
Google 开发了受限数据处理功能 (Restricted data processing),协助广告客户、发布商和合作伙伴遵守《加利福尼亚消费者隐私法案》(CCPA) 。当启用了“受限数据处理”功能后,Google 会限制自身对某些唯一标识符的使用方式,并会在向您提供服务时更为严格地处理数据,以确保仅将此类数据用于某些商业目的。另外“受限数据处理”功能,需要广告客户、发布商、合作伙伴自行决定何时以及如何启用。Google建议以下三种情况启用RDP:
启用 RDP 功能,Google 提供了很多入口,背后的核心就是如何处理用于指明 Google 是否应启用“受限数据处理”(RDP)的参数 “restricted_data_processing”。此参数的默认值为 false,如果您将此参数的值设为 true,您的特定用户使用google服务时就开启了“受限数据处理”功能。
下面介绍一下不同场景中设置参数 “restricted_data_processing” 的例子。
2.1 在 Google Ads 或跟踪代码管理器中的 Google tag 代码中设置该参数,gtag 场景示例代码:
< ! -- Google 代码 (gtag.js) - Google Ads -->
<script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
<script>
window.dataLayer = window.dataLayer | | [ ] ;
function gtag () { dataLayer.push ( arguments ) } ;
gtag ( 'js', new Date ( ) ) ;
gtag ( 'config' , 'TAG_ID', { 'restricted_data_processing': true } ) ;
</script>
< ! 如果您使用的是旧版 AdWords -->
<script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = 1234567890;
var google_conversion_label = "xxx-XXx1xXXX123X1xX";
var google_remarketing_only = false
var google_conversion_value = 10.0;
var google_conversion_currency = "USD";
var google_restricted_data_processing = true;
/* ] ] > */
</script>
<script type="text/javascript"
src="//www.googleadservices.com/pagead/conversion.js">
</script>
2.2 在Google 发布商广告代码中的“受限的数据处理”,gpt tag 场景示例代码:
<script async
src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
<div id='gpt'>
<script>
window.googletag = window.googletag || {cmd: []};
googletag.cmd.push(function() {
googletag
.defineSlot('/123/sports', [300, 250], 'gpt')
.addService(googletag.pubads());
googletag.pubads().setPrivacySettings({
'restrictDataProcessing': true
});
googletag.enableServices();
googletag.display('gpt');
});
</script>
</div>
2.3 在Google 发布商广告代码中的“受限的数据处理”,gpt passback tag 场景示例代码:
<script async
src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
<div id='gpt-passback'>
<script>
window.googletag = window.googletag || {cmd: []};
googletag.cmd.push(function() {
googletag
.defineSlot('/123/sports', [300, 250], 'gpt-passback')
.addService(googletag.pubads());
googletag.pubads().setPrivacySettings({
'restrictDataProcessing': true
});
googletag.enableServices();
googletag.display('gpt-passback');
});
</script>
</div>
2.4 在Google 发布商广告代码中的“受限的数据处理”,如果是 AdSense and Ad Exchange asynchronous ad tag 场景示例代码
<ins class="adsbygoogle"
style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-0123456789abcdef"
data-ad-slot="0123456789"
data-restrict-data-processing="1"></ins>
2.5 在Google 发布商广告代码中的“受限数据处理”,如果是 Tagless Request 场景,url 请求如下
https://securepubads.g.doubleclick.net/gampad/ad?iu=/12345/adunit&sz=728x90&rdp=1&c=12345
3. 全球隐私控制(GPC,Global Privacy Control)
GPC 是一个新的隐私实现方式,已经得到主流隐私浏览器(比如 Mozila,DuckDuckGo)的支持,也得到了加州CCPA执法机构的背书。通过向访问的网站发送信号(譬如,在 HTTP 包头里面加了一个新的字段),告诉不希望他们的数据被出售,不希望他们的数据被分享。它可以在消费者行使选择退出权利方面发挥不可或缺的作用。虽然只有加州消费者保护法(CCPA)和欧洲的全球数据保护条例(GDPR)以及科罗拉多州的隐私法都要求 GPC 功能存在;但未来会有越来越被接受,比起前辈 Do-Not-Track,我们认为 GPC 更具有可执行性。
GPC 的落地有三种主流的方向:
浏览器支持。如果浏览器将
navigator.globalPrivacyControl
设置为 True;浏览器将会通知网站不要出售或共享你的个人数据。2021年12月,Mozilla 向所有的 Firefox 使用者推送全球隐私控制(Global Privacy Control,GPC)功能;Google Chrome 以插件扩展的方式抢先让用户体验;相信越来越多的浏览器支持该功能。如果浏览器支持后,可以通过script脚本修改navigator.globalPrivacyControl
的值。客户端通过 HTTP 请求 header 中增加 Sec-GPC 字段告知到服务端。如果
Sec-GPC = 1
,客户端开启 GPC 功能。如果接服务端收到 Sec-GPC 为 1 的请求头,则在应答的 cookie 中设置gpc=1,服务端有两种简单的方法可以做到。
如果网站服务器是 Nginx,在 Nginx 配置文件添加以下内容,将会在每次收到 Sec-GPC: 1 请求头时设置 cookie:
server {
listen 80;
location / {
if ($http_sec_gpc = "1") {
add_header "Set-Cookie" "gpc=1;domain=$host;path=/";
}
return 200;
}
}
如果网站服务器是 Apache,在根目录 .htaccess 文件中添加以下内容,将会在每次收到 Sec-GPC: 1 请求头时设置 cookie:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP:Sec-GPC} !^$
RewriteRule ^ - [CO=gpc:1:%{HTTP_HOST}:0:/:secure:0:samesite]
</IfModule>
如果是 java 代码,您可以将以下代码添加到 java 文件中,用于在每次收到 Sec GPC:1 请求头时设置 cookie:
void setGpcCookie(HttpServletRequest request, HttpServletResponse response, String request_url)
{
if ("1".equals(request.getHeader("SEC_GPC"))) {
URI uri = new URI(request_url);
String domain = uri.getHost();
if (domain != null && !domain.isEmpty()) {
Cookie cookie = new Cookie("gpc", "1");
cookie.setMaxAge(0);
cookie.setPath("/");
cookie.setDomain(domain);
cookie.setSecure(true);
cookie.setHttpOnly(false);
response.addCookie(cookie);
}
}
}
如果是 python 代码,您可以将以下代码添加到 python 文件中,用于在每次收到 Sec GPC:1 请求头时设置 cookie:
#python flask
@app.route('/gpc_test')
def gpc_test():
response = make_response(render_template('gpc_test.html'))
gpc = request.headers.get('SEC-GPC');
if gpc == '1':
response.set_cookie('gpc','1')
return response
如果是 php 代码,您可以将以下代码添加到 php 文件中,用于在每次收到 Sec GPC:1 请求头时设置 cookie:
function set_gpc_cookie ($request_url) {
$key = 'HTTP_SEC_GPC';
if ( isset( $_SERVER[$key] ) && $_SERVER[$key] == '1' ) {
$domain = parse_url(request_url, PHP_URL_HOST);
if(!empty($domain))
setcookie( 'gpc', '1', 0, '/', $domain, true, false );
}
}
现在客户端可以通过 javascript 可以读取响应 cookie,判断服务器是否收到 Sec GPC:1 请求头
/* 判断服务端是否收到了 Sec GPC:1 请求头 */
var is_gpc = (document.cookie.search("gpc=1;") !== -1);
服务端表示其遵守 GPC ;可以在站点上提供 /.well-known/gpc.json 的 URL 请求。根据[ RFC8259 ] 要求,如果服务器返回内容 JSON 对象,有 gpc 和 lastUpdate 两个字段。gpc 的值只有为
true
,表示服务器遵守 GPC 请求。lastUpdate 表示支持 GPC 声明发布的时间。请求示例如下:kaamel.io 遵守 GPC
GET /.well-known/gpc.json HTTP/2 Host: kaamel.ioUser-Agent: whatever
Content-Type: application/json
{ "gpc": true, "lastUpdate": "2022-09-01" }
企业使用 Google 分析或者广告服务的时候,最严谨的做法考虑兼容前辈 Do-Not-Track 以及常用浏览器,请参考代码:
<script>
/* 测试 gpc 以及 do not track 是否启用 */
var gpc = (-1 !== document.cookie.search( 'gpc=1;' ));
var dnt = ((navigator.globalPrivacyControl || gpc) ||
(window.doNotTrack && window.doNotTrack == '1') ||
(navigator.doNotTrack && (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1')) ||
(navigator.msDoNotTrack && navigator.msDoNotTrack == '1') ||
(window.external && ('msTrackingProtectionEnabled' in window.external) && window.external.msTrackingProtectionEnabled()));
/* 只有 gpc 以及 do not track 都没启用的时候,才初始化 google 分析脚本 */
if(!dnt) {
var dh = document.head;
var scriptElement = document.createElement('script');
scriptElement.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXX';
dh.appendChild(scriptElement);
}
window.dataLayer = window.dataLayer || [];
/* 修改gtag 函数 */
function gtag() {
/* 如果 gpc 及 do not track 启用,直接返回啥也不做。*/
if(dnt) return;
dataLayer.push( arguments );
}
gtag('js', new Date());
/* 开启 google 数据受限处理 */
gtag ('config', 'TAG_ID', { 'restricted_data_processing': true }) ;
/* 配置 GA4 或者 普通用户使用 google 分析 */
gtag('config', 'G-XXXXXX');
gtag('config', 'UA-XXXXXX-Y');
</script>
个人隐私保护在全世界范围内这几年都在飞速发展,新的立法,新技术也层出不穷。以后,类似这种“你以为你没卖用户数据,也和全世界大声的说自己没问题,可实际尴尬的发现什么是卖数据都没搞懂”的案例可能会越来越多。
这次的判例给我们的启示是如果你的企业的网站或者app,是面向消费者,并且面向全球提供业务,必须要持续关注当地的隐私合规的法律和执法标准,尽可能的采取隐私的最佳实践。另一方面,隐私的最佳实践又比较复杂, 牵扯的面很广。对于企业内部来说,也需要法务,技术,安全等等部门紧密协同起来,支持好隐私保护负责人的工作。
最后,企业要特别重视用户的反馈和投诉,隐私类的问题反馈,要确保第一时间找专业人士评估影响,确定解决方案和时限,才能避免违规,才能让你的用户信任你,放心地使用你的产品和服务。
Kaamel原创内容,未经授权禁止任何转载