动态数据屏蔽 (DDM)
动态数据屏蔽 (DDM) 会隐藏敏感信息,同时仍允许访问屏蔽的列。DDM 不会更改存储的数据。相反,它只是在 `SELECT` 查询期间以屏蔽形式呈现数据。这旨在提供一定程度的保护,防止意外数据泄露。但是,任何直接访问 SSTable 文件的人都可以读取明文数据。
屏蔽函数
DDM 基于一组 CQL 本机函数,这些函数会隐藏敏感信息。可用的函数是
函数 | 描述 |
---|---|
|
将第一个参数替换为 `null` 列。返回值始终是不可存在的列,而不是表示 `null` 值的非空列。 示例
|
|
将它的参数替换为相同类型的任意固定默认值。对于文本值,这将是 `****`,对于数值,这将是零,对于布尔值,这将是 `false`,等等。 可变长度多值类型(如列表、集合和映射)被屏蔽为空集合。 固定长度多值类型(如元组、用户定义类型 (UDT) 和向量)通过将每个值替换为值类型的默认屏蔽值来屏蔽。 示例
|
|
将第一个参数替换为第二个参数上的替换值。替换值需要与被替换值具有相同的类型。 示例
|
|
返回第一个 `text`、`varchar` 或 `ascii` 参数的副本,将除第一个和最后一个字符以外的每个字符替换为填充字符。第二个和第三个参数是公开的前缀和后缀的大小。可选的第四个参数是填充字符,默认情况下为 `\*`。 示例
|
|
返回第一个 `text`、`varchar` 或 `ascii` 参数的副本,将第一个和最后一个字符替换为填充字符。第二个和第三个参数是公开的前缀和后缀的大小。可选的第四个参数是填充字符,默认情况下为 `\*`。 示例
|
|
返回包含第一个参数哈希值的 `blob`。可选的第二个参数是根据可用的 Java 安全提供程序使用的哈希算法。默认哈希算法是 `SHA-256`。 示例
|
这些函数可以在 `SELECT` 查询中使用,以获取数据的屏蔽视图。例如
CREATE TABLE patients (
id timeuuid PRIMARY KEY,
name text,
birth date
);
INSERT INTO patients(id, name, birth) VALUES (now(), 'alice', '1982-01-02');
INSERT INTO patients(id, name, birth) VALUES (now(), 'bob', '1982-01-02');
SELECT mask_inner(name, 1, null), mask_default(birth) FROM patients;
// system.mask_inner(name, 1, NULL) | system.mask_default(birth)
// -----------------------------------+----------------------------
// b** | 1970-01-01
// a**** | 1970-01-01
将屏蔽函数附加到表列
可以将屏蔽函数永久附加到表的任何列。如果定义了屏蔽列,则 `SELECT` 查询将始终以屏蔽形式返回列值。屏蔽对运行 `SELECT` 查询的用户来说是透明的。了解列是否被屏蔽的唯一方法是查看表定义。
这是一个可选功能,默认情况下处于禁用状态。要使用此功能,请在 `cassandra.yaml` 中启用 `dynamic_data_masking_enabled` 属性。
可以在 `CREATE TABLE` 中定义表的列的掩码,以创建表模式。此示例使用具有两个参数的 `mask_inner` 函数
CREATE TABLE patients (
id timeuuid PRIMARY KEY,
name text MASKED WITH mask_inner(1, null),
birth date MASKED WITH mask_default()
);
在对该数据使用 `SELECT` 查询时,`mask_inner` 函数需要三个参数,但将函数附加到表模式时,始终省略第一个参数。该第一个参数的值始终被解释为屏蔽列的值,在本例中为 `text` 列。
出于同样的原因,在创建表模式时,使用屏蔽函数 `mask_default` 不需要任何参数,但在 `SELECT` 查询中使用时,它需要一个参数。
可以将数据正常插入屏蔽表,而不会更改。例如
INSERT INTO patients(id, name, birth) VALUES (now(), 'alice', '1984-01-02');
INSERT INTO patients(id, name, birth) VALUES (now(), 'bob', '1982-02-03');
`SELECT` 查询将返回屏蔽数据。屏蔽函数将自动应用于列值。
SELECT name, birth FROM patients;
// name | birth
// -------+------------
// a**** | 1970-01-01
// b** | 1970-01-01
可以使用 `ALTER TABLE` 查询更改表列上的屏蔽函数。
ALTER TABLE patients ALTER name
MASKED WITH mask_default();
类似地,可以使用 `ALTER TABLE` 查询从列中分离屏蔽函数
ALTER TABLE patients ALTER name
DROP MASKED;
权限
普通用户在创建时没有 `UNMASK` 权限,将看到屏蔽值。授予用户 `UNMASK` 权限允许他们检索屏蔽列的未屏蔽值。超级用户在创建时自动拥有 `UNMASK` 权限,并且将在 `SELECT` 查询结果中看到未屏蔽值。
例如,假设我们有一个包含屏蔽列的表
CREATE TABLE patients (
id timeuuid PRIMARY KEY,
name text MASKED WITH mask_inner(1, null),
birth date MASKED WITH mask_default()
);
然后我们将一些数据插入表中
INSERT INTO patients(id, name, birth) VALUES (now(), 'alice', '1984-01-02');
INSERT INTO patients(id, name, birth) VALUES (now(), 'bob', '1982-02-03');
LOGIN unprivileged
SELECT name, birth FROM patients;
// name | birth
// -------+------------
// a**** | 1970-01-01
// b** | 1970-01-01
然后我们创建两个用户,他们对该表具有 `SELECT` 权限,但我们只向其中一个用户授予 `UNMASK` 权限
CREATE USER privileged WITH PASSWORD 'xyz';
GRANT SELECT ON TABLE patients TO privileged;
GRANT UNMASK ON TABLE patients TO privileged;
CREATE USER unprivileged WITH PASSWORD 'xyz';
GRANT SELECT ON TABLE patients TO unprivileged;
具有 `UNMASK` 权限的用户可以看到清晰的未屏蔽数据
LOGIN privileged
SELECT name, birth FROM patients;
// name | birth
// -------+------------
// alice | 1984-01-02
// bob | 1982-02-03
没有 `UNMASK` 权限的用户只能看到屏蔽数据
LOGIN unprivileged
SELECT name, birth FROM patients;
// name | birth
// -------+------------
// a**** | 1970-01-01
// b** | 1970-01-01
`UNMASK` 权限与任何其他权限一样,可以随时撤销
REVOKE UNMASK ON TABLE patients
FROM privileged;
请注意,当禁用身份验证时,匿名默认用户将拥有所有权限,包括 `UNMASK` 权限,并且可以看到未屏蔽数据。换句话说,将数据屏蔽函数附加到列只有在启用身份验证时才有意义。
只有具有 `UNMASK` 权限的用户才能在 `SELECT` 查询的 `WHERE` 子句中使用屏蔽列。没有 `UNMASK` 权限的用户无法使用此功能。此功能可防止恶意用户通过运行详尽的暴力查询来查看明文数据。没有 `UNMASK` 权限的用户将看到以下内容
CREATE USER untrusted_user WITH PASSWORD 'xyz';
GRANT SELECT ON TABLE patients TO untrusted_user;
LOGIN untrusted_user
SELECT name, birth FROM patients WHERE name = 'Alice' ALLOW FILTERING;
// Unauthorized: Error from server: code=2100 [Unauthorized] message="User untrusted_user has no UNMASK nor SELECT_UNMASK permission on table k.patients"
在某些用例中,受信任的数据库用户需要生成未经授权的外部用户将查询的屏蔽数据。例如,受信任的应用程序可以连接到数据库,并通过查询提取屏蔽数据,这些数据将显示给其最终用户。在这种情况下,受信任的用户(应用程序)可以获得 `SELECT_MASKED` 权限。此权限允许用户在 `SELECT` 查询的 `WHERE` 子句中查询屏蔽列,同时仍然只能在查询结果中看到屏蔽数据
CREATE USER trusted_user WITH PASSWORD 'xyz';
GRANT SELECT, SELECT_MASKED ON TABLE patients TO trusted_user;
LOGIN trusted_user
SELECT name, birth FROM patients WHERE name = 'Alice' ALLOW FILTERING;
// name | birth
// -------+------------
// a**** | 1970-01-01
自定义函数
用户定义函数 (UDF) 可以附加到表列。用于掩码的 UDF 应该属于与被掩码表相同的键空间。要掩码的列值将作为附加的 UDF 的第一个参数传递。因此,附加到列的 UDF 应该至少有一个参数,并且该参数应该与被掩码列具有相同的类型。此外,附加的 UDF 应该返回与被掩码列相同的类型的返回值。
CREATE FUNCTION redact(input text)
CALLED ON NULL INPUT
RETURNS text
LANGUAGE java
AS 'return "redacted";';
CREATE TABLE patients (
id timeuuid PRIMARY KEY,
name text MASKED WITH redact(),
birth date
);
这会在表模式和函数之间创建依赖关系。在存在此依赖关系的情况下,任何删除函数的尝试都将被拒绝。因此,您必须在删除函数之前删除表中的掩码列。
ALTER TABLE patients ALTER name
DROP MASKED;
删除列、包含它的表或包含它的键空间也会删除依赖关系。
聚合函数 不能用作掩码函数。