跳到主要内容
版本:1.0.14

sepgsql

sepgsql是一个基于SELinux安全策略的支持基于标签的强制访问控制(MAC)模块。

警告:当前的实现具有明显的限制,并且不支持对所有动作的强制访问控制。详见第 C.35.7 节。

1. 概述

这个模块和SELinux集成在一起在Halo提供的安全检查之上,提供了一个 额外的安全检查层。从SELinux的角度来看,这个模块允许 Halo作为一个用户空间对象管理器。

对每一次由 DML 查询发起的表或者函数访问将根据系统安全策略进行检查。这种检查是在Halo执行的常规权限检查之外进行的。

SELinux访问控制决定是通过使用安全标签来做出的,安全标签使用system_u:object_r:sepgsql_table_t:s0 这样的字符串表示。每个访问控制决定涉及两个标签:尝试执行该动作的主体的标签,以及要在执行该动作的客体的标签。由于这些标签可以被应用于任何种类的对象,对于存储在数据库中的对象的(用这个模块做出的)访问控制决定,服从于任意其他类型对象(例如文件)的同一种一般准则。这种设计是为了允许一种中央安全策略来保护信息资产,而不依赖于这些资产是如何存储的。

SECURITY LABEL语句允许为一个数据库对象分配安全标签。

2. 安装

sepgsql只能在启用了 SELinux的 Linux 2.6.28 或者更高版本上使用。在任何其他平台上都无法使用这个模块。你将还需要 libselinux 2.1.10 或者更高版本以及 selinuxpolicy 3.9.13 或者更高版本(尽管某些发行中可能 把必要的规则逆向移植到较老的策略版本中)。

你可以使用sestatus命令检查 SELinux的状态。一种典型的显示是:

$ sestatus

SELinux status: enabled

SELinuxfs mount: /selinux

Current mode: enforcing

Mode from config file: enforcing

Policy version: 24

Policy from config file: targeted

如果没有安装或者启用SELinux,你就必须在安装这个模块之前先安装或者启用它。

3. 回归测试

由于SELinux的本质,为sepgsql 运行回归测试要求一些额外的配置步骤,某些步骤还需要由 root 来完成。该回归测试无法通过普通的make check或者make installcheck命令运行,你必须建立配置并且接着手工调用测试脚本。这些测试必须在一个已配置 Halo

编译树的contrib/sepgsql目录中运行。尽管它们要求一个编译树,但是 这些测试被设计成在一个已安装服务器上执行,也就是说它们可以比得上 make installcheck(而不是make check)。

首先,根据第C.35.2 节中的指导在一个工作数据库中设置 sepgsql。注意:当前操作系统用户必须能够不使用口令认证作为超级用户连接到该数据库。

第二,为该回归测试编译和安装策略包。sepgsql-regtest策略是一个特殊的策略包,它提供一组在回归测试浅见要被允许的规则。它应该从策略源文件 sepgsql-regtest.te编译,这需要通过使用 make和一个 SELinux 提供的 Makefile 完成。你将需要在你自己的系统上找到合适的 Makefile,下面展示的路径只是一个例子。(这个 Makefile 通常由 selinuxpolicy-devel 或 selinux-policy RPM 提供。)一旦编译好,使用semodule命令安装这个策略包,它会把所提供的策略包载入到内核中。如果该包被正确地安装,semodule -l应该把 sepgsql-regtest列成一个可用的策略包:

$ cd .../contrib/sepgsql

$ make -f /usr/share/selinux/devel/Makefile

$ sudo semodule -u sepgsql-regtest.pp

$ sudo semodule -l | grep sepgsql

sepgsql-regtest 1.07

第三,打开sepgsql_regression_test_mode。由于安全性的原因, sepgsql-regtest中的规则默认没有被启用the sepgsql_regression_test_mode参数会启用启动该回归测试所的规则。它可以使用setsebool命令来启用:

$ sudo setsebool sepgsql_regression_test_mode on

$ getsebool sepgsql_regression_test_mode

sepgsql_regression_test_mode --> on

第四,验证你的 shell 在unconfined_t域中操作:

$ id -Z

unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

如果有必要,可以参考第 C.35.8 节来调整你的工作域。

最后,运行该回归测试脚本:

$ ./test_sepgsql

这个脚本将尝试验证你已经正确地完成了所有的配置步骤,接下来它将运行 sepgsql模块的回归测试。

完成测试后,推荐你禁用 sepgsql_regression_test_mode参数:

$ sudo setsebool sepgsql_regression_test_mode off

你可能想要完全移除sepgsql-regtest策略:

$ sudo semodule -r sepgsql-regtest

4. GUC 参数

sepgsql.permissive (boolean)

不管系统设置如何,这个参数让sepgsql在自由模式中运行。默认值为关闭。这个参数只能在postgresql.conf文件中或者服务器命令行上被设置。

当这个参数为打开时,sepgsql在自由模式中运行,即便 SELinux 运行在强制模式中也是如此。这个参数主要用于测试目的。

sepgsql.debug_audit (boolean)

不管系统策略设置如何,这个参数启用打印审计消息。默认值为关闭,表示将根据系统设置打印消息。

SELinux的安全性策略也具有控制是否记录特定访问的规则。默认情况下,违法访问将会被记录,但是被允许的访问则不会被记录。

这个参数强制打开所有可能的记录而不管该系统策略。

5. 特性

5.1. 控制对象类

SELinux的安全模型把所有访问控制规则描述为一个主体(典型的是一个数据库客户端)和一个客体(例如一个数据库对象)之间的关系,每一个这样的关系被一个安全标签标识。

如果尝试访问一个未加标签的客体,会认为该客体被分配了标签unlabeled_t。

当前,sepgsql允许把安全标签分配给模式、表、列、序列、视图和函数。在使用sepgsql时,安全标签会在所支持的数据库对象创建时自动分配给它们。这种标签被称为默认安全标签并且根据系统安全性策略决定,默认安全标签被用来输入创建者标签、分配给新对象父对象的标签以及所构造对象的可选名称。

一个新数据库对象基本上会继承父对象的安全标签,不过当安全策略具有特殊的类型转换规则时,将会应用一个不同的标签。对于模式,其父对象是当前数据库。对于表、序列、视图和函数,父对象是包含它的模式。对于列,其父对象是包含它的表。

5.2. DML 权限

对于表,根据语句的种类会对所有被引用的目标表检查

db_table:select、db_table:insert、db_table:update或者db_table:delete。此外,对于所有其列被WHERE或RETURNING子句引用、作为 UPDATE的数据源(以及其他情况)的表,都要检查db_table:select。

对每一个被引用的列也将检查列级权限。不仅在使用SELECT读取列时会检查db_column:select,在其他 DML 语句中引用列时也要检查。对于被UPDATE或者INSERT修改的列也将检查 db_column:update或者db_column:insert。

例如,考虑:

UPDATE t1 SET x = 2, y = func1(y) WHERE z = 100;

这里,将对t1.x检查db_column:update,因为它被更新。对t1.y将检查db_column:{select update},因为它既被更新也被引用。并且会对t1.z检查 db_column:select,因为它只被更新。还将在表层面上检查 db_table:{select update}。

对于序列,当我们使用SELECT引用一个序列对象时会检查 db_sequence:get_value。不过,我们当前不会检查执行相应函数(例如lastval())的权限。

对于视图,将检查db_view:expand,然后对从视图展开来的任何对象都会分别检查所需的权限。

对于函数,当用户尝试在一个查询中或者使用快路径调用执行一个函数时会检查

db_procedure:{execute}。如果该函数是一个可信过程,也会检查 db_procedure: {entrypoint}权限来看看它能否作为一个可信程序的入口点来执行。

为了访问任何模式对象,在其所在的模式上需要db_schema:search 权限。当不用模式限定引用一个对象时,其上没有该权限的模式不会被搜索(就好 像该用户在该模式上没有USAGE特权)。如果出现一个显式的模式限定,当该用户在提及的模式上没有要求的权限时将会发生一个错误。

客户端必须被允许访问所有引用到的表和列,即便它们是由视图扩展得来的。这样我们可以应用一致的访问控制规则而不管表内容被引用的方式。

默认的数据库特权系统允许数据库超级用户使用 DML 命令修改系统目录并且引用或者修改TOAST 表。当sepgsql被启用时,这些操作会被禁止。

5.3. DDL 权限

SELinux为每一种对象类型定义了数个权限来控制常用操作,例如创建、修改、删除以及重新标记安全标签。此外,数种对象类型具有特殊的权限来控制它们的特性化操作,例如在一个特定模式中增加或者删除名字项。

创建一个新的数据库对象要求create权限。SELinux将基于客户端的安全标签来授予或者否决这个权限并且为新对象提出安全标签。在某些情况下,还需要额外的特权:

• CREATE DATABASE额外要求源数据库或者模板数据库的getattr权限。

• 创建一个模式对象额外地要求父模式上的add_name权限。

• 创建一个表额外要求创建单个表列的权限,就好像每一个表列都是一个 单独的顶层对象。

• 创建一个被标记为LEAKPROOF的函数额外要求 install权限(当为一个现有函数设置LEAKPROOF时也要检查这个权限)。

当执行DROP命令时,在要移除的对象上会检查drop。 对于通过CASCADE间接被删除的对象也会检查权限。删除包含在一个特定模式内的对象(表、视图、序列以及过程)额外地要求该模式上的 remove_name。

在执行ALTER命令时,会在被修改的对象上为每一种对象类型检查 setattr。附属对象(例如一个表的索引或者触发器)除外,这种情况下权限是在父对象上检查的。在某些情况下,还需要额外的权限:

• 将一个对象移动到一个新的模式要求旧模式上的remove_name 权限以及新模式上的add_name权限。

• 设置一个函数上的LEAKPROOF属性要求install权限。

• 在一个对象上使用SECURITY LABEL会额外对该对象要求 relabelfrom权限连同它的旧安全标签以及relabelto 权限连同它的新安全标签。

5.4. 可信过程

可信过程类似于 SECURITY DEFINER 函数或者 setuid 命令。 SELinux提供了一个特性来允许可信代码使用一个不同于客户端的安全标签运行,通常这是为了提供对敏感数据的高度控制的访问(例如行可能会被忽略或者存储值的精度可能会被降低)。一个函数是否可以作为可信过程受到其安全标签和操作系统安全性策略的控制。例如:

=## CREATE TABLE customer (

cid int primary key,

cname text,

credit text

);

CREATE TABLE

=## SECURITY LABEL ON COLUMN customer.credit

IS 'system_u:object_r:sepgsql_secret_table_t:s0';

SECURITY LABEL

=## CREATE FUNCTION show_credit(int) RETURNS text

AS 'SELECT regexp_replace(credit, ''-[0-9]+$'', ''-xxxx'', ''g'')

FROM customer WHERE cid = $1'

LANGUAGE sql;

CREATE FUNCTION

=## SECURITY LABEL ON FUNCTION show_credit(int)

IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';

SECURITY LABEL

上述的操作应该由一个管理员用户执行。

=## SELECT * FROM customer;

ERROR: SELinux: security policy violation

=## SELECT cid, cname, show_credit(cid) FROM customer;

cid | cname | show_credit

-----+--------+---------------------

1 | taro | 1111-2222-3333-xxxx

2 | hanako | 5555-6666-7777-xxxx

(2 rows)

在这种情况下,一个常规用户无法直接引用customer.credit,但是一个可信过程show_credit允许用户在打印客户的信用卡号时把一些数字掩盖掉。

5.5. 动态域转换

如果安全性策略允许,可以使用 SELinux 的动态域转换特性来切换客户端进程(客户端域)的安全性标签到一个新的上下文。该客户端域需要 setcurrent权限还有从旧的域到新的域的 dyntransition权限。

动态域转换需要被仔细考虑,因为在用户看来,它们允许用户切换其标签, 并且因而切换特权,而不是(像可信过程的情况那样)受系统的强制性管理。 因此,只有当被用来切换到一个比原来的域具有更少特权的域时, dyntransition才被认为是安全的。例如:

select sepgsql_getcon();

sepgsql_getcon

-------------------------------------------------------

unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

(1 row)


SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-

s0:c1.c4');

sepgsql_setcon

----------------

t

(1 row)


regression=#SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-
s0:c1.c1023');

ERROR: SELinux: security policy violation

在上面的这个例子中,我们被允许从较大范围的c1.c1023切换到较小范围的c1.c4,但却禁止切换回去。

动态域转换和可信过程的组合开启了一种有趣的使用案例,它适合典型的 连接池软件的处理生命周期。即便你的连接池软件不被允许运行大部分的 SQL 命令,你可以从一个可信过程中使用 sepgsql_setcon()函数允许它切换该客户端的安全标签,这个过程应该采用一些证据来授权,该请求切换该客户端标签。之后,这个会话将会具有目标用户而不是连接池的特权。该连接池之后可以用 NULL参数再次调用sepgsql_setcon() 逆转这次安全标签改变,当然再次的调用也要在一个可信过程中配合适当的权限检查进行。这里的要点是只有可信过程实际具有权限来更改有效的安全标签,并且只有在得到适当的证据后才这样做。当然,对于安全操作,必须保护证据存储(表、过程定义或者其他什么)不会受到未经授权的访问。

5.6. 杂项

我们全面拒绝LOAD命令,因为任何模块的装载都可能很轻易地绕过安全策略的强制保护。

6. Sepgsql 函数

表 C.29展示了可用的函数。

表 C.29. Sepgsql 函数

函数/简述
sepgsql_getcon () → text 返回客户端域,即客户端的当前安全标签
sepgsql_setcon ( text ) → boolean 如果安全策略允许,则将当前会话的客户端域切换到新域。它还接受NULL输入作为转换到客户机原始域的请求
sepgsql_mcstrans_in ( text ) → text 如果 mcstrans 守护进程正在运行,则将给定的限定 MLS/MCS 范围转换为原始格式
sepgsql_mcstrans_out ( text ) → text如果 mcstrans 守护程序正在运行,则将给定的原始 MLS/MCS 范围转换为限定格式
sepgsql_restorecon ( text ) → boolean 为当前数据库中的所有对象设置初始安全标签。参数可以是NULL,也可以是要用作系统默认值替代项的规范文件的名称

7. 限制

数据定义语言(DDL)权限

收到实现的限制,一些 DDL 操作无法检查权限。

数据控制语言(DCL)权限

由于实现限制,DCL 操作不检查权限。

行级访问控制

Halo支持行级访问,但是 sepgsql不支持行级访问。

隐蔽通道

sepgsql不会尝试隐藏一个特定对象的存在,即便是用户不被允许引用该对象。例如,即便我们无法得到一个不可见对象的内容,我们也可以通过主键冲突、外键违背等等结果来推知该对象的存在。一个绝密表的存在无法被隐藏,我们只希望能够隐藏其内容。