对持卡人敏感数据进行标记化处理以满足 PCI DSS 要求

本教程介绍如何在 Cloud Functions 上设置受访问权限控制的信用卡和借记卡标记化服务。为设置该服务,本文使用以下 Google Cloud 服务:Identity and Access Management (IAM)Cloud Key Management Service (KMS) 以及采用 Datastore 模式的 Firestore

标记化是将信用卡数据等敏感信息替换为良性占位符(或称标记)的过程。支付卡行业数据安全标准 (PCI DSS) 的第 3 部分要求将信用卡上存储的大部分数据视作敏感信息。

令牌本身没有意义,它只是作为一种用于在特定上下文中查找经过标记化的数据的方法。但是,您仍然需要确保您的标记不包含任何特定于用户的信息,并且不能直接解密。这样一来,即使您失去对客户支付卡标记的控制,任何人也无法使用标记来窃取持卡人数据。

用于处理敏感信息的服务

可供您选择的用于托管持卡人数据环境 (CDE) 的平台或服务多种多样。本教程将指导您使用 Cloud Functions 进行示例部署,并帮助您完成后续步骤,获得可直接用于生产环境的解决方案。

Cloud Functions 是用于托管和执行代码的无服务器平台,借助它,您可以方便地快速启动无需干预即可扩缩的应用。请注意,在兼容 PCI DSS 的 CDE 中,您必须将所有入站和出站流量限制为已获授权的连接。Cloud Functions 目前不支持此类精细控制。因此,您必须在其他位置(例如在应用中)实现补偿性控制,或者选择其他平台。相同的标记化服务可采用容器化方式运行,例如自动扩缩的托管实例组或 Kubernetes 集群。它们是具有完整 VPC 网络控制的首选生产环境。

Cloud KMS 是 Google Cloud 的密文管理服务。Cloud KMS 托管您的加密密钥、定期轮替加密密钥,并对存储的帐号数据进行加密或解密。 Firestore 用于存储标记化数据。

本教程使用 IAM 来严格控制标记化服务中使用的所有资源。您需要一个令牌经常过期的特殊服务帐号,以便授予对 Cloud KMS 和 Firestore 的访问权限以及执行标记生成器。

下图展示了标记化应用架构。

标记化应用架构

Firestore 模式

Firestore 是 Datastore 的下一代版本。Firestore 可以采用 Datastore 模式运行,该模式使用 Datastore 所用的 API 并且可以扩容到每秒数百万次写入;Firestore 也可以采用原生模式运行,该模式使用另一种 API,最适合移动和 Web 应用。

为完成本教程,我们建议您在 Datastore 模式下使用 Firestore。本教程不支持在原生模式下使用 Firestore。

如果您已在 Google Cloud 项目中启用了 Datastore,则可以改用 Datastore。不过,本教程的其余部分假定您在 Datastore 模式下使用 Firestore。

如果您需要帮助,以确定在应用中使用哪一种 Firestore 模式,请参阅我们的原生模式或 Datastore 模式选择指南

目标

  • 选择数据库服务和模式。
  • 创建服务帐号。
  • 设置 Cloud KMS。
  • 选择一个存储区域。
  • 创建两个 Cloud Functions 函数。

费用

本教程使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用量来估算费用。 Google Cloud 新用户可能有资格申请免费试用

准备工作

  1. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到项目选择器页面

  2. 在整个教程中,我们将使用 [YOUR_PROJECT] 指代您的项目。
  3. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

  4. 启用 Cloud Functions and Cloud KMS API。

    启用 API

  5. 为 Firestore 选择 Datastore 模式。
    选择 Datastore 模式

完成本教程后,您可以删除所创建的资源以避免继续计费。如需了解详情,请参阅清理

创建服务帐号

  1. 在 Cloud Console 中,打开 IAM 服务帐号页面。

    转到“服务帐号”页面

  2. 点击 + 创建服务帐号。在显示的对话框中,执行以下操作:

    1. 将该帐号命名为 Tokenization Service User

      默认 ID tokenization-service-user 是根据您的输入内容生成的。

    2. 点击创建

    3. 授予预定义角色 Cloud KMS CryptoKey Encrypter/DecrypterCloud Datastore User

    4. 点击继续

    5. 点击创建密钥,选择 JSON 格式,然后点击创建

      点击创建后,系统将自动下载 JSON 文件。

    6. 将 JSON 文件移动到安全的位置。由于该文件可授予对您的 Google Cloud 帐号的强大访问权限,并且您只有此时可以检索这组密钥,因此请妥善保存。

    现在,您已经拥有一个具有以下电子邮件地址的服务帐号用户:

    tokenization-service-user@[YOUR_PROJECT].iam.gserviceaccount.com

设置 Cloud KMS

  1. 在 Cloud Console 中,打开加密密钥

    转到“加密密钥”页面

  2. 点击 + 创建密钥环。在显示的对话框中,执行以下操作:

    1. 将该密钥环命名为 tokenization-service-kr
    2. 对于密钥环位置,选择全局。通常此选项就足以满足本教程的要求。但在做出任何生产架构决策之前,请确保您了解各个 Cloud KMS 位置之间的差异
    3. 请仔细检查您的所选项,因为创建密钥环之后,您无法对其执行删除或重命名操作
    4. 点击创建

      创建密钥环

    系统会创建密钥环并将您转到“密钥创建”页面。

  3. 创建密钥对话框中,执行以下操作:

    1. 将该密钥命名为 cc-tokenization
    2. 对于用途,请选择 Symmetric encrypt/decrypt
    3. 轮替周期设置为您选择的值,然后点击创建

    跟踪密钥的相关信息

创建 Cloud Functions 函数

本教程假设您将使用 Cloud Shell。如果您使用其他终端,请确保使用最新版本的 gcloud 命令行工具

  1. 在 Cloud Console 中,打开 Cloud Shell:

    转到 Cloud Shell

  2. 克隆 GitHub 项目代码库并移动到工作文件夹:

    git clone https://github.com/GoogleCloudPlatform/community gcp-community
    cd gcp-community/tutorials/pci-tokenizer/
    

    gcs-cf-tokenizer 文件夹包含 index.js 文件,该文件是您要创建的两个不同 Cloud Functions 函数的来源。它还包含 package.json,用于告知 Cloud Functions 函数要运行哪些软件包。

  3. 应用 KMS 配置 复制配置模板文件并打开以进行修改:

    cp config/default.json config/local.json
    nano config/local.json
    

    Node.js 10 运行时要求您显式定义 Google Cloud 项目 ID:

    "project_id":              "YOUR_PROJECT_ID_HERE"
    
  4. 找到 KMS 配置并应用您在上一部分中创建的 KMS 值:

    "location":                "global",
    "key_ring":                "tokenization-service-kr",
    "key_name":                "cc-tokenization"
    
  5. 在 KMS 模式下部署两个 Cloud Functions 函数(如需详细了解 DLP 模式,请参阅 README.md):

    gcloud functions deploy tokenize --runtime=nodejs10 --trigger-http --entry-point=kms_crypto_tokenize --memory=256MB --source=.
    gcloud functions deploy detokenize --runtime=nodejs10 --trigger-http --entry-point=kms_crypto_detokenize --memory=256MB --source=.
    

    这些命令创建两个单独的 Cloud Functions 函数:一个用于将卡号转换为标记,另一个用于逆转此过程。不同的入口点将执行定向到 index.js 中的正确起始函数。

  6. 请记下每条命令的输出中的 httpsTrigger 网址。调用函数需要这些网址。

  7. 部署好函数后,打开 Cloud Functions 控制台。

    打开 Cloud Functions 控制台

  8. 验证函数已创建。如果一切顺利,您会看到两个函数,每个函数旁边都有一个对勾标记。

    验证已创建 Cloud Functions 函数

构建身份验证令牌

以单个服务帐号用户身份执行所有 Cloud Functions 函数。如果您希望更好地控制特定 Cloud Functions 函数的功能,您可以在代码中构建规则。您在前面步骤中部署的代码需要一个 OAuth2 授权令牌(本文档中称为 auth_token),该令牌是代表您创建的特殊服务帐号 (tokenization-service-user@[YOUR_PROJECT].iam.gserviceaccount.com) 生成的。

除了本教程中的方法外,还有许多方法可用于生成 auth_token。一款名为 getToken.js 的开发和测试工具可以帮助您完成本教程的其余部分。您可以在 GitHub 代码库的 src 文件夹中找到 getToken.js

您必须先提供服务帐号凭据,然后才能使用 auth_token 生成器。

  1. 打开包含您下载的服务帐号凭据的 JSON 文件,并将所有内容复制到剪贴板,确保不要截断任何数据。
  2. 在 Cloud Shell 中,创建并打开身份验证令牌文件:

    nano ~/.tokenization-service-user.json
  3. 粘贴 JSON 文件的内容。

  4. Ctrl+OEnter,然后按 Ctrl+X 进行保存并退出编辑器。

  5. 如果您在 Cloud Shell 之外运行此流程,请定义 GOOGLE_CLOUD_PROJECT 环境变量:

    export GOOGLE_CLOUD_PROJECT=[YOUR_PROJECT]
  6. 生成示例 auth_token

    npm install
    AUTH_TOKEN=$(GOOGLE_APPLICATION_CREDENTIALS=~/.tokenization-service-user.json node src/getToken.js)
    echo $AUTH_TOKEN
    

    这些命令会生成 auth_token 字符串并将其存储在环境变量 $AUTH_TOKEN 中。为方便起见,还会显示 auth_token。此时,您便可以使用此 auth_token 来调用您的标记化服务。

调用标记生成器

  1. 打开 Cloud Functions 控制台。

    打开 Cloud Functions 控制台

  2. 点击您的函数。

  3. 切换到触发器标签页并复制网址(如果您还没有网址)。 请在后续步骤中使用触发器网址代替 {CF_URL}

    复制 Cloud Functions 函数的网址

  4. 在 shell 中,将触发器网址保存到环境变量:

    export TOK_URL="{CF_URL}"
  5. 创建一些示例数据,将它们传递给标记生成器:

    export TOK_CC=4000300020001000
    export TOK_MM=11
    export TOK_YYYY=2028
    export TOK_UID=543210
    
  6. 按照上一节中描述的步骤生成 auth_token,然后调用标记生成器:

    CC_TOKEN=$(curl -s -X POST "$TOK_URL" -H "Content-Type:application/json" --data '{"auth_token":"'$AUTH_TOKEN'", "cc": "'$TOK_CC'", "mm": "'$TOK_MM'", "yyyy": "'$TOK_YYYY'", "userid": "'$TOK_UID'"}') ; echo $CC_TOKEN
    

    如果此步骤有效,则会显示 64 个字符的字母数字字符串。此字符串已存储在环境变量 CC_TOK 中。您可以通过调用标记取消器检索卡片信息。

  7. 如需逆转标记化过程,请先检索去标记化函数的网址,方法与检索标记化操作的方法相同。

  8. 如需进行去标记化,请运行以下命令,将 {CF2_URL} 替换为您的触发器网址:

    export DETOK_URL="{CF2_URL}"
    curl -s -X POST "$DETOK_URL" -H "Content-Type:application/json" --data '{"auth_token":"'$AUTH_TOKEN'", "cc_token": "'$CC_TOKEN'"}'
    

    输出结果类似于以下内容:

    {"cc":"4000300020001000","mm":"11","yyyy":"2028","userid":"543210"}
    

    此数据是最初发送到标记生成器的数据,由您的应用解密和检索。

验证数据

  1. 打开 Datastore 控制台。此控制台还支持 Datastore 模式的 Firestore。

    打开 Datastore 控制台

  2. 如果您没有看到任何记录,请将种类设置为 cc,将命名空间设置为 tokenizer

您看到的数据是加密字段中经过标记化处理的加密支付卡数据。(以下屏幕截图并未显示加密字段。)

已成功对支付卡进行标记化处理(未显示加密字段)

本教程的拓展内容

GitHub 上的示例代码是个不错的起点,但在进入生产阶段之前还有许多需要考虑的问题。

如果您不熟悉如何生成和刷新访问令牌,那么为每个请求生成 OAuth 令牌会增加不必要的 API 调用,并且会降低服务的速度,使身份验证配额耗尽

如果您选择使用 Cloud Functions 对支付卡进行标记化处理,则可能需要完成更多工作才能满足合格安全评估机构或自我评估调查问卷的要求。具体而言,PCI DSS 第 1.2 和 1.3 节要求严格控制入站和出站流量。由于 Cloud Functions 和 App Engine 并未提供双向的可配置的防火墙,因此您必须创建补偿性控制,或者在 Compute Engine 或 Google Kubernetes Engine 上部署标记化服务。如果您想探索容器化,GitHub 代码与 Docker 兼容,并包含支持文档。

此示例代码还引入了部署的 npm(Node.js 包管理器)依赖项。在生产环境中,请始终将依赖项固定到特定的经过审核的版本。然后将这些版本与应用捆绑到一起,您也可以从受信任的非公开位置提供这些版本。这两种方法都可以使您免遭因公共 npm 代码库中断或者对您认为安全的包造成影响的供应链攻击而导致的停机。如果您预先构建并捆绑完整的应用,则部署时间通常会缩短,这意味着启动速度更快,扩缩更顺畅。

清理

如需清理本教程中使用的各个资源,请执行以下操作:

  1. 打开 Datastore 控制台。

    打开 Datastore 控制台

  2. 选择您创建的所有记录,然后点击删除

  3. 打开 Cloud Functions 控制台。

    打开 Cloud Functions 控制台

  4. 选择您创建的函数,然后点击删除

  5. 打开 IAM 控制台。

    打开 IAM 控制台

  6. 选择名为 tokenization-service-user@[YOUR_PROJECT].iam.gserviceaccount.com 的服务帐号,然后点击移除

  7. 在 IAM 加密密钥页面中,打开密钥环 tokenization-service-kr。删除密钥 cc-tokenization

  8. 在 Cloud Storage 控制台中,删除名为 staging.[YOUR_PROJECT].appspot.com 的存储分区。

或者,如果您创建了一个仅针对本教程的项目,则可以删除整个项目。

  1. 在 Cloud Console 中,转到管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

后续步骤