MySQL安全与审计之:`MySQL`的`Data Masking`:其在敏感数据脱敏中的应用。

MySQL安全与审计之:MySQL的Data Masking:其在敏感数据脱敏中的应用

大家好,今天我们来聊聊MySQL中的数据脱敏技术,特别是Data Masking在保护敏感数据方面的应用。在数字化时代,数据安全至关重要。很多公司需要处理大量的敏感数据,例如客户的个人身份信息(PII)、财务数据、健康信息等。如何安全地使用这些数据,同时又不暴露原始敏感信息,是一个需要认真对待的问题。数据脱敏就是解决这个问题的一种有效方法。

什么是数据脱敏?

数据脱敏,也称为数据遮蔽、数据屏蔽或数据匿名化,是一种通过修改或替换数据来保护敏感信息的安全措施。脱敏后的数据仍然可以用于测试、开发、分析等目的,但无法还原为原始的敏感数据。这降低了数据泄露的风险,符合数据隐私保护法规(如GDPR、CCPA等)的要求。

为什么需要数据脱敏?

  • 合规性: 遵守数据隐私法规,避免因数据泄露而产生的法律责任。
  • 安全性: 降低敏感数据泄露的风险,保护客户和企业的利益。
  • 测试和开发: 在非生产环境中使用脱敏后的数据,避免敏感数据暴露给开发人员和测试人员。
  • 数据分析: 在不暴露原始敏感数据的情况下,进行数据分析和挖掘。

MySQL Data Masking 简介

MySQL 8.0.19 引入了 Data Masking 功能,它允许我们动态地隐藏或修改查询结果中的敏感数据,而无需修改数据库中的原始数据。这意味着,只有拥有特定权限的用户才能看到原始数据,而其他用户只能看到脱敏后的数据。

Data Masking 的实现方式

MySQL Data Masking 通过定义 masking function 来实现数据脱敏。 这些函数在查询时被应用到特定的列,从而改变返回给用户的数据。

Data Masking 的优点

  • 动态性: 脱敏是在查询时动态进行的,原始数据不会被修改。
  • 细粒度控制: 可以针对不同的用户或角色应用不同的脱敏策略。
  • 易于实施: 通过简单的SQL语句即可实现数据脱敏。
  • 性能优化: Data Masking 在MySQL服务器端执行,避免了将敏感数据传输到客户端进行脱敏的开销。

Data Masking 的缺点

  • 需要MySQL 8.0.19及以上版本
  • 增加了查询的复杂性: 需要理解和维护masking function。
  • 性能影响: 虽然通常在服务器端执行,但masking function的计算也会带来一定的性能开销,特别是对于复杂的脱敏逻辑。
  • 功能限制: 自带的masking function相对简单,对于复杂的脱敏需求,可能需要自定义函数或结合其他安全措施。

Data Masking 的使用方法

Data Masking 主要涉及到以下几个步骤:

  1. 创建 masking function (可选): 如果MySQL内置的masking function不能满足需求,可以自定义函数。
  2. 授予用户 MASKING_POLICY 权限: 只有拥有 MASKING_POLICY 权限的用户才能创建和修改 Data Masking 策略。
  3. 创建 Data Masking 策略: 使用 ALTER TABLE ... ALTER COLUMN ... SET MASKING POLICY USING ... 语句来定义 Data Masking 策略。
  4. 验证 Data Masking 策略: 使用不同的用户身份来查询数据,验证 Data Masking 策略是否生效。

MySQL 内置的 Masking Functions

MySQL 提供了几个内置的 masking function,可以满足常见的脱敏需求:

函数名称 描述 适用数据类型 示例
DEFAULT() 将列的值替换为列的默认值。 所有 ALTER TABLE employees ALTER COLUMN salary SET MASKING POLICY USING DEFAULT()
NULL() 将列的值替换为 NULL 所有 ALTER TABLE employees ALTER COLUMN phone SET MASKING POLICY USING NULL()
EMPTY_STRING() 将列的值替换为空字符串。 字符串 ALTER TABLE employees ALTER COLUMN address SET MASKING POLICY USING EMPTY_STRING()
REDACT() 将列的值替换为 [REDACTED] 字符串。 字符串 ALTER TABLE employees ALTER COLUMN email SET MASKING POLICY USING REDACT()

自定义 Masking Functions

如果内置的 masking function 不能满足需求,可以使用用户自定义函数(UDF)来实现更复杂的脱敏逻辑。 UDF 可以使用 C、C++ 或其他支持的编程语言编写,并在 MySQL 中注册使用。

Data Masking 示例

假设我们有一个名为 employees 的表,包含以下列:

  • id (INT): 员工ID
  • name (VARCHAR): 员工姓名
  • email (VARCHAR): 员工邮箱
  • phone (VARCHAR): 员工电话
  • salary (DECIMAL): 员工工资

现在,我们需要对 emailphonesalary 列进行脱敏,只允许具有 admin 角色的用户查看原始数据。

1. 创建用户并授予权限

首先,创建两个用户:adminanalystadmin 用户拥有所有权限,包括 MASKING_POLICY 权限,analyst 用户只有查询权限。

CREATE USER 'admin'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost';
GRANT MASKING_POLICY ON *.* TO 'admin'@'localhost';
FLUSH PRIVILEGES;

CREATE USER 'analyst'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT ON employees TO 'analyst'@'localhost';
FLUSH PRIVILEGES;

2. 定义 Data Masking 策略

使用 admin 用户登录,并执行以下 SQL 语句来定义 Data Masking 策略:

-- 对 email 列进行脱敏,替换为 [REDACTED]
ALTER TABLE employees ALTER COLUMN email SET MASKING POLICY USING REDACT();

-- 对 phone 列进行脱敏,替换为 NULL
ALTER TABLE employees ALTER COLUMN phone SET MASKING POLICY USING NULL();

-- 对 salary 列进行脱敏,替换为 0
ALTER TABLE employees ALTER COLUMN salary SET MASKING POLICY USING DEFAULT();

-- 因为 salary 是 DECIMAL 类型,没有默认值的话,需要指定默认值
ALTER TABLE employees ALTER COLUMN salary SET DEFAULT 0.00;

3. 验证 Data Masking 策略

使用 admin 用户登录,查询 employees 表:

SELECT * FROM employees;

admin 用户应该能够看到原始的 emailphonesalary 数据。

使用 analyst 用户登录,查询 employees 表:

SELECT * FROM employees;

analyst 用户应该看到脱敏后的数据:email 列的值为 [REDACTED]phone 列的值为 NULLsalary 列的值为 0.00

更复杂的脱敏场景示例:部分遮蔽

有时候,我们不需要完全隐藏数据,而是只需要部分遮蔽敏感信息。例如,我们可以只显示电话号码的前三位和后四位,隐藏中间的四位数字。 由于 MySQL 内置的 masking function 无法直接实现这种需求,我们需要自定义函数。

1. 创建自定义函数 (UDF)

首先,我们需要创建一个 UDF 来实现部分遮蔽的逻辑。 以下是一个使用 C 语言编写的 UDF 示例:

#include <mysql.h>
#include <string.h>

#ifdef HAVE_DLOPEN

extern "C" {

my_bool partial_mask_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *partial_mask(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
void partial_mask_deinit(UDF_INIT *initid);

}

my_bool partial_mask_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
  if (args->arg_count != 1) {
    strcpy(message, "partial_mask requires one string argument");
    return 1;
  }

  if (args->arg_type[0] != STRING_RESULT) {
    strcpy(message, "partial_mask requires a string argument");
    return 1;
  }

  initid->max_length = args->lengths[0];
  initid->maybe_null = 1;
  return 0;
}

char *partial_mask(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
  if (args->args[0] == NULL) {
    *is_null = 1;
    return NULL;
  }

  char *input = args->args[0];
  unsigned long input_length = args->lengths[0];

  // Mask the middle 4 digits of a phone number
  if (input_length == 11 && strncmp(input, "+", 1) == 0) { // Assuming +1XXXXXXXXXX format
    strncpy(result, input, 3); // First 3 chars (+1X)
    strcat(result, "XXX");      // Masked middle
    strncat(result, input + 7, 4); // Last 4 chars
    *length = strlen(result);
    return result;
  } else if(input_length == 10){
    strncpy(result, input, 3);
    strcat(result, "XXX");      // Masked middle
    strncat(result, input + 6, 4); // Last 4 chars
    *length = strlen(result);
    return result;

  }
  else {
    // Return original string if it doesn't match the expected format
    strncpy(result, input, input_length);
    result[input_length] = '';
    *length = input_length;
    return result;
  }

}

void partial_mask_deinit(UDF_INIT *initid) {
  // No resources to free in this example
}
#endif

将以上代码保存为 partial_mask.c,并使用以下命令编译:

gcc -shared -fPIC partial_mask.c -o partial_mask.so -I/usr/include/mysql

注意: /usr/include/mysql 需要替换为实际的 MySQL 头文件路径。

2. 在 MySQL 中注册 UDF

使用 admin 用户登录 MySQL,并执行以下 SQL 语句来注册 UDF:

CREATE FUNCTION partial_mask RETURNS STRING SONAME 'partial_mask.so';

注意: partial_mask.so 需要放置在 MySQL 可以访问的目录中,例如 /usr/lib/mysql/plugin/。可以使用 SHOW VARIABLES LIKE 'plugin_dir'; 命令来查看 MySQL 的插件目录。

3. 定义 Data Masking 策略

使用 admin 用户登录,并执行以下 SQL 语句来定义 Data Masking 策略:

-- 对 phone 列进行脱敏,使用 partial_mask 函数
ALTER TABLE employees ALTER COLUMN phone SET MASKING POLICY USING partial_mask(phone);

4. 验证 Data Masking 策略

使用 analyst 用户登录,查询 employees 表:

SELECT * FROM employees;

analyst 用户应该看到 phone 列的值被部分遮蔽,例如 +12XXX7890123XXX7890。其他列的数据应该保持不变。

Data Masking 与其他安全措施的结合

Data Masking 只是数据安全措施的一部分,需要与其他安全措施结合使用才能达到最佳效果。 以下是一些常见的安全措施:

  • 访问控制: 限制用户对数据库的访问权限,只允许用户访问其需要的数据。
  • 数据加密: 对敏感数据进行加密存储,防止未经授权的访问。
  • 审计: 记录用户对数据库的操作,以便追踪和分析安全事件。
  • 防火墙: 保护数据库服务器免受网络攻击。
  • 入侵检测系统: 检测和阻止恶意行为。

Data Masking 的最佳实践

  • 根据实际需求选择合适的 masking function: 不同的数据类型和敏感程度需要使用不同的 masking function。
  • 定期审查 Data Masking 策略: 确保 Data Masking 策略仍然有效,并根据业务需求进行调整。
  • 对自定义 masking function 进行安全审计: 确保自定义 masking function 没有安全漏洞。
  • 监控 Data Masking 的性能影响: 确保 Data Masking 不会对数据库的性能产生过大的影响。
  • 培训用户: 让用户了解 Data Masking 的作用和使用方法。

关于Data Masking的总结陈述

Data Masking是MySQL中一个强大的数据脱敏工具,它允许我们动态地隐藏或修改敏感数据,而无需修改原始数据。通过结合内置的 masking function 和自定义函数,我们可以实现各种复杂的脱敏策略。然而,Data Masking 只是数据安全措施的一部分,需要与其他安全措施结合使用才能达到最佳效果。选择合适的策略,定期审查,并监控性能,才能充分发挥Data Masking的优势。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注