外观
PostgreSQL 密码策略
密码加密方式
加密算法概述
PostgreSQL支持多种密码加密算法,不同版本默认使用的算法有所不同:
- md5:从PostgreSQL 7.4开始支持,结合用户名和密码生成MD5哈希值
- scram-sha-256:从PostgreSQL 10开始支持,14版本起成为默认加密方式,提供更强的安全性
配置默认加密算法
在postgresql.conf中配置默认密码加密算法:
ini
# PostgreSQL 10+ 配置
password_encryption = scram-sha-256
# 如果需要兼容旧版本客户端,可以使用以下配置
# password_encryption = md5版本差异
| 版本 | 默认加密算法 | 支持的加密算法 |
|---|---|---|
| 9.6及以下 | md5 | md5 |
| 10-13 | md5 | md5, scram-sha-256 |
| 14+ | scram-sha-256 | md5, scram-sha-256 |
密码复杂度要求
PostgreSQL本身没有内置的密码复杂度检查机制,但可以通过以下方式实现:
使用check_password_policy扩展
从PostgreSQL 13开始,提供了check_password_policy扩展用于密码复杂度检查:
sql
-- 安装扩展
CREATE EXTENSION IF NOT EXISTS check_password_policy;
-- 配置密码复杂度
ALTER SYSTEM SET password_policy = 'strong';
ALTER SYSTEM SET password_policy_min_length = 12;
ALTER SYSTEM SET password_policy_min_digits = 2;
ALTER SYSTEM SET password_policy_min_uppercase = 2;
ALTER SYSTEM SET password_policy_min_lowercase = 2;
ALTER SYSTEM SET password_policy_min_special = 1;
-- 重载配置
SELECT pg_reload_conf();使用pg_hba.conf限制
通过pg_hba.conf可以限制连接时的密码验证方式:
# 要求使用scram-sha-256加密
local all all scram-sha-256
host all all 0.0.0.0/0 scram-sha-256
hostssl all all ::/0 scram-sha-256使用外部认证机制
结合PAM、LDAP等外部认证机制实现更强的密码复杂度要求:
# 使用PAM进行密码验证
host all all 0.0.0.0/0 pam pamservice=postgresql密码过期策略
使用password_validation扩展
从PostgreSQL 10开始,可以使用password_validation扩展实现密码过期:
sql
-- 安装扩展
CREATE EXTENSION IF NOT EXISTS password_validation;
-- 设置密码有效期为90天
ALTER ROLE username VALID UNTIL '2025-12-31';
-- 检查用户密码有效期
SELECT usename, valuntil FROM pg_user WHERE valuntil IS NOT NULL;使用自定义函数
创建自定义函数定期检查和提醒密码过期:
sql
CREATE OR REPLACE FUNCTION check_password_expiry()
RETURNS void AS $$
DECLARE
r RECORD;
BEGIN
FOR r IN SELECT usename, valuntil FROM pg_user WHERE valuntil IS NOT NULL AND valuntil < CURRENT_DATE + INTERVAL '7 days' LOOP
RAISE NOTICE 'User % password will expire on %', r.usename, r.valuntil;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- 定期执行检查
SELECT check_password_expiry();密码历史记录
使用pgcrypto扩展
结合pgcrypto扩展实现密码历史记录:
sql
-- 安装扩展
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- 创建密码历史表
CREATE TABLE password_history (
username text NOT NULL,
password_hash text NOT NULL,
change_date timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (username, change_date)
);
-- 创建密码变更触发器
CREATE OR REPLACE FUNCTION record_password_change()
RETURNS trigger AS $$
BEGIN
INSERT INTO password_history (username, password_hash)
VALUES (NEW.usename, NEW.passwd);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER password_change_trigger
AFTER UPDATE ON pg_authid
FOR EACH ROW
WHEN (OLD.passwd IS DISTINCT FROM NEW.passwd)
EXECUTE FUNCTION record_password_change();限制重复使用密码
创建函数检查新密码是否在历史记录中:
sql
CREATE OR REPLACE FUNCTION check_password_reuse(username text, new_password text)
RETURNS boolean AS $$
DECLARE
history_count integer;
BEGIN
-- 检查新密码是否与最近3次密码相同
SELECT COUNT(*) INTO history_count
FROM password_history
WHERE username = $1
ORDER BY change_date DESC
LIMIT 3;
-- 实现密码匹配逻辑(需要根据实际加密方式调整)
RETURN history_count < 3;
END;
$$ LANGUAGE plpgsql;账户锁定机制
使用pg_fail2ban
通过pg_fail2ban扩展实现失败登录尝试的账户锁定:
sql
-- 安装扩展
CREATE EXTENSION IF NOT EXISTS pg_fail2ban;
-- 配置参数
ALTER SYSTEM SET pg_fail2ban.max_tries = 5;
ALTER SYSTEM SET pg_fail2ban.ban_time = 3600; -- 锁定1小时
ALTER SYSTEM SET pg_fail2ban.unban_time = 86400; -- 24小时后自动解锁
-- 重载配置
SELECT pg_reload_conf();使用pam_tally2
通过PAM的pam_tally2模块实现账户锁定:
bash
# /etc/pam.d/postgresql
auth required pam_tally2.so onerr=fail deny=5 unlock_time=3600
account required pam_tally2.so最佳实践
生产环境建议
- 使用强加密算法:在PostgreSQL 14+中使用默认的
scram-sha-256,10-13版本手动配置 - 实施密码复杂度要求:结合
check_password_policy扩展或外部认证机制 - 设置合理的密码有效期:根据业务需求设置90-180天的密码有效期
- 维护密码历史记录:限制用户重复使用最近3-5次的密码
- 配置账户锁定:对失败登录尝试进行限制,防止暴力破解
- 定期审计密码策略:检查用户密码是否符合要求,及时提醒过期密码
- 使用角色继承:通过角色继承管理权限,减少直接修改超级用户密码的需求
监控与审计
- 监控密码过期:定期检查
pg_user视图中的valuntil字段 - 审计密码变更:通过
password_history表记录所有密码变更 - 监控登录失败:通过PostgreSQL日志或
pg_fail2ban监控失败登录尝试 - 定期安全扫描:使用工具如
pgAudit或第三方安全扫描工具检查密码策略执行情况
常见问题与解决方案
问题:无法使用旧版本客户端连接
解决方案:
临时将加密算法切换回md5:
inipassword_encryption = md5为特定用户设置md5加密:
sqlALTER USER username PASSWORD 'md5_hash';升级客户端至支持scram-sha-256的版本
问题:忘记超级用户密码
解决方案:
以单用户模式启动PostgreSQL:
bashpg_ctl stop postgres --single -D /var/lib/postgresql/data重置密码:
sqlALTER USER postgres PASSWORD 'new_password';重启PostgreSQL服务:
bashpg_ctl start
问题:密码策略配置不生效
解决方案:
检查扩展是否正确安装:
sqlSELECT * FROM pg_extension WHERE extname = 'check_password_policy';检查配置参数是否正确设置:
sqlSHOW password_policy;确保配置已重载:
sqlSELECT pg_reload_conf();检查日志文件中是否有相关错误信息
总结
PostgreSQL密码策略是数据库安全的重要组成部分,通过合理配置密码加密方式、复杂度要求、过期策略、历史记录和账户锁定机制,可以有效提高数据库的安全性。DBA应根据业务需求和合规要求,选择适合的密码策略方案,并定期进行审计和监控,确保密码策略的有效执行。
