ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Cloud SQL MySQL 客户端字段加密实战:基于 Tink 信封加密与 Cloud KMS 的敏感数据保护方案

Cloud SQL MySQL 客户端字段加密实战:基于 Tink 信封加密与 Cloud KMS 的敏感数据保护方案 示例工程【免费下载链接】python-docs-samplesCode samples used on cloud.google.com项目地址https://gitcode.com/GitHub_Trending/py/python-docs-samples点击查看免费下载本指南基于开源仓库 python-docs-samples 中的cloud-sql/mysql/client-side-encryption示例完整讲解如何在 Cloud SQL for MySQL 之上实现客户端字段级加密应用在写入数据之前先借助 Google Cloud KMS 与 Tink 库将敏感字段如用户邮箱加密为密文再入库读取时再解密。读完本文你将掌握信封加密Envelope Encryption的核心原理、TinkKmsEnvelopeAead原语的初始化与用法、Cloud SQL Proxy 的 TCP/Unix Socket 两种本地连接方式以及一套可复制、可运行、带测试验证的完整示例代码结构。为什么需要客户端字段加密Cloud SQL 默认提供了传输加密TLS与静态加密存储层但这两者都发生在数据库服务端数据库管理员或拥有底层访问权限的人依然可能读到明文。客户端侧加密Client-Side EncryptionCSE把加密动作前移到应用进程内只有你的应用持有解密能力数据库里落盘的一直是密文从而为敏感字段提供纵深防御。本示例的典型场景是投票应用votes表中保存投票队伍team与投票人邮箱voter_email其中voter_email被定义为VARBINARY(255)用于存放加密后的字节流。从源码结构看整个示例被拆成四个可独立阅读与复用的模块位于 snippets 目录cloud_kms_env_aead.py初始化 Tink 信封 AEAD 原语cloud_sql_connection_pool.py建立 Cloud SQL 连接池并建表encrypt_and_insert_data.py加密字段并写入query_and_decrypt_data.py查询并解密字段。核心原理信封加密与关联数据AAD示例选用的加密原语是 Tink 的KmsEnvelopeAead信封加密其思路是不直接用 KMS 主密钥加密每一份业务数据那样太慢且成本高而是让 KMS 生成/封装一个随机的数据密钥DEK用 DEK 加密业务数据再用 KMS 主密钥加密 DEK最终把加密后的 DEK 密文一起交付。解密时反向操作。这样既获得 KMS 主密钥的强安全性又保留了对称加密的高吞吐。在 cloud_kms_env_aead.py 中初始化过程分三步注册 AEAD 算法实现aead.register()用 KMS 资源名与凭据创建 GCP 客户端并获取 AEAD 原语gcp_client gcpkms.GcpKmsClient(key_uri, credentials) gcp_aead gcp_client.get_aead(key_uri)这里key_uri必须带gcp-kms://前缀例如gcp-kms://projects/your-project/locations/global/keyRings/your-ring/cryptoKeys/your-key指定 DEK 的密钥模板并组装信封原语key_template aead.aead_key_templates.AES256_GCM env_aead aead.KmsEnvelopeAead(key_template, gcp_aead)即 DEK 采用AES-256-GCM同时提供机密性、完整性与认证。另一个关键概念是关联数据Associated DataAAD。示例在加密邮箱时把队伍名team作为 AAD 传入env_aead.encrypt(email.encode(), team.encode())。AAD 不参与保密但会参与认证计算——解密时必须提供完全相同的 AAD否则解密失败。这样即使密文被整体搬到另一行也会因 AAD 不匹配而无法解密可有效防止密文被换行重放该机制符合 RFC 5116 对 AEAD 关联数据的定义源码注释也做了明确说明。前置准备从零搭建运行环境原文档的 Before you begin 部分列出的准备工作如下均为 Google Cloud 控制台或命令行操作具体步骤以官方文档为准Python 开发环境确保本机已安装可用的 Python 3并完成 gcloud 认证创建 Cloud SQL for MySQL 实例2nd Gen记录连接字符串、数据库用户名与密码创建数据库在实例中为应用创建数据库记录数据库名创建 Cloud KMS 密钥记录 KMS key 的完整资源名形如projects/.../locations/.../keyRings/.../cryptoKeys/...后续作为GCP_KMS_URI使用创建服务账号并授予Cloud SQL Client角色下载 JSON 格式的密钥文件用于认证数据库连接示例中通过GOOGLE_APPLICATION_CREDENTIALS环境变量指向它macOS / Windows 用户部分平台需要配置 gRPC 根证书以接受 Google 服务器证书否则 Tink 调用 KMS 时可能出现证书校验失败。从 encrypt_and_insert_data.py 与 query_and_decrypt_data.py 的源码可以确认运行时应用依赖以下环境变量环境变量用途示例值DB_USER数据库用户名root、mysqlDB_PASS数据库密码超强密码DB_NAME数据库名votes_dbDB_HOSTTCP 连接时的host:port127.0.0.1:3306DB_SOCKET_DIRUnix Socket 连接时的目录可选默认/cloudsql/cloudsqlINSTANCE_CONNECTION_NAME实例连接名project:region:instancemy-project:us-central1:my-instanceGOOGLE_APPLICATION_CREDENTIALS服务账号 JSON 密钥路径可选下载的 JSON 文件路径GCP_KMS_URICloud KMS 密钥资源名代码会自动拼接gcp-kms://前缀projects/.../cryptoKeys/...需要特别注意的是明文密码通过环境变量注入只是一种演示便捷方案并不安全。原文档与源码注释都明确建议使用 Secret Manager 之类的托管方案来保存数据库口令与服务账号凭据。本地运行Cloud SQL Proxy 的两种连接方式本地开发无法直接访问 VPC 内的 Cloud SQL需要先下载并安装cloud_sql_proxy。代理提供两种连接形态TCP 连接全平台与 Unix Domain Socket仅 Linux/macOS。方式一TCP 连接Linux / macOS先导出环境变量export GOOGLE_APPLICATION_CREDENTIALS/path/to/service/account/key.json export DB_HOST127.0.0.1:3306 export DB_USERDB_USER_NAME export DB_PASSDB_PASSWORD export DB_NAMEDB_NAME export GCP_KMS_URIGCP_KMS_URI然后在后台启动代理把远程实例映射到本地 3306 端口./cloud_sql_proxy -instancesproject-id:region:instance-nametcp:3306 -credential_file$GOOGLE_APPLICATION_CREDENTIALS Windows / PowerShell设置环境变量$env:GOOGLE_APPLICATION_CREDENTIALSCREDENTIALS_JSON_FILE $env:DB_HOST127.0.0.1:3306 $env:DB_USERDB_USER_NAME $env:DB_PASSDB_PASSWORD $env:DB_NAMEDB_NAME $env:GCP_KMS_URIGCP_KMS_URI在独立的 PowerShell 会话中启动代理Start-Process -filepath C:\path to proxy exe -ArgumentList -instancesproject-id:region:instance-nametcp:3306 -credential_fileCREDENTIALS_JSON_FILETCP 模式下代码走 init_tcp_connection_engine从DB_HOST中切分出host与port构造mysqlpymysql://db_user:db_passdb_host:db_port/db_name形式的 SQLAlchemy 连接 URL。方式二Unix Domain Socket该方式仅支持 Linux 与 macOSWindows 请回退到 TCP 方式。首先创建代理可写的目录sudo mkdir /cloudsql sudo chown -R $USER /cloudsql导出 socket 目录与其他环境变量export DB_SOCKET_DIR/path/to/the/new/directory export GOOGLE_APPLICATION_CREDENTIALS/path/to/service/account/key.json export INSTANCE_CONNECTION_NAMEMY-PROJECT:INSTANCE-REGION:INSTANCE-NAME export DB_USERDB_USER_NAME export DB_PASSDB_PASSWORD export DB_NAMEDB_NAME export GCP_KMS_URIGCP_KMS_URI后台启动代理并监听 Unix socket./cloud_sql_proxy -dir$DB_SOCKET_DIR --instances$INSTANCE_CONNECTION_NAME --credential_file$GOOGLE_APPLICATION_CREDENTIALS Unix 模式下init_unix_connection_engine 通过 SQLAlchemy URL 的query参数传入unix_socketdb_socket_dir/instance_connection_name等价于mysqlpymysql://db_user:db_pass/db_name?unix_socket...。安装依赖与建表进入示例目录并创建虚拟环境virtualenv --python python3 env source env/bin/activate pip install -r requirements.txt依赖清单见 requirements.txtSQLAlchemy2.0.40、PyMySQL1.1.2、tink1.9.0。其中 PyMySQL 作为纯 Python 驱动保证在本地与无原生 MySQL 客户端的环境都能连接。连接建立后init_db 会自动创建votes表若不存在CREATE TABLE IF NOT EXISTS votes ( vote_id SERIAL NOT NULL, time_cast timestamp NOT NULL, team CHAR(6) NOT NULL, voter_email VARBINARY(255), PRIMARY KEY (vote_id) );注意voter_email使用VARBINARY(255)而非VARCHAR因为要存储的是加密后的二进制密文使用二进制类型可避免字符集转换破坏字节流。此外init_db会根据是否提供db_host自动在 TCP 与 Unix 两种引擎间切换这也是示例对两种代理模式统一支持的关键。运行演示加密写入与查询解密启动演示脚本python snippets/query_and_decrypt_data.py该脚本一次完成写入加密数据 查询解密两个动作输出形如TeamTABEmailTABTime Cast的最近 5 条投票记录。加密写入链路encrypt_and_insert_data.py 的核心流程time_cast datetime.datetime.now(tzdatetime.timezone.utc) encrypted_email env_aead.encrypt(email.encode(), team.encode()) # team 作为关联数据传入保障数据的完整性与来源真实性 stmt sqlalchemy.text( fINSERT INTO {table_name} (time_cast, team, voter_email) VALUES (:time_cast, :team, :voter_email) ) with db.connect() as conn: conn.execute(stmt, time_casttime_cast, teamteam, voter_emailencrypted_email)三个实战细节值得注意参数化语句防注入即使表名是动态拼接的字段值也全部通过:time_cast、:team、:voter_email命名参数绑定从源头规避 SQL 注入with 语句自动归还连接无论执行成功或抛错连接都会归还到连接池避免泄漏合法性前置校验写入前校验team只能是TABS或SPACES非法值直接记日志返回防止脏数据入库。查询解密链路query_and_decrypt_data.py 逆操作读取最近 5 条投票recent_votes conn.execute( fSELECT team, time_cast, voter_email FROM {table_name} ORDER BY time_cast DESC LIMIT 5 ).fetchall() for row in recent_votes: team row[0] email env_aead.decrypt(row[2], team.encode()).decode() time_cast row[1] print(f{team}\t{email}\t{time_cast})解密时再次以team为 AAD只有当 AAD 一致时env_aead.decrypt才会成功否则会抛认证失败异常。这意味着数据库中的密文无法被静默篡改或迁移到其他队伍名下。测试验证用真实 KMS 与数据库跑通闭环仓库为该示例提供了三层测试均为需要真实云资源的集成测试配置见 noxfile_config.py仅 Python 3.10 参与执行且强制类型注解检查cloud_kms_env_aead_test.py读取环境变量CLOUD_KMS_KEY初始化信封原语断言返回对象确实是KmsEnvelopeAead且key_template与 KMS URI 一致encrypt_and_insert_data_test.py依赖MYSQL_USER、MYSQL_PASSWORD、MYSQL_DATABASE、MYSQL_HOST四个环境变量建立连接池写入一条加密投票后回读解密断言邮箱明文出现在解密结果中测试表名用votes_uuid隔离结束后自动DROP TABLE清理query_and_decrypt_data_test.py先插入再调用query_and_decrypt_data若解密结果中找不到目标邮箱则pytest.fail完整验证加密写入 → 查询解密闭环。从测试代码可以印证两点实现事实一是解密必须与加密使用同一个KmsEnvelopeAead原语同一 KMS key二是GOOGLE_APPLICATION_CREDENTIALS在测试中同样通过环境变量注入CLOUD_KMS_KEY与运行脚本中的GCP_KMS_URI指向同一个密钥。安全注意事项与适用边界最后汇总示例反复强调的安全要点与限制这些是生产化改造时的关键依据密钥即权限客户端加密的强度完全取决于 KMS 主密钥的访问控制。服务账号应遵循最小权限原则仅授予必要的 KMS 解密/加密权限与Cloud SQL Client角色凭据不进代码环境变量只适合演示生产环境应接入 Secret Manager 等托管凭据服务AAD 设计关联数据字段一旦在业务上可能变更例如允许用户改名会影响解密兼容性设计表结构与字段时应预先评估字段类型密文必须存为VARBINARY/BLOB等二进制类型并使用固定长度的表结构规划避免长度溢出查询限制加密后的字段无法在数据库侧做WHERE email ...等明文条件查询除非另行建立可检索的加密索引方案这是所有字段级加密方案的固有取舍。如需继续深入可在仓库内查看完整的示例目录 cloud-sql/mysql/client-side-encryption以及同仓库下 PostgreSQL 客户端加密目录 的对照实现思路。赞分享示例工程【免费下载链接】python-docs-samplesCode samples used on cloud.google.com项目地址https://gitcode.com/GitHub_Trending/py/python-docs-samples点击查看免费下载相关推荐Cloud SQL PostgreSQL 客户端字段加密实战基于 Tink 与 Cloud KMS 的信封加密方案Cloud SQL PostgreSQL 客户端字段加密实战基于 Tink 与 Cloud KMS 的信封加密方案 本指南以 cloud sql/postgr示例工程Tink Java 与 Google Cloud Storage基于 Cloud KMS 信封加密Envelope Encryption实现 GCS Blob 客户端加密实战Tink Java 与 Google Cloud Storage基于 Cloud KMS 信封加密Envelope Encryption实现 GCS Bl密码学应用安全使用 Tink 与 Cloud KMS 在 Cloud SQL for SQL Server 中实现客户端字段级加密Envelope AEAD 实战使用 Tink 与 Cloud KMS 在 Cloud SQL for SQL Server 中实现客户端字段级加密Envelope AEAD 实战 导读示例工程上一篇DXVK终极指南Linux游戏性能优化与深度调校完全手册下一篇B站视频下载技术伙伴如何用Python工具解放你的离线观看生产力创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表