当您期望某些用户只可以查看MaxCompute项目中隐藏关键信息的敏感数据时,您可以开启MaxCompute动态脱敏功能,在数据访问或展示时实时隐藏或替换敏感数据,以防止敏感数据泄露。本文为您介绍如何开启MaxCompute动态脱敏功能,并提供参考示例。
功能介绍
MaxCompute提供数据动态脱敏功能,用于业务开发测试、数据共享、运维等场景中对个人身份信息(PII)等敏感数据以脱敏展示的方式进行保护。动态脱敏与ACL列级权限的访问控制不同,ACL列级权限需要用户修改查询SQL剔除无权限访问的列,脱敏策略无需用户修改现有查询SQL,访问数据时系统会自动根据用户和角色对相关列数据进行脱敏处理,确保数据在查询、下载、关联、UDF计算时已经处于脱敏状态,避免敏感数据泄露风险。
脱敏策略支持掩码、散列、字符替换、数值取整、日期取整等多种方式,满足用户对身份信息、银行卡号、地址、电话等数据的脱敏需求。MaxCompute数据脱敏在最靠近数据从存储中读取的环节中实现,具备高性能和高安全性。

使用限制
- 支持地域 - 该功能目前处于公测阶段,仅华东1(杭州)、华东2(上海)、华北2(北京)、华北3(张家口)、华北6(乌兰察布)、华南1(深圳)、西南1(成都)、中国香港、日本(东京)、新加坡、马来西亚(吉隆坡)、印度尼西亚(雅加达)、德国(法兰克福)地域支持数据动态脱敏。 
- 支持的驱动版本 - MaxCompute连接方式 - 驱动版本 - 脱敏功能支持情况 - Java SDK - 0.48.0-public及以上版本 - 支持 - odpscmd - 0.47.1及以上版本 - 支持 - JDBC - 3.4.3及以上版本 - 支持 - MaxFrame - 不限制 - 支持 - PyODPS - 不限制 - 支持 - Go SDK - 不限制 - 支持 
- 内部表 - MaxCompute内部表支持数据脱敏策略,外部表不支持。 
- 数据脱敏与行级权限功能互斥,已配置脱敏策略的表不支持再配置行级权限策略,反之亦然。 
- 对中文字符使用掩码策略脱敏时,中文字符编码格式必须为UTF-8。 
 
- 视图 - 传统的视图支持数据脱敏策略,视图脱敏策略与原脱敏表脱敏策略同步,当原表绑定、解绑脱敏策略时,传统的视图会同步生效。 
- 物化视图依据视图创建时原表的脱敏策略建立对应的脱敏数据视图。当原表继续绑定、解绑脱敏策略时,物化视图维持创建时的脱敏策略不变。 
 
- 脱敏策略 - 当用户访问敏感数据时,如果同时有多条脱敏策略生效,将执行优先级较高的脱敏策略对敏感数据进行脱敏。详情请参见预定义脱敏策略优先级。 
数据脱敏流程
项目所有者(Project Owner)和具备Super_Administrator或Admin角色的用户可以管理脱敏策略。当用户访问敏感数据表时,系统会检查用户或角色关联的脱敏策略,并按照脱敏策略返回脱敏后的数据或返回明文。

脱敏命令
项目开启或关闭数据脱敏功能
脱敏功能开关odps.data.masking.policy.enable为项目空间的Project级属性,只有项目Owner或被赋予项目级别的Super_Administrator和Admin角色的账号可以进行操作,操作详情请参见为用户赋予内置管理角色。
- 项目开启数据脱敏功能。 - setproject odps.data.masking.policy.enable=true;
- 项目关闭数据脱敏功能。 - setproject odps.data.masking.policy.enable=false;
创建和删除脱敏策略
- 命令格式 - 创建脱敏策略。 - CREATE DATA MASKING POLICY [IF NOT EXISTS] <policy_name> TO { USER <user_list> | ROLE <role_list> | default } USING <Predefined Masking Policy>;
- 删除脱敏策略。 - DROP DATA MASKING POLICY <policy_name>;
 
- 参数说明 - 参数名称 - 是否必填 - 描述 - policy_name - 是 - 脱敏策略名称。策略名称大小写不敏感,不支持特殊字符,只能包含a~z、A~Z、数字和下划线。建议以字母开头,名称的长度不超过128字节。 - USER | ROLE | default - 是 - 三者选其一。 - USER:对用户脱敏,<user_list>填写待脱敏的用户名称。您可以在MaxCompute中执行 - list users;命令获取角色信息。
- ROLE:对角色脱敏,<role_list>填写待脱敏的角色名称。您可以在MaxCompute中执行 - list roles;命令获取角色信息。
- default:默认脱敏,用户或角色访问敏感列时如果没有匹配到脱敏策略,那么采用default策略对敏感列进行脱敏。 
 - Predefined Masking Policy - 是 - 预定义的脱敏策略,详情请参见预定义脱敏策略。 
- 使用示例 - 示例1:为用户userA、userB和userC创建MD5哈希脱敏策略。 - CREATE data masking policy IF NOT EXISTS masking_test_001 TO USER (userA, userB, userC) USING MASKED_MD5(0);
- 示例2:为项目开发角色和运维角色创建MD5哈希脱敏策略。 - CREATE data masking policy IF NOT EXISTS masking_test_001 TO ROLE (role_project_deploy, role_project_dev) USING MASKED_MD5(0);
 
将脱敏策略应用于敏感数据列
- 命令格式 - --将脱敏策略应用于敏感表的敏感数据列 APPLY DATA MASKING POLICY <policy_name> BIND TO TABLE <table_name> COLUMN <column_name>; --为敏感表的敏感数据列取消指定的脱敏策略 APPLY DATA MASKING POLICY <policy_name> UNBIND FROM TABLE <table_name> COLUMN <column_name>; --为敏感表的敏感数据列取消全部脱敏策略 APPLY DATA MASKING POLICY UNBIND ALL FROM TABLE <table_name> COLUMN <column_name>; --为敏感表的全部敏感数据列取消全部脱敏策略 APPLY DATA MASKING POLICY UNBIND ALL FROM TABLE <table_name>;
- 参数说明 - 参数名称 - 是否必填 - 描述 - policy_name - 是 - 脱敏策略名称。 - table_name - 是 - 表名称。包含敏感数据的表。 - column_name - 是 - 列名称。包含敏感数据的列。 
查看脱敏策略
- 命令格式 - --查看脱敏策略的创建信息 DESC DATA MASKING POLICY <policy_name>; --查看表的扩展信息,包含敏感数据列的信息应用的脱敏策略信息 DESC EXTENDED <table_name>; --显示当前Project下所有的脱敏策略名称 LIST DATA MASKING POLICY; --显示与指定用户绑定的脱敏策略名称 LIST DATA MASKING POLICY TO USER <user_name>; --显示与指定角色绑定的脱敏策略名称 LIST DATA MASKING POLICY TO ROLE <role_name>; --显示与指定表绑定的所有脱敏策略名称 LIST DATA MASKING POLICY ON <table_name>; --显示与指定表指定列绑定的所有脱敏策略名称 LIST DATA MASKING POLICY ON <table_name> TO COLUMN <column_name>;
- 参数说明 - 参数名称 - 是否必填 - 描述 - policy_name - 是 - 脱敏策略名称。 - table_name - 是 - 表名称。包含敏感数据的表。 - column_name - 是 - 列名称。包含敏感数据的列。 - user_name - 是 - 用户名称。 - role_name - 是 - 角色名称。 
预定义脱敏策略
预定义脱敏策略包含掩码、散列、字符替换、取整等脱敏策略,您可以根据敏感数据类型选择适用的脱敏策略实现数据保护。
| 策略类型 | 策略名称 | 命令格式 | 描述 | 
| 通用 | 不脱敏 | UNMASKED | 不脱敏。 支持类型:全部类型。 | 
| 置空值 | MASKED_NULLIFY | 置空值,数据脱敏后返回NULL。 
 | |
| 赋默认值 | MASKED_DV | 赋默认值,每种数据类型的默认值请参见赋默认值脱敏策略(MASKED_DV)的赋值参考。 
 | |
| 只保留年份 | MASKED_DATE_YEAR | 只保留时间的年份数值,非年份数值设置为1月1日00:00(UTC时间)。 
 | |
| 取整 | MASKED_POINT_RESERVE(<num>) | 取整,保留小数点后0~5位小数。 
 | |
| 掩码 | 字符串头尾部分掩码 | MASKED_STRING_MASKED_BA(<before>, <after>) | 字符串头尾部分用 
 | 
| 字符串中间部分掩码 | MASKED_STRING_UNMASKED_BA(<before>, <after>) | 字符串头尾部分用明文,中间部分用 
 | |
| 散列 | SHA256散列 | MASKED_SHA256(<salt>) | SHA256散列算法脱敏。 
 | 
| SHA512散列 | MASKED_SHA512(<salt>) | SHA512散列算法脱敏。 
 | |
| MD5散列 | MASKED_MD5(<salt>) | MD5散列算法脱敏。 
 | |
| SM3散列 | MASKED_SM3(<salt>) | SM3散列算法脱敏。 
 | |
| 字符替换 | 随机字符替换 | MASKED_REPLACE_RANDOM(<position>) | 用随机字符替换数据,替换后字符串长度不变,随机值包括数字和英文字母。 
 | 
| 头尾随机字符替换 | MASKED_REPLACE_RANDOM_BA(<before>, <after>) | 用随机字符替换数据的头尾部分,替换后字符串长度不变,随机值包括数字和英文字母。 
 | |
| 固定字符替换 | MASKED_REPLACE_FIXED(<position>, <fixed_string>) | 
 | 
使用示例
个人敏感信息脱敏
此处以个人敏感信息为例,为您展示如何配置敏感策略,并对敏感信息进行脱敏。
- 数据准备。 - 创建个人敏感信息表,并插入敏感数据。 - -- 创建敏感信息表 CREATE TABLE if NOT EXISTS personal_info ( id bigint COMMENT '用户唯一标识ID', name string COMMENT '用户姓名', age int COMMENT '用户年龄', gender string COMMENT '用户性别', height float COMMENT '用户身高', birthday date COMMENT '用户生日', phone_number string COMMENT '用户电话号码', email string COMMENT '用户电子邮箱', address string COMMENT '用户地址', salary decimal(18, 2) COMMENT '用户薪水', create_time timestamp COMMENT '用户信息创建时间', update_time timestamp COMMENT '用户信息更新时间', is_deleted boolean COMMENT '用户信息是否被删除的标志位' ); -- 插入敏感数据 INSERT INTO personal_info VALUES (1, '张三', 18, '男', 178.56, '1990-01-01', '13800000000', 'zhangsan@example.com', '北京市海淀区', 5000.00, '2023-04-19 11:32:00', '2023-04-19 11:32:00', false), (2, '李四', 20, '女', 162.70, '1992-02-02', '13900000000', 'lisi@example.com', '上海市浦东新区', 6000.00, '2023-04-19 11:32:00', '2023-04-19 11:32:00',false), (3, '王五', 22, '男', 185.21, '1994-03-03', '14000000000', 'wangwu@example.com', '深圳市南山区', 7000.00, '2023-04-19 11:32:00', '2023-04-19 11:32:00', false);
- 配置脱敏策略。 - 姓名只保留第1个字,其他字符用 - *代替。- CREATE data masking policy IF NOT EXISTS masking_name TO USER (RAM$xxx@test.aliyunid.com:xxx) USING MASKED_STRING_UNMASKED_BA(1, 0); apply data masking policy masking_name bind TO TABLE personal_info COLUMN name;
- 身高字段取整。 - CREATE data masking policy IF NOT EXISTS masking_height TO USER (RAM$xxx@test.aliyunid.com:xxx) USING MASKED_POINT_RESERVE(0); apply data masking policy masking_height bind TO TABLE personal_info COLUMN height;
- 生日只保留年份。 - CREATE data masking policy IF NOT EXISTS masking_birthday TO USER (RAM$xxx@test.aliyunid.com:xxx) USING MASKED_DATE_YEAR; apply data masking policy masking_birthday bind TO TABLE personal_info COLUMN birthday;
- 默认用户使用SM3算法哈希电话号码。 - CREATE DATA MASKING POLICY default_sm3 TO DEFAULT USING MASKED_SM3(0); apply data masking policy default_sm3 bind TO TABLE personal_info COLUMN phone_number;
 
- 使用被脱敏账号,查询脱敏后的数据。 - SELECT id, name, height, birthday, phone_number FROM personal_info; -- 脱敏前 +------------+------+--------+----------+--------------+ | id | name | height | birthday | phone_number | +------------+------+--------+----------+--------------+ | 1 | 张三 | 178.56 | 1990-01-01 | 13800000000 | | 2 | 李四 | 162.7 | 1992-02-02 | 13900000000 | | 3 | 王五 | 185.21 | 1994-03-03 | 14000000000 | +------------+------+--------+----------+--------------+ -- 脱敏后 +------------+------------+------------+------------+--------------+ | id | name | height | birthday | phone_number | +------------+------------+------------+------------+--------------+ | 1 | 张* | 179.0 | 1990-01-01 | lvYJaH4ElL2ilpQx/8tfMUw7xP22yblIgmfWp0/msUQ= | | 2 | 李* | 163.0 | 1992-01-01 | 9fFWacNSwCRZLAjMHqunlfwkqhTbP2ubuDOeOSh4N1c= | | 3 | 王* | 185.0 | 1994-01-01 | k/0JoQCSarJg9ATJ5tyVnhQf1jIBxHXRbB+cvUm4OmE= | +------------+------------+------------+------------+--------------+
默认对所有用户和角色脱敏
下述实例为您展示当用户或角色同时命中多种敏感策略时,优先级较高的敏感策略将生效。
对默认用户采用MASKED_SHA256(5)的masking策略。
CREATE DATA MASKING POLICY  default_hash_policy
TO DEFAULT
USING MASKED_SHA256(5);对特殊用户A,B采用UNMASKED的策略。
CREATE DATA MASKING POLICY  ab_unmask_policy
TO USER (A, B)
USING UNMASKED;结果:用户A,B可以访问明文数据,其他用户只能访问SHA256散列脱敏的数据。
A,B用户命中MASKED_SHA256(5),UNMASKED策略,因此执行优先级较高的脱敏策略UNMASKED(详情请参见预定义脱敏策略优先级)。其他用户命中MASKED_SHA256(5)策略。
附录
预定义脱敏策略优先级
当用户访问敏感数据时有多条脱敏策略生效时,将执行较高优先级的脱敏策略对敏感数据进行脱敏。
例如用户A访问列col_string同时匹配到2条脱敏策略,分别是优先级3级MASKED_REPLACE_RANDOM(3)和优先级4级MASKED_SM3,系统将执行较高优先级的脱敏策略即MASKED_REPLACE_RANDOM(3),用户A将看到随机字符替换的脱敏结果。
| 优先级 | 预定义脱敏策略 | 
| 0(高) | UNMASKED | 
| 1 | MASKED_POINT_RESERVE(num) | 
| 2 | MASKED_DATE_YEAR | 
| 3 | MASKED_STRING_MASKED_BA(before, after) | 
| MASKED_STRING_UNMASKED_BA(before, after) | |
| MASKED_REPLACE_RANDOM(position) | |
| MASKED_REPLACE_RANDOM_BA(before, after) | |
| MASKED_REPLACE_FIXED(position) | |
| 4 | MASKED_SHA256 | 
| MASKED_SHA512 | |
| MASKED_MD5 | |
| MASKED_SM3 | |
| 5 | MASKED_DV | 
| 6(低) | MASKED_NULLIFY | 
赋默认值脱敏策略(MASKED_DV)的赋值参考
| 数据类型 | 默认值 | 
| bigint | 0 | 
| double | 0.0 | 
| decimal | 0 | 
| string | "" | 
| datetime | DATETIME'1970-01-01 00:00:00'(UTC时间) | 
| boolean | false | 
| tinyint | 0 | 
| smallint | 0 | 
| int | 0 | 
| binary | '' | 
| float | 0.0 | 
| double | 0.0 | 
| decimal | 0 | 
| varchar(n) | "" | 
| char(n) | " " (填充n个空格) | 
| date | DATE'1970-01-01' | 
| timestamp | TIMESTAMP'1970-01-01 00:00:00'(UTC时间) | 
| timestamp_ntz | TIMESTAMP'1970-01-01 00:00:00'(UTC时间) | 
| array | {子类型的默认值} | 
| map | {key:value} (key, value分别对应子类型的默认值) | 
| json | "" | 
| struct | (子类型的默认值) |