为独立开发者打造完美的隐私政策与Cookie同意横幅 (Jekyll, 应对GDPR)

在运营个人项目或小型玩具项目时,我们常常会忽略“隐私政策”。然而,当我们在网站上添加广告或访客分析工具的那一刻,我们便开始处理来自全球用户的数据。这不仅受韩国的个人信息保护法管辖,还适用于欧洲的GDPR、美国的CCPA等严苛的法律。

这看起来可能有些复杂,但请别担心。本文将从A到Z分享整个过程,介绍如何在一个像Jekyll这样的静态网站上,构建既满足法律要求又能赢得用户信任的隐私政策和Cookie同意横幅系统。

第一步:构建政策框架 - 需要告知哪些内容?

首先要做的是创建一份文件,透明地说明我们的网站收集哪些信息、为什么收集以及如何处理。经过多次讨论,我们最终敲定了一份包含以下必要条款的中文、英文、韩文版政策。

必要条款

  1. 总则: 明确本文件适用于谁(网站运营者)。虽然使用实名可能会有些尴尬,但这是明确信息处理主体的法律义务,也是建立信任的开始。
  2. 收集项目与目的: 说明收集哪些信息及其目的。就我而言,除了回复邮件咨询的目的外,我已将信息收集降至最低。
  3. Cookie使用说明: 告知用户为了投放个性化广告(如Monetag)或进行访客分析(如Google Analytics),网站会使用Cookie,并说明拒绝的方法。
  4. 保留期限: 原则上,收集到的信息(如电子邮件)在达成目的后会立即销毁,但设有例外条款,即在发生法律纠纷时,信息可保留至纠纷解决为止。
  5. 第三方提供与处理委托: 明确不会直接向第三方提供信息,并指明使用了哪些外部服务,如托管服务(GitLab)或广告服务(Monetag)。
  6. 信息主体的权利: 告知用户有权请求删除自己的信息。
  7. 未成年人保护: 明确不会有意收集未满16周岁儿童的个人信息。
  8. 安全保障措施: 说明为安全管理所收集信息而采取的最低限度的管理和技术措施(例如:限定负责人、使用可信的电子邮件服务等)。

您可以参考基于这些内容完成的隐私政策

第二步:Cookie同意横幅的技术实现 - 如何获取同意?

与制定政策同样重要的是以“合法的方式”获取同意。特别是GDPR要求“事前同意(Prior Consent)”,这意味着在用户点击“同意”按钮之前,广告或分析脚本决不能执行

为了在Jekyll网站上灵活且易于管理地实现这一点,我们构建了一个积极利用 _config.yml 文件的系统。

1. 在 _config.yml 中整合所有设置

首先,将横幅的文本、按钮文字以及所有需要获得同意的脚本,都在 _config.yml 中进行统一管理。这样一来,将来修改脚本或文本时,就无需改动HTML文件。

# _config.yml

# Cookie同意横幅设置
cookie_consent:
  enabled: true  # 将此值设为false可禁用整个横幅功能。
  banner_message: "为确保网站正常运行并提供个性化广告,我们使用Cookie。"
  accept_button_text: "同意"
  decline_button_text: "拒绝"

# 基于同意的脚本设置
consent_scripts:
  monetag: |
    (function(s,u,z,p) ... document.documentElement)
  google_analytics: |
    // 在此处粘贴您的Google Analytics脚本内容。

2. 修改布局文件 (_layouts/default.html)

接下来,我们创建一个 for 循环,自动将 _config.yml 中定义的脚本添加到页面中。这段代码会先将需要同意的脚本以 type="text/plain" 的形式插入页面,使其处于非活动状态。

</head> 闭合标签前的适当位置添加以下代码。

{% for script_item in site.consent_scripts %}
  {% if script_item[1] and script_item[1] != "" %}
    <script type="text/plain" data-consent-script>
      {{ script_item[1] }}
    </script>
  {% endif %}
{% endfor %}

然后在 </body> 闭合标签的正上方,添加横幅的HTML代码以及用于控制这一切的JavaScript文件链接。

{% if site.cookie_consent.enabled %}
  <div id="cookie-banner">
    <p>{{ site.cookie_consent.banner_message | escape }}</p>
    <div>
      <button id="consent-accept">{{ site.cookie_consent.accept_button_text | escape }}</button>
      {% if site.cookie_consent.decline_button_text and site.cookie_consent.decline_button_text != "" %}
        <button id="consent-decline">{{ site.cookie_consent.decline_button_text | escape }}</button>
      {% endif %}
    </div>
  </div>
  <script src="{{ '/assets/js/consent.js' | relative_url }}"></script>
{% endif %}

3. 编写核心逻辑 (assets/js/consent.js)

最后是处理实际同意操作并激活非活动脚本的JavaScript代码。该代码将用户的选择保存在 localStorage 中,以防止横幅重复出现。

// assets/js/consent.js
document.addEventListener('DOMContentLoaded', function() {
  const banner = document.getElementById('cookie-banner');
  const acceptBtn = document.getElementById('consent-accept');
  const declineBtn = document.getElementById('consent-decline');

  function loadConsentScripts() {
    const consentScripts = document.querySelectorAll('script[type="text/plain"][data-consent-script]');
    consentScripts.forEach(script => {
      const newScript = document.createElement('script');
      for (let i = 0; i < script.attributes.length; i++) {
        const attr = script.attributes[i];
        if (attr.name.toLowerCase() !== 'type') {
            newScript.setAttribute(attr.name, attr.value);
        }
      }
      if (script.innerHTML) {
        newScript.innerHTML = script.innerHTML;
      }
      document.body.appendChild(newScript);
    });
  }

  acceptBtn.addEventListener('click', function() {
    loadConsentScripts();
    localStorage.setItem('cookie_consent', 'true');
    banner.style.display = 'none';
  });

  if (declineBtn) {
    declineBtn.addEventListener('click', function() {
      localStorage.setItem('cookie_consent', 'false');
      banner.style.display = 'none';
    });
  }

  const consent = localStorage.getItem('cookie_consent');
  if (consent === 'true') {
    loadConsentScripts();
  } else if (consent === 'false') {
    banner.style.display = 'none';
  } else {
    if (banner) {
        banner.style.display = 'block';
    }
  }
});

(CSS代码可以根据个人设计自由添加。)

结论:一个建立信任的过程

现在,我们拥有了满足法律要求的多语言隐私政策,以及一个尊重用户选择的灵活的Cookie同意系统。这个过程不仅仅是遵守法律,更是向访问我们网站的用户传递一个信息:“我们珍视您的信息”,从而建立信任。

当然,最后一步是寻求法律专家的审阅。希望这篇指南能成为为您的项目增加透明度和可信度的第一步。