外观
PostgreSQL 密码策略与管理
密码加密配置
核心加密参数
sql
-- 密码加密方式
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
-- 加密迭代次数(仅适用于scram-sha-256)
ALTER SYSTEM SET scram_iterations = 4096;
-- 验证配置
SHOW password_encryption;
SHOW scram_iterations;加密方式选择
| 加密方式 | 安全性 | 兼容性 | 推荐使用 |
|---|---|---|---|
| md5 | 低 | 高 | 不推荐 |
| scram-sha-256 | 高 | PostgreSQL 10+ | 推荐 |
| password | 极低 | 高 | 不推荐 |
加密配置最佳实践
- 使用scram-sha-256加密方式,这是PostgreSQL 13+的默认值
- 适当调整scram_iterations,平衡安全性和性能
- 避免使用md5和password加密方式
- 定期检查用户密码的加密方式
密码复杂度策略
密码复杂度要求
PostgreSQL本身不直接提供密码复杂度检查,但可以通过以下方式实现:
- 使用pgcrypto扩展:实现密码复杂度验证
- 使用外部认证:如LDAP、Kerberos
- 使用客户端工具:如pgAdmin提供密码复杂度检查
- 使用自定义函数:在CREATE USER或ALTER USER时调用
自定义密码复杂度函数示例
sql
-- 创建密码复杂度检查函数
CREATE OR REPLACE FUNCTION check_password_strength(password TEXT) RETURNS BOOLEAN AS $$
BEGIN
-- 密码长度至少8位
IF LENGTH(password) < 8 THEN
RAISE EXCEPTION '密码长度至少8位';
END IF;
-- 包含至少一个大写字母
IF password !~ '[A-Z]' THEN
RAISE EXCEPTION '密码必须包含至少一个大写字母';
END IF;
-- 包含至少一个小写字母
IF password !~ '[a-z]' THEN
RAISE EXCEPTION '密码必须包含至少一个小写字母';
END IF;
-- 包含至少一个数字
IF password !~ '[0-9]' THEN
RAISE EXCEPTION '密码必须包含至少一个数字';
END IF;
-- 包含至少一个特殊字符
IF password !~ '[!@#$%^&*(),.?":{}|<>]' THEN
RAISE EXCEPTION '密码必须包含至少一个特殊字符';
END IF;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器,在创建用户时检查密码
CREATE OR REPLACE FUNCTION check_user_password() RETURNS TRIGGER AS $$
BEGIN
PERFORM check_password_strength(NEW.password);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器(需要超级用户权限)
-- CREATE TRIGGER trg_check_user_password BEFORE INSERT OR UPDATE ON pg_catalog.pg_authid FOR EACH ROW EXECUTE FUNCTION check_user_password();密码复杂度最佳实践
- 密码长度至少8位
- 包含大小写字母、数字和特殊字符
- 避免使用常见密码和字典词
- 避免使用与用户名相关的密码
- 定期更换密码
密码有效期管理
配置密码有效期
PostgreSQL本身不支持密码有效期,但可以通过以下方式实现:
- 使用外部认证系统:如LDAP支持密码有效期
- 使用自定义扩展:如pg_tmplug
- 使用自定义表和函数:跟踪密码创建和修改时间
自定义密码有效期实现
sql
-- 创建密码有效期表
CREATE TABLE password_expiry (
username TEXT PRIMARY KEY,
password_last_changed TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
password_expiry_date TIMESTAMP,
FOREIGN KEY (username) REFERENCES pg_catalog.pg_authid(rolname)
);
-- 创建函数更新密码有效期
CREATE OR REPLACE FUNCTION update_password_expiry() RETURNS EVENT_TRIGGER AS $$
BEGIN
IF tg_tag = 'CREATE ROLE' OR tg_tag = 'ALTER ROLE' THEN
-- 这里可以添加逻辑来更新密码有效期
-- 例如:当用户密码更改时,更新有效期
END IF;
END;
$$ LANGUAGE plpgsql;
-- 创建事件触发器
-- CREATE EVENT TRIGGER trg_update_password_expiry ON ddl_command_end WHEN TAG IN ('CREATE ROLE', 'ALTER ROLE') EXECUTE FUNCTION update_password_expiry();
-- 检查密码是否过期的函数
CREATE OR REPLACE FUNCTION is_password_expired(username TEXT) RETURNS BOOLEAN AS $$
DECLARE
expiry_date TIMESTAMP;
BEGIN
SELECT password_expiry_date INTO expiry_date FROM password_expiry WHERE username = $1;
IF expiry_date IS NOT NULL AND expiry_date < CURRENT_TIMESTAMP THEN
RETURN TRUE;
END IF;
RETURN FALSE;
END;
$$ LANGUAGE plpgsql;密码有效期最佳实践
- 密码有效期设置为90天
- 提前30天、7天、1天发送密码过期提醒
- 允许用户自行重置密码
- 管理员可以强制重置过期密码
- 为服务账号设置较长的密码有效期
密码重置方法
超级用户密码重置
sql
-- 方法1:使用psql命令行重置
ALTER USER postgres WITH PASSWORD 'new_password';
-- 方法2:如果无法登录,修改pg_hba.conf文件
-- 将local all all peer改为local all all trust,然后重启或重载配置
-- 登录后重置密码,再改回原来的认证方式普通用户密码重置
sql
-- 超级用户重置普通用户密码
ALTER USER username WITH PASSWORD 'new_password';
-- 用户自行重置密码(需要知道旧密码)
ALTER USER username WITH PASSWORD 'new_password' VALID UNTIL 'infinity';忘记密码的处理流程
- 确认用户身份
- 超级用户重置密码
- 强制用户首次登录时修改密码
- 记录密码重置操作
密码重置最佳实践
- 密码重置需要验证用户身份
- 密码重置后,强制用户首次登录时修改密码
- 记录所有密码重置操作
- 使用安全的方式传递新密码
- 避免在日志中记录明文密码
密码安全监控
监控登录失败
sql
-- 查看登录失败次数
SELECT * FROM pg_stat_auth_members;
-- 查看当前连接
SELECT * FROM pg_stat_activity;
-- 配置登录失败日志
ALTER SYSTEM SET log_connections = on;
ALTER SYSTEM SET log_disconnections = on;
ALTER SYSTEM SET log_failed_connections = on;监控密码策略合规性
sql
-- 检查用户密码加密方式
SELECT rolname, rolpassword FROM pg_authid WHERE rolpassword IS NOT NULL;
-- 检查用户创建时间
SELECT rolname, rolcreated FROM pg_authid;
-- 检查哪些用户有超级用户权限
SELECT rolname FROM pg_authid WHERE rolsuper = true;安全监控最佳实践
- 启用登录失败日志
- 监控异常登录尝试
- 定期检查用户权限和密码加密方式
- 配置告警,当登录失败次数超过阈值时通知
- 定期审计用户密码策略合规性
密码管理最佳实践
日常管理
- 定期更换密码,建议90天更换一次
- 使用强密码策略
- 避免共享密码
- 使用密码管理工具存储密码
- 为不同环境使用不同的密码
服务账号管理
- 为每个服务创建独立的数据库账号
- 服务账号密码定期更换
- 服务账号权限最小化
- 避免在代码中硬编码密码
- 使用环境变量或配置文件管理服务账号密码
权限管理
- 遵循最小权限原则
- 定期审计用户权限
- 及时撤销不再需要的权限
- 使用角色管理权限
- 限制超级用户数量
常见问题(FAQ)
Q1:如何查看用户的密码加密方式?
A1:查看用户密码加密方式的方法:
sql
SELECT rolname,
CASE
WHEN rolpassword LIKE 'SCRAM-SHA-256%' THEN 'scram-sha-256'
WHEN rolpassword LIKE 'md5%' THEN 'md5'
WHEN rolpassword IS NULL THEN 'no password'
ELSE 'other'
END AS encryption_type
FROM pg_authid;Q2:如何将所有用户的密码加密方式从md5转换为scram-sha-256?
A2:转换密码加密方式的步骤:
- 修改postgresql.conf中的password_encryption为scram-sha-256
- 重载配置
- 要求所有用户重新设置密码
- 验证所有用户的密码都已转换
Q3:如何强制用户首次登录时修改密码?
A3:强制首次登录修改密码的方法:
- 创建一个标记表,记录用户是否已修改密码
- 创建一个登录触发器,检查用户是否需要修改密码
- 如果需要修改密码,限制用户只能执行密码修改操作
Q4:如何防止暴力破解密码?
A4:防止暴力破解的方法:
- 启用登录失败日志
- 配置防火墙规则,限制登录IP
- 使用fail2ban等工具,自动封禁多次失败的IP
- 使用双因素认证
- 限制登录尝试次数
Q5:如何安全地存储服务账号密码?
A5:安全存储服务账号密码的方法:
- 使用环境变量
- 使用加密的配置文件
- 使用密钥管理服务(如AWS KMS、HashiCorp Vault)
- 避免在代码中硬编码密码
- 定期轮换服务账号密码
Q6:如何审计密码策略合规性?
A6:审计密码策略合规性的方法:
- 检查用户密码加密方式
- 检查密码复杂度是否符合要求
- 检查密码是否过期
- 检查用户权限是否符合最小权限原则
- 检查是否存在共享账号
Q7:如何配置双因素认证?
A7:配置双因素认证的方法:
- 使用外部认证系统,如LDAP结合TOTP
- 使用PostgreSQL扩展,如pg_totp
- 使用代理服务器,在数据库前面添加双因素认证
- 使用云服务提供商的双因素认证
Q8:如何处理密码泄露事件?
A8:处理密码泄露事件的步骤:
- 立即重置所有可能泄露的密码
- 检查系统日志,确定是否有未授权访问
- 加强安全监控
- 通知相关人员
- 调查泄露原因,防止再次发生
Q9:如何备份和恢复密码策略?
A9:备份和恢复密码策略的方法:
- 备份postgresql.conf文件
- 备份pg_hba.conf文件
- 备份自定义的密码策略函数和表
- 记录密码策略文档
- 恢复时,确保所有配置一致
Q10:如何为不同用户设置不同的密码策略?
A10:为不同用户设置不同密码策略的方法:
- 使用角色管理不同的密码策略
- 使用外部认证系统,支持基于用户组的密码策略
- 使用自定义函数,根据用户名或角色应用不同的密码策略
- 使用不同的数据库实例,配置不同的密码策略
