DD 数据开发学习站DATA ENGINEERING
模块 08 · 平台与数据服务

数据安全与合规

数据分级、RBAC/ABAC、脱敏与加盐哈希、行级权限、审计与导出管控。

难度 · 进阶 约 100 分钟 选学 练习 8 项 计划内 刷题 0/3
建议先学:BI 数据服务
本页目录 · 29 节

本章目标:能给数据分级,设计表级/行级/列级权限,写出可运行的脱敏脚本,并说清审计、导出和开发生命周期中的安全边界。 前置知识:数仓分层、用户画像 预计用时:100 分钟

数仓里往往同时有订单金额、手机号、收货地址和身份证号。一旦泄露,损失不是“删库重跑”能弥补的。数据安全不是上线前加一个密码,而是从采集、存储、使用到销毁的整套约束。

1. 为什么需要数据安全

三个现实场景:

  • 分析师为了跑数,把生产用户表整表导出到本地 Excel,文件被转发到群里。
  • 开发图省事,所有任务共用一个高权限账号,谁改了什么查不到。
  • 前端把手机号打码了,但接口仍返回明文,抓包就能拿到。

安全问题的共同点是:便利性压过了边界。数据安全要做的,是把“能访问”变成“按需、可审计、可收回地访问”。

2. 核心概念

2.1 数据分级分类

先给数据定级,再定权限:

级别 示例 默认策略
公开 商品类目、城市编码 可自由访问
内部 汇总 GMV、订单量 员工可申请
敏感 手机号、邮箱、收货地址 脱敏后使用,按需审批
核心 身份证号、银行卡、密码 禁止明文落数仓,强审计

分类还要按业务维度标注,例如用户数据、交易数据、财务数据。分级结果写进元数据,权限系统据此自动套策略。

2.2 权限模型

  • RBAC(基于角色):给角色授权,人加入角色。简单、易管理,适合大多数团队。
  • ABAC(基于属性):按用户部门、数据标签、访问时间等属性动态判断。灵活,但规则复杂。

落地时通常是组合:角色决定基础权限,属性补充行级和列级限制。

三条原则:

  1. 最小权限:只给完成工作必需的库表。
  2. 职责分离:申请权限的人和审批的人分开。
  3. 权限到期:临时权限设置有效期,到期自动回收。

2.3 脱敏与加密

手段 做法 适用
掩码 138****1234 展示、客服查询
哈希 加盐 SHA-256 需要关联但不需要还原
加密 AES 等可逆加密 必须还原原文
令牌化 用随机 token 替换原值 支付、跨系统传递
泛化 年龄转年龄段、地址到城市 统计分析

哈希要加盐,防止彩虹表反查;盐值放密钥管理系统,不能写死在代码里。加密密钥和密文分开存放,定期轮换。

2.4 行级与列级权限

  • 行级:不同用户看到不同行,例如区域分析师只看本区域订单。
  • 列级:同一行里隐藏敏感列,例如都看订单,但不能看手机号。
  • 脱敏视图:为敏感表建视图,视图里做掩码或过滤,再把视图权限授给分析师。

原则是在数据出口统一控制,不要让每个查询自己写过滤条件,否则漏一处就泄露。

2.5 审计与生命周期

审计日志至少记录:谁、什么时间、访问了哪张表、执行了什么操作、返回多少行、是否导出。异常行为要告警,例如凌晨大批量导出、短时间扫描全表。

数据生命周期包括采集最小化、存储期限、归档、删除。用户注销或撤回授权后,要在规定时间内清理可识别信息,备份中的副本也要有处理方案。

3. 动手示例

3.1 Python 掩码与加盐哈希

import hashlib
import hmac
import os

SALT = os.environ.get("PII_SALT", "local-demo-salt").encode("utf-8")

def mask_phone(phone):
    return phone[:3] + "****" + phone[-4:]

def tokenize(value):
    return hmac.new(SALT, value.encode("utf-8"), hashlib.sha256).hexdigest()

print(mask_phone("13800001234"))
print(tokenize("13800001234")[:16])
print(tokenize("13800001234") == tokenize("13800001234"))

输出:

138****1234
0d08e01ea9084f93
True

同一个手机号每次哈希结果相同,可以用于关联;但没有盐无法从哈希还原手机号。生产环境把 PII_SALT 放密钥管理系统,仓库里不要提交真实盐值。

3.2 建脱敏视图

CREATE OR REPLACE TABLE user_contact (
    user_id VARCHAR,
    phone VARCHAR,
    email VARCHAR
);

INSERT INTO user_contact VALUES
    ('U01', '13800001234', 'alice@example.com'),
    ('U02', '13900005678', 'bob@example.com');

CREATE OR REPLACE VIEW v_user_contact_masked AS
SELECT
    user_id,
    CONCAT(SUBSTR(phone, 1, 3), '****', SUBSTR(phone, 8, 4)) AS phone_mask,
    CONCAT(SUBSTR(email, 1, 1), '***@', SPLIT_PART(email, '@', 2)) AS email_mask
FROM user_contact;

SELECT * FROM v_user_contact_masked ORDER BY user_id;

分析师只拿到 v_user_contact_masked 的权限,原始表权限留在少数管理员手里。掩码规则要覆盖所有敏感列,新增字段时同步更新视图。

3.3 行级权限

以 PostgreSQL 的行级安全为例:

ALTER TABLE ads_order_wide ENABLE ROW LEVEL SECURITY;

CREATE POLICY p_city ON ads_order_wide
FOR SELECT
USING (city = current_setting('app.current_city', true));

SET app.current_city = '北京';
SELECT * FROM ads_order_wide;

会话变量由应用在建立连接时注入,用户无法在 SQL 里随意修改。表所有者默认绕过行级策略,生产环境要确认是否需要 FORCE ROW LEVEL SECURITY。

其他引擎的写法不同,但模型一致:

Hive/Spark:Ranger 策略按库表列和行过滤条件授权
StarRocks/Doris:ROW POLICY 绑定角色,USING 里写过滤表达式
ClickHouse:行级策略 + 视图 + 列级授权组合

3.4 小样本抑制

统计结果也可能泄露个人信息。例如某个城市只有一个 25 岁用户,按年龄分组后等于直接暴露他。低于阈值的分组要抑制:

SELECT city, age_group, COUNT(*) AS user_cnt
FROM user_profile
GROUP BY city, age_group
HAVING COUNT(*) >= 5;

HAVING COUNT(*) >= 5 只保留至少 5 人的分组。这是最基础的 k-匿名思路,不能替代完整的隐私保护方案,但能挡住明显的个体识别。

3.5 审计查询

SELECT user_name, action, table_name, query_id, event_time
FROM audit_log
WHERE event_time >= TIMESTAMP '2024-03-01 00:00:00'
  AND action IN ('SELECT', 'EXPORT')
ORDER BY event_time DESC
LIMIT 20;

审计日志本身也要保护:只读、防篡改、单独存储,保留期限满足合规要求。

4. 常见坑

4.1 明文写日志

调试时把整个请求体打进日志,里面带手机号和地址。日志系统往往权限更宽、保留更久,泄露面更大。日志只记录必要字段,敏感值先脱敏。

4.2 生产数据直接复制到开发

开发环境权限松、缺审计,复制一份生产数据等于扩大泄露面。开发用脱敏样本或合成数据。

4.3 共用高权限账号

所有任务用一个管理员账号,出问题无法定位责任人。每个任务独立账号,按需授权,离职或任务下线及时回收。

4.4 只在界面打码

前端显示 138****1234,接口返回的 JSON 里还是明文。脱敏要在服务端完成,前端拿不到原文。

4.5 哈希不加盐

不加盐的哈希可以被彩虹表反查,手机号空间有限,几小时就能撞出来。使用带盐的 HMAC 或慢哈希,并保护盐值。

4.6 权限只加不减

项目结束、人员转岗后权限还在。建立定期复核机制,临时权限设置过期时间。

4.7 导出文件失控

数据导出成 CSV 后脱离平台管控,被转发、上传网盘。限制导出字段和行数、加水印、记录导出审计,敏感数据默认不允许导出。

4.8 备份成为盲区

主库做了脱敏,备份还是明文;主库删除了数据,备份还保留多年。备份加密、保留策略和删除流程要一起设计。

5. 在线练习

题目 考点
1517. 查找拥有有效邮箱的用户 邮箱格式校验
1527. 患某种疾病的患者 敏感信息的条件筛选
196. 删除重复的电子邮箱 去重与保留最小主键

自测:

  • 能写出一条只返回脱敏手机号的视图定义。
  • 能解释为什么行级权限不能只在前端实现。

6. 面试延伸

面试题:数据分级怎么做?

是什么:按敏感程度分为公开、内部、敏感、核心,再结合业务分类打标签,写入元数据。

解决什么问题:不同数据需要不同强度的保护,统一分级后可以自动套用权限、脱敏和审计策略。

我的实操边界:本章给出分级表和脱敏示例,未参与企业级数据分类分级项目。

面试题:脱敏和加密有什么区别?

是什么:脱敏不可逆或只保留部分信息,用于展示和分析;加密可逆,用于需要还原原文的传输和存储。

解决什么问题:分析场景不需要原文,脱敏降低泄露风险;需要还原的场景才用加密,并承担密钥管理成本。

我的实操边界:本章写过掩码和加盐哈希,未设计过密钥轮换体系。

面试题:行级权限怎么实现?

是什么:数据库行级安全策略、查询网关注入过滤条件、或给不同角色建脱敏视图。

解决什么问题:让同一张表对不同用户呈现不同数据范围,且无法通过改 SQL 绕过。

我的实操边界:本章在 PostgreSQL 语法下写了策略,未在生产权限平台配置。

面试题:怎么防止数据导出泄露?

是什么:限制可导出字段和行数、敏感列禁止导出、导出走审批和异步任务、加水印并记录审计。

解决什么问题:导出后的文件脱离平台控制,必须在出口处做最后一道限制。

我的实操边界:了解导出管控思路,未实现水印和文件追踪。

7. 本章验收

  • 能给出四级数据分类,并为每级举两个字段例子。
  • 能写出一个手机号和邮箱的脱敏视图。
  • 能运行 Python 加盐哈希示例,说明为什么同一个号码哈希结果相同。
  • 能写出 PostgreSQL 的行级权限策略,并说明会话变量由谁注入。
  • 能解释小样本抑制要解决什么问题。
  • 能列出至少四条数据导出和生命周期管理中的安全要求。
本章任务0 / 8
本页目录