# 5.8.Row安全策略

除了SQL标准之外特权制度可通过授予,桌子上可以有row安全策略这限制了在每个用户的基础上,哪些行可以通过正常查询返回,哪些行可以通过数据修改命令插入、更新或删除。此功能也称为行级安全性。默认情况下,表没有任何策略,因此,如果用户根据SQL特权系统对表具有访问权限,则表中的所有行都可以平等地用于查询或更新。

在表上启用行安全性时(使用改变桌子。。。启用行级安全性),行安全策略必须允许所有用于选择行或修改行的表的正常访问。(但是,表的所有者通常不受行安全策略的约束。)如果该表不存在任何策略,则使用默认的拒绝策略,这意味着没有可见或可修改的行。应用于整个表的操作,例如截断推荐人,不受世界其他地区安全的约束。

行安全策略可以特定于命令、角色或两者。可以指定要应用于的策略全部的命令,或者选择, 插入, 使现代化删去。可以为给定的策略分配多个角色,并应用常规角色成员资格和继承规则。

要指定哪些行根据策略可见或可修改,需要一个返回布尔结果的表达式。在来自用户查询的任何条件或函数之前,将为每一行计算该表达式。(这条规则的唯一例外是防漏的保证不泄露信息的功能;优化器可以选择在行安全检查之前应用这些函数。)表达式不返回的行符合事实的不会被处理。可以指定单独的表达式,以对可见的行和允许修改的行提供独立的控制。策略表达式作为查询的一部分运行,并具有运行查询的用户的权限,尽管安全定义函数可用于访问调用用户不可用的数据。

超级用户和角色绕过RLS属性在访问表时总是绕过行安全系统。表所有者通常也会绕过行安全性,尽管表所有者可以选择使用改变桌子。。。部队行级安全.

启用和禁用行安全性,以及向表中添加策略,始终是表所有者的特权。

策略是使用创建策略命令,使用改变政策命令,并使用放弃政策命令要启用和禁用给定表的行安全性,请使用改变桌子命令

每个策略都有一个名称,可以为一个表定义多个策略。由于策略是特定于表的,因此表的每个策略必须具有唯一的名称。不同的表可能有同名的策略。

当多个策略应用于给定的查询时,它们将使用(对于默认的许可策略)或使用(对于限制性政策)。这类似于一个给定角色拥有其所属的所有角色的特权的规则。下文将进一步讨论允许政策与限制政策。

作为一个简单的例子,下面是如何在账户关系,只允许经理角色访问行,并且仅访问其帐户的行:

CREATE TABLE accounts (manager text, company text, contact_email text);

ALTER TABLE accounts ENABLE ROW LEVEL SECURITY;

CREATE POLICY account_managers ON accounts TO managers
    USING (manager = current_user);

上述政策隐含地提供了支票与其相同的条款使用子句,使约束同时应用于命令选择的行(因此管理器无法选择, 使现代化删去属于不同管理器的现有行)和由命令修改的行(因此无法通过创建属于不同管理器的行)插入使现代化).

如果未指定角色或特殊用户名平民的则策略将应用于系统上的所有用户。允许所有用户只访问一行中自己的行用户表中,可以使用一个简单的策略:

CREATE POLICY user_policy ON users
    USING (user_name = current_user);

这与前面的示例类似。

要对要添加到表中的行与那些可见的行使用不同的策略,可以组合多个策略。这对策略将允许所有用户查看用户表,但只修改自己的:

CREATE POLICY user_sel_policy ON users
    FOR SELECT
    USING (true);
CREATE POLICY user_mod_policy ON users
    USING (user_name = current_user);

在一个选择命令,这两个策略使用,其净效果是可以选择所有行。在其他命令类型中,仅应用第二个策略,因此效果与之前相同。

也可以使用禁用行安全性改变桌子命令禁用行安全性不会删除表中定义的任何策略;他们只是被忽视了。然后,表中的所有行都是可见的和可修改的,受标准SQL特权系统的约束。

下面是如何在生产环境中使用此功能的一个较大示例。桌子passwd模拟Unix密码文件:

-- Simple passwd-file based example
CREATE TABLE passwd (
  user_name             text UNIQUE NOT NULL,
  pwhash                text,
  uid                   int  PRIMARY KEY,
  gid                   int  NOT NULL,
  real_name             text NOT NULL,
  home_phone            text,
  extra_info            text,
  home_dir              text NOT NULL,
  shell                 text NOT NULL
);

CREATE ROLE admin;  -- Administrator
CREATE ROLE bob;    -- Normal user
CREATE ROLE alice;  -- Normal user

-- Populate the table
INSERT INTO passwd VALUES
  ('admin','xxx',0,0,'Admin','111-222-3333',null,'/root','/bin/dash');
INSERT INTO passwd VALUES
  ('bob','xxx',1,1,'Bob','123-456-7890',null,'/home/bob','/bin/zsh');
INSERT INTO passwd VALUES
  ('alice','xxx',2,1,'Alice','098-765-4321',null,'/home/alice','/bin/zsh');

-- Be sure to enable row-level security on the table
ALTER TABLE passwd ENABLE ROW LEVEL SECURITY;

-- Create policies
-- Administrator can see all rows and add any rows
CREATE POLICY admin_all ON passwd TO admin USING (true) WITH CHECK (true);
-- Normal users can view all rows
CREATE POLICY all_view ON passwd FOR SELECT USING (true);
-- Normal users can update their own records, but
-- limit which shells a normal user is allowed to set
CREATE POLICY user_mod ON passwd FOR UPDATE
  USING (current_user = user_name)
  WITH CHECK (
    current_user = user_name AND
    shell IN ('/bin/bash','/bin/sh','/bin/dash','/bin/zsh','/bin/tcsh')
  );

-- Allow admin all normal rights
GRANT SELECT, INSERT, UPDATE, DELETE ON passwd TO admin;
-- Users only get select access on public columns
GRANT SELECT
  (user_name, uid, gid, real_name, home_phone, extra_info, home_dir, shell)
  ON passwd TO public;
-- Allow users to update certain columns
GRANT UPDATE
  (pwhash, real_name, home_phone, extra_info, shell)
  ON passwd TO public;

与任何安全设置一样,测试并确保系统按预期运行非常重要。使用上面的示例,这表明权限系统工作正常。

-- admin can view all rows and fields
postgres=> set role admin;
SET
postgres=> table passwd;
 user_name | pwhash | uid | gid | real_name |  home_phone  | extra_info | home_dir    |   shell