数据库安全的第一道防线是完善的用户和权限管理体系。PostgreSQL 提供了精细的权限控制模型,从数据库级别到列级别都能控制。

用户/角色管理

PostgreSQL 中用户和角色概念相通——区别在于用户默认有 LOGIN 权限,角色没有。

-- 创建用户
CREATE USER alice WITH PASSWORD 'alice123';
-- 等价于 CREATE ROLE alice WITH LOGIN PASSWORD 'alice123';

-- 创建角色(不用于登录,用于权限分组)
CREATE ROLE sales_team;
CREATE ROLE dev_team;

CREATE USER bob WITH PASSWORD 'bob456';
CREATE USER charlie WITH PASSWORD 'charlie789';

修改用户

-- 修改密码
ALTER USER alice WITH PASSWORD 'newpassword';

-- 修改属性
ALTER USER alice WITH SUPERUSER;  -- 设为超级用户
ALTER USER alice WITH NOSUPERUSER;  -- 取消超级用户
ALTER USER alice WITH CREATEDB;  -- 允许创建数据库
ALTER USER alice WITH CREATEROLE;  -- 允许创建角色

-- 禁用用户
ALTER USER alice WITH NOLOGIN;

-- 重命名
ALTER USER alice RENAME TO alice_new;

删除用户

-- 删除前确认没有依赖的数据库对象
REASSIGN OWNED BY alice TO postgres;  -- 转移对象所有权
DROP OWNED BY alice;  -- 删除用户所有的对象
DROP USER alice;

角色继承

角色的核心价值在于层级管理——把权限授予角色,然后把角色授予用户:

-- 创建角色层级
CREATE ROLE readonly NOINHERIT;  -- NOINHERIT:不自动继承权限
CREATE ROLE readwrite;
CREATE ROLE admin;

-- 授予角色权限
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO readwrite;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO admin;

-- 继承关系(admin 继承 readwrite 和 readonly 的权限)
GRANT readonly TO readwrite;
GRANT readwrite TO admin;

-- 授予用户
GRANT readwrite TO bob;

使用 NOINHERIT 的角色需要用 SET ROLE 激活:

-- 设置角色
SET ROLE readonly;
-- 现在拥有 readonly 的权限
SELECT * FROM orders;  -- 可以查询
INSERT INTO orders ... VALUES ...;  -- ❌ 不可插入

-- 恢复原始用户
RESET ROLE;

对象权限

-- 授予对特定表的查询权限
GRANT SELECT ON orders TO readonly;
GRANT SELECT, INSERT, UPDATE ON orders TO readwrite;
GRANT ALL ON orders TO admin;

-- 授予 schema 的使用权限
GRANT USAGE ON SCHEMA public TO readonly;
GRANT CREATE ON SCHEMA public TO readwrite;

默认权限

对现有表做了 GRANT,但新表怎么办?用 ALTER DEFAULT PRIVILEGES

-- 当前用户将来创建的所有表,readwrite 组都有 SELECT, INSERT 权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO readwrite;

-- 当前用户将来创建的所有函数,readonly 组都有执行权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT EXECUTE ON FUNCTIONS TO readonly;

列级权限

-- 敏感列仅对特定角色开放
GRANT SELECT (name, email, department) ON employees TO readonly;
-- 但工资列隐藏
REVOKE SELECT (salary) ON employees FROM readonly;

行级安全(RLS)

PostgreSQL 9.5+ 支持行级安全策略,让不同用户看到不同的数据行:

-- 启用行级安全
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE orders FORCE ROW LEVEL SECURITY;  -- 对表所有者同样生效

-- 创建策略:每个用户只能看自己的订单
CREATE POLICY user_orders ON orders
    FOR SELECT
    USING (customer_id = current_setting('myapp.user_id')::INT);

-- 创建策略:用户只能修改自己的订单
CREATE POLICY user_update_orders ON orders
    FOR UPDATE
    USING (customer_id = current_setting('myapp.user_id')::INT)
    WITH CHECK (customer_id = current_setting('myapp.user_id')::INT);

多角色 RLS 示例

-- 数据表带可见性控制
ALTER TABLE documents ADD COLUMN visibility VARCHAR(20) DEFAULT 'private';
ALTER TABLE documents ADD COLUMN owner_id INT;
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;

-- 公开文档:所有人可见
CREATE POLICY public_docs ON documents
    FOR SELECT
    USING (visibility = 'public');

-- 私有文档:仅自己可见
CREATE POLICY own_docs ON documents
    FOR SELECT
    USING (owner_id = current_setting('app.user_id')::INT);

-- 已提交文档:仅审核组可见
CREATE POLICY reviewed_docs ON documents
    FOR SELECT
    USING (visibility = 'reviewed' AND
           current_role IN ('reviewer', 'admin'));

pg_hba.conf 认证配置

用户能连接数据库不仅取决 SQL 权限,还取决于 pg_hba.conf

# TYPE  DATABASE    USER        ADDRESS          METHOD
local   all         all                          scram-sha-256    # 本地连接
host    all         all         127.0.0.1/32     scram-sha-256    # 本机网络
host    all         all         192.168.1.0/24   scram-sha-256    # 内网
host    all         all         0.0.0.0/0        reject            # 拒绝外网

认证方法优先级:

方法 安全性 场景
trust 最低 开发环境
password 密码明文传输
md5 常用,密码哈希
scram-sha-256 推荐,抗暴力破解
cert 很高 客户端证书认证
gssapi 企业的 Kerberos 环境

权限最佳实践

最小权限原则

-- 创建只读账号用于报表查询
CREATE ROLE report_user LOGIN PASSWORD 'report123';
GRANT CONNECT ON DATABASE mydb TO report_user;
GRANT USAGE ON SCHEMA public TO report_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO report_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT SELECT ON TABLES TO report_user;

审计登录

-- 开启登录审计
ALTER USER alice SET log_login_connections = on;  -- 需要超级用户设置

-- 查看 pg_hba.conf 设置后生效
-- 在配置文件中增加:
-- log_connections = on
-- log_disconnections = on

定期检查权限

-- 查看用户的权限
SELECT * FROM information_schema.role_table_grants
WHERE grantee = 'readwrite';

-- 查看当前用户的权限
SELECT * FROM information_schemaapplicable_roles;

-- 查看数据库的权限概要
SELECT 
    grantee,
    table_schema,
    table_name,
    string_agg(privilege_type, ', ' ORDER BY privilege_type) AS privileges
FROM information_schemarole_table_grants
WHERE table_schema = 'public'
GROUP BY grantee, table_schema, table_name
ORDER BY grantee, table_name;

小结

用户和权限管理是数据库安全的核心。PostgreSQL 的权限体系从认证(pg_hba.conf)到角色继承、从对象权限到行级安全(RLS),提供了全方位的分级控制。核心实践:最小权限原则、角色而非直接用户授权、定期审计。

下一篇文章将学习 PostgreSQL 的高级特性——JSON、全文搜索、扩展等。

Summary: 用户角色管理、GRANT 权限、行级安全(RLS)与认证配置。