在隐私计算-SecretFlow/SCQL-SCQL的安全性说明一文中介绍过,SCQL 对单次查询在计算过程中提供满足 CCL 权限要求的数据机密性保护。那么什么是CCL呢?本篇将结合业界已有的实践,对CCL进行介绍。
我的SCQL系列文章:
- 隐私计算-SecretFlow/SCQL-如何在不泄漏隐私数据下进行联合数据分析
- 隐私计算-SecretFlow/SCQL-SCQL的两种部署模式架构
- 隐私计算-SecretFlow/SCQL-SCQL的安全性说明
- 👉隐私计算-SecretFlow/SCQL-CCL列控制列表机制
- 开发必备-使用DevContainer技术快速搭建团队开发环境
从ACL到CCL
在介绍CCL前,先简单介绍下ACL。
ACL即访问控制列表(Access Control List),是由一条或多条规则组成的集合。ACL常见于路由器、防火墙等网络边界设备上,通过规则限制外部网络(如互联网)对内部网络的访问,阻挡恶意流量或未授权请求。举例说明,若企业监测到某外部 IP(如203.0.113.10)存在恶意扫描或攻击行为,可配置 ACL 规则直接拒绝该 IP 的所有报文进入内部网络,或仅允许其访问特定公开服务(如企业官网),禁止访问内网服务器(如数据库、办公系统)。
因此CCL(Column Control List,列控制列表)所提供的机制可以通过ACL更好地进行理解,是一种对数据表中的列进行访问控制的规则集合。
为什么需要CCL
由于 SCQL 语法灵活多变,查询者可以通过精巧地构造 Query 以从结果中尽可能地推测原始数据敏感信息。因此,在执行查询者提交 Query 前,一般需要获得数据 owner 的审核授权。
人工审核 Query 的方式可以让数据 owner 对数据如何被使用以及结果中是否包含敏感信息泄露等问题进行人工确认。但人工审核方式有如下两方面的问题:1、对审核者有较高的要求,审核者需要具备 Query 分析能力,能够分析出潜在的信息泄露问题;2、执行前审批等待时间长,Query 执行前需要获得 Query 涉及的所有数据 owner 的授权。
在MySQL数据库中,提供有一套授权机制(更多细节可以参考我的这篇文章)来对数据进行保护:
GRANT [权限1, 权限2]
ON [权限范围]
TO [用户/角色]
[WITH GRANT OPTION]; -- 允许被授权者转授权限(不建议普通用户使用)
-- 直接给bob授予company库所有表的SELECT权限
GRANT SELECT ON company.* TO 'bob'@'localhost' IDENTIFIED BY 'Bob@123';
但这种授权机制在SCQL中却略显不足:
- SCQL作为联合数据分析引擎,数据通常应在满足一定条件下(如聚合后)进行披露,而原始数据则不能被披露;
- SCQL基于半诚实模型设计,中间过程涉及多方参与计算,且参与方好奇其余参与方的数据。SCQL执行的中间过程也一样需要有授权机制进行控制保护;
因此 SCQL 提供了 Column Control List(CCL) 机制,让数据 owner 可以定义数据的使用方式和披露限制,未通过 CCL 检查的 Query 不允许执行。对于通过 CCL 检查的 Query,审核人员可以在 CCL 的辅助下专注审核 Query 结果是否可以反推原始敏感数据的问题,从而降低审核负担,提高审核效率。需要注意的是,CCL 可以一定程度上缓解数据被滥用的问题,但无法杜绝从查询结果反推原始敏感数据的风险,建议结合事前审批一起,降低结果反推风险。
什么是CCL
CCL(Column Control List) 限定了列的披露策略,以及允许在列上执行的操作。SCQL承诺遵守这些限定,拒绝执行不满足CCL要求的 query,并保证执行过程不会违背 CCL 规定的数据披露策略。CCL 可以表示为一个三元组 <src_column, dest_party, constraint>,其含义为 src_column 对于 dest_party 的约束策略。
CCL Constraints的类型
根据当前已经实现的语法,目前 CCL constraints 一共分为如下 8 个类型。其中前 7 个 constraints 说明数据在何种情况下可以披露出去。
PLAINTEXT: 允许以任何形式(包括明文)进行计算和披露,没有任何使用上的限制,通常用于非敏感数据,请谨慎使用。PLAINTEXT_AFTER_JOIN: 允许作为 INNER JOIN 的 key,经过 JOIN 后可以明文披露。PLAINTEXT_AS_JOIN_PAYLOAD: 数据被 INNER JOIN(非 join key)后可以明文披露。PLAINTEXT_AFTER_GROUP_BY: 被约束的列经过 GROUP BY 分组后可以明文披露。PLAINTEXT_AFTER_AGGREGATE: 被约束的列经过 Aggregation 操作(如:SUM、AVG、MIN、MAX、COUNT)后的结果可以明文披露。CCL 还限制了 GROUP BY 分组的结果行数,记录行数小于等于3的分组,会被过滤掉,不会出现在最终结果中。PLAINTEXT_AFTER_COMPARE: 被约束的列经过 Compare 操作(如:<, >, >=, =, != 等等)后的结果可以明文披露。ENCRYPTED_ONLY: 始终以密态的形式参与计算,用于标记非常敏感数据,除了 COUNT 外(SCQL 不保护计算中间结果的size),不允许任何形式的披露。UNKNOWN: 未定义,目前默认拒绝以任何形式披露。
当前版本还提供:
REVEAL_RANK:被约束的列经过 RANK 窗口函数(目前支持ROW_NUMBER)后的结果可以明文披露。
CCL的作用
CCL 的首要作用是,给数据 OWNER 提供约束自己数据如何被使用的能力。CCL 带来的另外一个好处是,可以为 SCQL 执行优化提供 hints。
比如当某一列的 CCL constraint 为 PLAINTEXT_AFTER_AGGREGATE 时,该列数据经过 SUM 聚合计算后,就可以以明文的状态参与接下来的计算,加快整体的执行效率。
CCL的工作机制
Translator 把 query 翻译得到的 Logical Plan 和 CCL 作为输入,经过 CCL 推导构建出带 CCL 的 Logical Plan。Translator 将检查根节点即结果的CCL,仅当结果对 query 发起者的约束为 PLAINTEXT 时,才允许 query 继续执行,否则拒绝此 query 的执行。
下面将对 CCL 的推导过程及原理进行简单介绍和说明。
推导以用户设置的 CCL 为基础,推导方法分为两类,一类是特定操作的推导,比如关系代数操作、特定的函数;另一类是通用表达式推导。
特定操作推导
下面以 JOIN, GROUP BY 等操作为例,讲解特定操作的推导。
Join
当 JOIN keys 的 CCL constraint 均为 PLAINTEXT_AFTER_JOIN 或 PLAINTEXT 时,则对于 InnerJoin , JOIN keys 交集结果的 CCL 变为 PLAINTEXT ,对于 LeftOuterJoin ,只有右 JOIN key 的交集结果的 CCL 变为 PLAINTEXT (即左参与者可查看右参与者交集后的结果), 对于 RightOuterJoin ,则是左 JOIN key 的交集结果变为 PLAINTEXT (即右参与者可查看左参与者交集后的结果)。
当 JOIN payloads 的 CCL constraint 为 PLAINTEXT_AS_JOIN_PAYLOAD 或 PLAINTEXT 时,则对于 InnerJoin , JOIN payloads 交集结果的 CCL 变为 PLAINTEXT。
-- <tb.ID, Alice, PLAINTEXT_AFTER_JOIN>
-- <tb.is_acitve, Alice, PLAINTEXT_AS_JOIN_PAYLOAD>
-- ok
SELECT tb.ID, tb.is_active FROM ta join tb on ta.ID = tb.ID
-- ccl check failed: the 1th column tb.ID in the result is not visibile (PLAINTEXT_AFTER_JOIN)
-- to party alice
SELECT tb.ID FROM tb
-- ccl check failed: the 1th column tb.is_active in the result is not visibile (PLAINTEXT_AS_JOIN_PAYLOAD)
-- to party alice
SELECT tb.ID FROM tb
Group By
当 GROUP BY key 的 CCL constraint 均为 PLAINTEXT_AFTER_GROUP_BY 或 PLAINTEXT 时,则 GROUP BY key 经过 GROUP BY 操作后的结果的 CCL constraint 为 PLAINTEXT。
-- <ta.credit_rank, Bob, PLAINTEXT_AFTER_GROUP_BY>
-- ok
SELECT ta.credit_rank FROM ta GROUP BY ta.credit_rank
-- ccl check failed: the 1th column ta.credit_rank in the result is not visibile (PLAINTEXT_AFTER_GROUP_BY)
-- to party bob
SELECT ta.credit_rank FROM ta
Aggregate
当 aggregation functions(如:SUM、AVG、MIN、MAX、COUNT)的入参 CCL constraint 为 PLAINTEXT_AFTER_AGGREGATE 或 PLAINTEXT 时,则 aggregation function 的 results 的 CCL constraint 为 PLAINTEXT。
-- <ta.income, Bob, PLAINTEXT_AFTER_AGGREGATE>
-- ok
SELECT AVG(ta.income) as avg_income FROM ta GROUP BY ta.income
-- ccl check failed: the 1th column ta.income in the result is not visibile (PLAINTEXT_AFTER_AGGREGATE)
-- to party bob
SELECT ta.income FROM ta GROUP BY ta.income
Compare
当 compare function(> < = >= <= !=)的入参 CCL constraint 均为 PLAINTEXT_AFTER_COMPARE 或 PLAINTEXT 时,则 compare function 的 results 的 CCL constraint 为 PLAINTEXT。
-- <ta.age, Bob, PLAINTEXT_AFTER_COMPARE>
-- ok
SELECT ta.age > 18 FROM ta
-- ccl check failed: the 1th column ta.age in the result is not visibile (PLAINTEXT_AFTER_COMPARE)
-- to party bob
SELECT ta.age FROM ta
Window
当 window function 为 rank function(如 ROW_NUMBER、PERCENT_RANK、RANK),其 ORDER BY 的 CCL constraint 均为 REVEAL_RANK 或 PLAINTEXT 时,则 rank function 的 results 的 CCL constraint 为 PLAINTEXT。
-- <tb.order_amount, Alice, REVEAL_RANK>
-- ok
SELECT ROW_NUMBER() OVER(PARTITION BY tb.is_active ORDER BY tb.order_amount) as num FROM tb
-- ccl check failed: the 1th column tb.order_amount in the result is not visibile (REVEAL_RANK)
-- to party alice
SELECT tb.order_amount FROM tb
通用表达式推导
对于通用 operator/function,根据入参的 CCL constraint 推导其结果的 CCL constraint,可以分为以下几种情况( UNKNOWN 属于异常情况,不在此处讨论):
- 当其中一个入参的 CCL constraint 为
PLAINTEXT时,在 CCL constraint 推导时可以忽略该参数,不影响结果(即返回另一个入参的 CCL constraint)。 - 当其中一个入参的 CCL constraint 为
ENCRYPTED_ONLY时,则结果的 CCL constraint 为ENCRYPTED_ONLY。 - 当入参的 CCL constraint 相同时,返回这个 constraint。
- 对于无入参的 operators,比如 CURDATE(), NOW() 等函数,结果的 CCL constraint 为
PLAINTEXT。
对于 query 中的常量可以认为对所有参与方的 CCL constraint 为 PLAINTEXT。
对于不在上述情况的,目前认为无法进行推导,返回的结果的 CCL constraint 为 UNKNOWN。
CCL使用示例
假设当前有两个参与方 Alice 和 Bob,其中 Alice 持有数据 table ta,Bob 持有数据 table tb,两者共同执行一次 sql 查询任务。其中 Alice 持有的 table ta 包含字段 id 和 rank,Bob 持有的 table tb 包含字段 id 和 rank。
Alice 设置 CCL 如下:
<ta.id, Alice, PLAINTEXT><ta.id, Bob, PLAINTEXT_AFTER_JOIN><ta.rank, Alice, PLAINTEXT><ta.rank, Bob, PLAINTEXT_AFTER_COMPARE>
Bob 设置 CCL 如下:
<tb.id, Bob, PLAINTEXT><tb.id, Alice, PLAINTEXT_AFTER_JOIN><tb.rank, Bob, PLAINTEXT><tb.rank, Alice, PLAINTEXT_AFTER_COMPARE>
当 Alice 执行 query select tb.rank from ta join tb on ta.id = tb.id,SCQL 会校验 CCL 失败产生并返回错误:tb.rank 对于 Alice 的 CCL constraint 不是 PLAINTEXT。
而当 Alice 执行 query select ta.rank > tb.rank from ta join tb on ta.id = tb.id,这时 CCL 推导得到 ta.rank > tb.rank 对于 Alice 的 CCL constraint 为 PLAINTEXT,校验 CCL 通过,则 query 可以正常执行。