我叫 Denis Rozhkov,是 Gazinformservice 公司产品团队的软件开发主管
本文是根据一次演讲编写的
这篇文章将分为三个部分:
- 如何保护连接。
- 什么是操作审计以及如何记录数据库端发生的情况并连接到数据库。
- 如何保护数据库本身的数据以及可用的技术。
DBMS 安全性的三个组成部分:连接保护、活动审核和数据保护
保护您的连接
您可以直接或通过 Web 应用程序间接连接到数据库。 通常,业务用户(即使用 DBMS 的人员)间接与其交互。
在讨论保护连接之前,您需要回答决定如何构建安全措施的重要问题:
- XNUMX个业务用户相当于XNUMX个DBMS用户吗?
- 是否仅通过您控制的 API 提供对 DBMS 数据的访问,或者是否直接访问表;
- DBMS 是否分配给单独的受保护段、谁与其交互以及如何交互;
- 是否使用池/代理和中间层,这可以更改有关如何构建连接以及谁在使用数据库的信息。
现在让我们看看可以使用哪些工具来保护连接:
- 使用数据库防火墙类解决方案。 额外的保护层至少可以提高 DBMS 中发生的情况的透明度,并且最多可以提供额外的数据保护。
- 使用密码策略。 它们的使用取决于您的架构的构建方式。 无论如何,连接到 DBMS 的 Web 应用程序的配置文件中的一个密码不足以提供保护。 有许多 DBMS 工具可让您控制用户和密码是否需要更新。
- 用必要的信息丰富会议的背景。 如果会话是不透明的,您不了解谁在 DBMS 的框架内工作,您可以在正在执行的操作框架内添加有关谁在做什么以及为什么这样做的信息。 这些信息可以在审计中看到。
- 如果 DBMS 和最终用户之间没有网络隔离,请配置 SSL;它不在单独的 VLAN 中。 在这种情况下,必须保护消费者和 DBMS 本身之间的通道。 安全工具也可以开源。
这将如何影响 DBMS 的性能?
我们以 PostgreSQL 为例,看看 SSL 如何影响 CPU 负载、增加时序、降低 TPS,以及启用它是否会消耗太多资源。
使用 pgbench 加载 PostgreSQL 是一个用于运行性能测试的简单程序。 它可能在并行数据库会话中重复执行单个命令序列,然后计算平均事务率。
测试 1 不使用 SSL 和使用 SSL — 为每个事务建立连接:
pgbench.exe --connect -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres sslmode=require
sslrootcert=rootCA.crt sslcert=client.crt sslkey=client.key"
vs
pgbench.exe --connect -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres"
测试 2 不使用 SSL 和使用 SSL — 所有事务均在一个连接中执行:
pgbench.exe -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres sslmode=require
sslrootcert=rootCA.crt sslcert=client.crt sslkey=client.key"
vs
pgbench.exe -c 10 -t 5000 "host=192.168.220.129 dbname=taskdb user=postgres"
其他设置:
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
number of transactions per client: 5000
number of transactions actually processed: 50000/50000
测试结果:
没有 SSL
SSL
每笔交易都会建立一个连接
平均延迟时间
171.915毫秒
187.695毫秒
tps 包括连接建立
58.168112
53.278062
tps 不包括连接建立
64.084546
58.725846
中央处理器
24%
28%
所有事务均在一个连接中执行
平均延迟时间
6.722毫秒
6.342毫秒
tps 包括连接建立
1587.657278
1576.792883
tps 不包括连接建立
1588.380574
1577.694766
中央处理器
17%
21%
在轻负载时,SSL 的影响与测量误差相当。 如果传输的数据量很大,情况可能会有所不同。 如果我们每个事务建立一个连接(这种情况很少见,通常连接是在用户之间共享的),你有大量的连接/断开,影响可能会大一点。 也就是说,可能存在性能下降的风险,但是差异并不大到不使用保护。
请注意,如果比较操作模式,就会发现很大的差异:您是在同一会话中工作,还是在不同的会话中工作。 这是可以理解的:资源被花费在创建每个连接上。
我们有一个案例,当我们以信任模式连接Zabbix时,即没有检查md5,不需要进行身份验证。 然后客户要求启用md5认证模式。 这会给CPU带来沉重的负载,并且性能下降。 我们开始寻找优化的方法。 解决该问题的一种可能的解决方案是实施网络限制、为 DBMS 建立单独的 VLAN、添加设置以明确谁从哪里连接以及取消身份验证。您还可以优化身份验证设置以降低启用身份验证时的成本,但是一般来说,使用不同的身份验证方法会影响性能,因此在设计 DBMS 的服务器(硬件)的计算能力时需要考虑这些因素。
结论:在许多解决方案中,即使身份验证中的细微差别也会极大地影响项目,并且只有在生产中实施时这一点才变得清晰,这是很糟糕的。
行动审核
审计不仅仅可以是DBMS。 审计的目的是获取有关不同部门正在发生的情况的信息。 这可以是数据库防火墙,也可以是构建 DBMS 的操作系统。
在商业企业级 DBMS 中,审计一切都很好,但在开源中 - 并非总是如此。 这是 PostgreSQL 的功能:
- 默认日志 - 内置日志记录;
- 扩展: pgaudit - 如果默认日志记录对您来说不够,您可以使用单独的设置来解决一些问题。
视频中的报告补充:
“基本语句日志记录可以由标准日志记录工具 log_statement = all 提供。
这对于监控和其他用途来说是可以接受的,但不能提供审计通常所需的详细程度。
拥有对数据库执行的所有操作的列表是不够的。
还应该可以找到审计师感兴趣的具体陈述。
标准日志记录显示用户请求的内容,而 pgAudit 侧重于数据库执行查询时发生的详细信息。
例如,审核员可能想要验证特定表是否是在记录的维护时段内创建的。
这似乎是一个简单的任务,需要基本的审核和 grep,但是如果您看到这样的(故意令人困惑的)示例,该怎么办:
做$$
开始
执行“创建表导入”|| 'ant_table(id int)';
结束$$;
标准日志记录将为您提供:
日志:语句:DO $$
开始
执行“创建表导入”|| 'ant_table(id int)';
结束$$;
在动态创建表的情况下,查找感兴趣的表可能需要一些代码知识。
这并不理想,因为最好简单地按表名称进行搜索。
这就是 pgAudit 派上用场的地方。
对于相同的输入,它将在日志中生成以下输出:
审核:会话,33,1,功能,DO,,,"DO $$
开始
执行“创建表导入”|| 'ant_table(id int)';
结束$$;”
审核:会话,33,2,DDL,创建表,表,public.important_table,创建表 important_table(id INT)
不仅记录 DO 块,还记录 CREATE TABLE 的全文,包括语句类型、对象类型和全名,使搜索更容易。
当记录 SELECT 和 DML 语句时,pgAudit 可以配置为为语句中引用的每个关系记录一个单独的条目。
不需要解析来查找涉及特定表的所有语句(
这将如何影响 DBMS 的性能?
让我们在启用完整审核的情况下运行测试,看看 PostgreSQL 性能会发生什么变化。 让我们为所有参数启用最大数据库日志记录。
我们在配置文件中几乎没有任何改变,最重要的是打开debug5模式以获得最大的信息。
配置文件
log_destination = '标准错误'
日志记录收集器 = 打开
log_truncate_on_rotation = 打开
log_rotation_age = 1d
log_rotation_size = 10MB
log_min_messages = 调试5
log_min_error_statement = 调试5
log_min_duration_statement = 0
debug_print_parse = 打开
debug_print_rewriting = 开
debug_print_plan = 开
debug_pretty_print = 开
log_checkpoints = 开
日志连接=打开
log_disconnections = 开
日志持续时间=开
日志主机名 = 打开
log_lock_waits = 开启
log_replication_commands = 打开
日志临时文件 = 0
log_timezone = '欧洲/莫斯科'
在参数为 1 个 CPU、2,8 GHz、2 GB RAM、40 GB HDD 的 PostgreSQL DBMS 上,我们使用以下命令进行三个负载测试:
$ pgbench -p 3389 -U postgres -i -s 150 benchmark
$ pgbench -p 3389 -U postgres -c 50 -j 2 -P 60 -T 600 benchmark
$ pgbench -p 3389 -U postgres -c 150 -j 2 -P 60 -T 600 benchmark
检测结果:
没有日志记录
带日志记录
数据库总填充时间
43,74秒
53,23秒
RAM
24%
40%
中央处理器
72%
91%
测试 1(50 个连接)
10分钟交易笔数
74169
32445
交易/秒
123
54
平均延迟
405 ms
925 ms
测试 2(150 个连接,其中 100 个可能)
10分钟交易笔数
81727
31429
交易/秒
136
52
平均延迟
550 ms
1432 ms
关于尺寸
数据库大小
2251 Mb
2262 Mb
数据库日志大小
0 MB
4587 MB
底线:全面的审计并不是很好。 审计的数据将与数据库本身的数据一样大,甚至更多。 使用 DBMS 时生成的日志量是生产中的一个常见问题。
我们再看看其他参数:
- 速度变化不大:没有记录 - 43,74 秒,有记录 - 53,23 秒。
- RAM 和 CPU 性能将会受到影响,因为您需要生成审核文件。 这在生产力方面也很明显。
随着连接数的增加,性能自然会略有下降。
对于有审计的公司来说,这就更加困难:
- 有很多数据;
- 不仅需要通过SIEM中的syslog进行审核,还需要通过文件进行审核:如果syslog发生问题,则必须有一个靠近保存数据的数据库的文件;
- 对于审计,需要一个单独的架子,以免浪费在I/O磁盘上,因为它占用大量空间;
- 碰巧信息安全员工到处都需要GOST标准,他们需要国家标识。
限制对数据的访问
让我们看看商业 DBMS 和开源中用于保护数据和访问数据的技术。
一般可以用什么:
- 过程和函数的加密和混淆(Wrapping)——即使可读代码不可读的单独工具和实用程序。 是的,那么它既不能改变也不能重构。 有时至少在 DBMS 端需要这种方法 - 许可证限制或授权逻辑的逻辑在过程和功能级别上精确加密。
- 按行限制数据可见性 (RLS) 是指不同的用户看到一张表,但其中的行组成不同,即某些内容无法在行级别向其他人显示。
- 编辑显示数据(Masking)是指表中某一列的用户要么看到数据,要么只看到星号,也就是说,对于某些用户,信息将被关闭。 该技术根据用户的访问级别确定向哪个用户显示什么内容。
- 安全DBA/应用程序DBA/DBA访问控制是限制对DBMS本身的访问,即信息安全人员可以与数据库管理员和应用程序管理员分开。 开源中此类技术很少,但商业 DBMS 中却有很多。 当有许多用户可以访问服务器本身时,就需要它们。
- 在文件系统级别限制对文件的访问。 您可以授予目录权限和访问特权,以便每个管理员只能访问必要的数据。
- 强制访问和内存清除——这些技术很少被使用。
- 直接来自 DBMS 的端到端加密是在服务器端进行密钥管理的客户端加密。
- 数据加密。 例如,列式加密是指使用加密数据库的单个列的机制。
这对 DBMS 的性能有何影响?
让我们看一下 PostgreSQL 中列式加密的示例。 有一个 pgcrypto 模块,它允许您以加密形式存储选定的字段。 当只有一些数据有价值时,这很有用。 为了读取加密字段,客户端传输解密密钥,服务器解密数据并将其返回给客户端。 没有密钥,任何人都无法对您的数据执行任何操作。
让我们用 pgcrypto 来测试一下。 让我们创建一个包含加密数据和常规数据的表。 下面是创建表的命令,在第一行有一个有用的命令 - 通过 DBMS 注册创建扩展本身:
CREATE EXTENSION pgcrypto;
CREATE TABLE t1 (id integer, text1 text, text2 text);
CREATE TABLE t2 (id integer, text1 bytea, text2 bytea);
INSERT INTO t1 (id, text1, text2)
VALUES (generate_series(1,10000000), generate_series(1,10000000)::text, generate_series(1,10000000)::text);
INSERT INTO t2 (id, text1, text2) VALUES (
generate_series(1,10000000),
encrypt(cast(generate_series(1,10000000) AS text)::bytea, 'key'::bytea, 'bf'),
encrypt(cast(generate_series(1,10000000) AS text)::bytea, 'key'::bytea, 'bf'));
接下来,我们尝试从每个表中获取数据样本并查看执行时间。
从没有加密功能的表中选择:
psql -c "timing" -c "select * from t1 limit 1000;" "host=192.168.220.129 dbname=taskdb
user=postgres sslmode=disable" > 1.txt
秒表已打开。
编号 | 文本1 | 文本2
——+——-+——-
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
...
997 | 997 997 | XNUMX XNUMX
998 | 998 998 | XNUMX XNUMX
999 | 999 999 | XNUMX XNUMX
1000 | 1000 1000 | XNUMX XNUMX
(1000线)
时间:1,386 毫秒
从具有加密功能的表中选择:
psql -c "timing" -c "select id, decrypt(text1, 'key'::bytea, 'bf'),
decrypt(text2, 'key'::bytea, 'bf') from t2 limit 1000;"
"host=192.168.220.129 dbname=taskdb user=postgres sslmode=disable" > 2.txt
秒表已打开。
编号 | 解密| 解密
——+————+————
1 | x31 | x31
2 | x32 | x32
3 | x33 | x33
...
999 | x393939 | x393939
1000 | x31303030 | x31303030
(1000线)
时间:50,203 毫秒
测试结果:
无加密
Pgcrypto(解密)
样本 1000 行
1,386 ms
50,203 ms
中央处理器
15%
35%
RAM
+5%
加密对性能有很大影响。 可以看出,时间增加了,因为加密数据的解密操作(解密通常仍然包含在您的逻辑中)需要大量资源。 也就是说,加密包含某些数据的所有列的想法会导致性能下降。
然而,加密并不是解决所有问题的灵丹妙药。 解密和传输数据过程中的解密数据和解密密钥位于服务器上。 因此,密钥可以被对数据库服务器具有完全访问权限的人(例如系统管理员)截获。
当所有用户的整个列都有一个键时(即使不是针对所有用户,而是针对有限组的客户端),这并不总是好的和正确的。 这就是为什么他们开始进行端到端加密,在 DBMS 中,他们开始考虑在客户端和服务器端加密数据的选项,并且出现了相同的密钥保管库存储 - 在 DBMS 上提供密钥管理的单独产品边。
商业和开源 DBMS 中的安全功能
功能
类型
密码政策
审计
保护过程和函数的源代码
RLS
加密
神谕
商业的
+
+
+
+
+
数据库管理系统
商业的
+
+
+
+
+
商业的
+
+
+
+
扩展
PostgreSQL的
Free
扩展
扩展
-
+
扩展
数据库
Free
-
+
-
-
仅适用于 MongoDB Enterprise
该表还很不完整,但情况是这样的:在商业产品中,安全问题已经解决了很长时间,在开源中,通常会使用某种附加组件来确保安全,许多功能都缺失,有时你必须添加一些东西。 例如,密码策略 - PostgreSQL 有许多不同的扩展(
如果您在任何地方都没有所需的东西该怎么办? 例如,您想要使用不具备客户所需功能的特定 DBMS。
然后,您可以使用与不同 DBMS 配合使用的第三方解决方案,例如 Crypto DB 或 Garda DB。 如果我们谈论的是国内市场的解决方案,那么他们比开源领域更了解 GOST。
第二种选择是自己编写您需要的内容,在程序级别的应用程序中实现数据访问和加密。 确实,使用 GOST 会更加困难。 但一般来说,您可以根据需要隐藏数据,将其放入 DBMS 中,然后根据需要在应用程序级别检索并解密数据。 同时,立即考虑如何在应用程序中保护这些算法。 我们认为,这应该在 DBMS 级别完成,因为它会工作得更快。
该报告首次发布于
关于该主题还可以阅读什么:
来源: habr.com