PostgreSQL password security

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介:
请参见
PostgreSQL 密码安全
如何防止暴力破解, 如何强制密码复杂度策略, 如何制定密码更换周期
如何防止密码在网络传输时被截获, 如何防止密码被超级用户获取
如何防止密码被审计服务器或日志服务器截获
如何防止密码在pg_stat_statements插件中或SAVE的文件中泄露
通过修改源码限制密码最小长度

一般来说数据库密码安全管理要考虑以下几个方面 : 
1. 密码过期策略, 决定密码的有效期, 多长时间过期. 
PostgreSQL 不支持密码过期策略, 但是可以通过其他方式来实现过期提醒.
2. 密码复用策略, 密码修改时需要对比以前的密码, 多少次以后才可以复用, 或者永不能使用与以前密码相同的密码.
PostgreSQL 不支持密码复用策略, 但是可以通过其他方式来实现强制密码复用策略.
3. 密码长度策略, 密码的最小长度, 太短的话很容易被穷举法破解, 一般至少使用8位以上长度的密码.
PostgreSQL 不支持密码长度策略, 但是可以通过其他方式来实现强制密码长度策略.
4. 密码复杂度策略, 密码包含的字符复杂度, 一般要求包含数字字母大小写以及特殊字符. 另外不要使用与数据库名, 用户名相似或一致的密码.
PostgreSQL 不支持密码复杂度策略, 但是可以通过其他方式来实现强制密码复杂度策略.
5. 密码字典过滤, 过滤掉一些用户常用的或者有意义的字符, 也是为了避免密码很容易被穷举破解. 
PostgreSQL 不支持密码字典过滤策略, 但是可以通过其他方式来实现强制字典过滤策略.
6. 密码存储策略, 使用加密存储, 不要使用明文存储. 
加密存储在创建用户时使用encrypted password即可. 
如果设置了password_encryption=off, 同时创建用户时不加encrypted, 那么密码将以明文存储.
例如 : 
加密存储 :
digoal=# create role u1 login encrypted password 'digoal';
CREATE ROLE
digoal=# select * from pg_shadow where usename='u1';
 usename | usesysid | usecreatedb | usesuper | usecatupd | userepl |               passwd                | valuntil | useconfig 
---------+----------+-------------+----------+-----------+---------+-------------------------------------+----------+-----------
 u1      |    26383 | f           | f        | f         | f       | md5bdf22a6622939c7c7ab2377eaca514d5 |          | 
(1 row)

明文存储 :
7. 密码锁策略, 密码输入错误多少次后锁用户, 多长时间解锁.
PostgreSQL 不支持密码锁策略.
8. 密码保护策略, 密码输入错误多少次后延迟认证. 可用来防止暴力破解.
PostgreSQL 不支持密码保护策略.

目前PostgreSQL在密码管理这块做得较弱, 
以下举例通过函数来实现其中的部分安全策略 : 
创建一个字典表, 用于存放已经使用过的密码的md5值, 以及用来进行暴力破解的密码字典的md5值.
digoal=# create table pwd_dictionary(pwd text unique);
CREATE TABLE

创建一个记录用户最后一次修改密码时间的表. 用于实施密码过期提醒策略.
digoal=# create table user_pwd(rolename name not null unique, pwd_modify_time timestamp not null);
CREATE TABLE

创建用户的函数 : 
digoal=# create or replace function create_role(i_rolename name, i_pwd text) returns void as $$
declare
  v_length int := 8;
begin
  -- 密码长度策略
  if length(i_pwd) < v_length then
    raise notice 'password too short, please use password long than %.', v_length;
    return;
  end if;
  -- 密码复杂度策略, 包含数字, 字母大小写.
  if not(i_pwd ~ '[a-z]' and i_pwd ~ '[A-Z]' and i_pwd ~ '[0-9]') then
    raise notice 'password too simple, please ensure password contain a-z,A-Z and 0-9.';
    return;
  end if;
  -- 密码复用策略, 不允许重复使用已经存在的密码.
  -- 密码字典策略, 不允许使用密码字典中的密码.
  insert into pwd_dictionary(pwd) values (md5(i_pwd));
  -- 插入用户表, 记录用户最后一次修改密码的时间, 用于密码过期策略
  insert into user_pwd(rolename, pwd_modify_time) values (i_rolename, now());
  -- 创建用户
  execute 'create role '||i_rolename||' encrypted password '||quote_literal(i_pwd);
  raise notice 'create role % successed.', i_rolename;
  return;
end;
$$ language plpgsql strict;
CREATE FUNCTION

创建用户密码过短, 不允许创建.
digoal=# select * from create_role('u4','pwd');
NOTICE:  password too short, please use password long than 8.
 create_role 
-------------
 
(1 row)

创建用户密码过于简单, 不允许创建.
digoal=# select * from create_role('u4','abcdefee');
NOTICE:  password too simple, please ensure password contain a-z,A-Z and 0-9.
 create_role 
-------------
 
(1 row)

创建用户正常.
digoal=# select * from create_role('u4','aA0ffffffff');
NOTICE:  create role u4 successed.
 create_role 
-------------
 
(1 row)

创建用户密码与现有密码重复, 不允许创建.
digoal=# select * from create_role('new','aA0ffffffff');
ERROR:  duplicate key value violates unique constraint "pwd_dictionary_pwd_key"
DETAIL:  Key (pwd)=(2b9aa88182d13d35930180b4cc791beb) already exists.
CONTEXT:  SQL statement "insert into pwd_dictionary(pwd) values (md5(i_pwd))"
PL/pgSQL function create_role(name,text) line 17 at SQL statement


修改用户密码的函数 : 
digoal=# create or replace function alter_role_pwd(i_rolename name, i_pwd text) returns void as $$
declare
  v_length int := 8;
begin
  -- 密码长度策略
  if length(i_pwd) < v_length then
    raise notice 'password too short, please use password long than %.', v_length;
    return;
  end if;
  -- 密码复杂度策略, 包含数字, 字母大小写.
  if not(i_pwd ~ '[a-z]' and i_pwd ~ '[A-Z]' and i_pwd ~ '[0-9]') then
    raise notice 'password too simple, please ensure password contain a-z,A-Z and 0-9.';
    return;
  end if;
  -- 密码复用策略, 不允许重复使用已经存在的密码.
  -- 密码字典策略, 不允许使用密码字典中的密码.
  insert into pwd_dictionary(pwd) values (md5(i_pwd));
  -- 更新用户表, 记录用户最后一次修改密码的时间, 用于密码过期策略
  update user_pwd set pwd_modify_time=now() where rolename=i_rolename;
  -- 修改用户密码
  execute 'alter role '||i_rolename||' encrypted password '||quote_literal(i_pwd);
  raise notice 'modify role % password successed.', i_rolename;
  return;
end;
$$ language plpgsql strict;
CREATE FUNCTION

使用该函数修改用户密码
digoal=# select * from alter_role_pwd('u4','new');
NOTICE:  password too short, please use password long than 8.
 alter_role_pwd 
----------------
 
(1 row)
digoal=# select * from alter_role_pwd('u4','new22222222');
NOTICE:  password too simple, please ensure password contain a-z,A-Z and 0-9.
 alter_role_pwd 
----------------
 
(1 row)
digoal=# select * from alter_role_pwd('u4','new2222222z2');
NOTICE:  password too simple, please ensure password contain a-z,A-Z and 0-9.
 alter_role_pwd 
----------------
 
(1 row)
digoal=# select * from alter_role_pwd('u4','new2222222z2A');
NOTICE:  modify role u4 password successed.
 alter_role_pwd 
----------------
 
(1 row)
digoal=# select * from alter_role_pwd('u4','new2222222z2A');
ERROR:  duplicate key value violates unique constraint "pwd_dictionary_pwd_key"
DETAIL:  Key (pwd)=(9a5c46207db775d4d98e64d427481cbc) already exists.
CONTEXT:  SQL statement "insert into pwd_dictionary(pwd) values (md5(i_pwd))"
PL/pgSQL function alter_role_pwd(name,text) line 17 at SQL statement

密码过期提醒 : 
因为密码最后一次修改时间已经更新到user_pwd表, 所以结合这个可以在系统crontab中或者nagios监控软件中实施密码过期提醒.
digoal=# select * from user_pwd ;
 rolename |      pwd_modify_time       
----------+----------------------------
 u4      | 2013-05-25 18:21:59.376404
(1 row)


[小结]
1. 为了密码安全性, 在PostgreSQL 中, 创建用户请使用create_role函数, 不要直接使用create role 命令.
2. 修改用户密码请使用alter_role_pwd函数. 不要直接使用alter role 命令.
3. 密码过期提醒请结合nagios软件或者操作系统crontab来实现邮件提醒数据库管理员.
digoal=# set password_encryption=off;
SET
digoal=# create role u2 login password 'digoal';
CREATE ROLE
digoal=# select * from pg_shadow where usename='u2';
 usename | usesysid | usecreatedb | usesuper | usecatupd | userepl | passwd | valuntil | useconfig 
---------+----------+-------------+----------+-----------+---------+--------+----------+-----------
 u2      |    26387 | f           | f        | f         | f       | digoal |          | 
(1 row)

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
6月前
|
关系型数据库 MySQL Java
连接MySQL 8.0时报错caching_sha2_password解决方案
连接MySQL 8.0时报错caching_sha2_password解决方案
121 0
|
10月前
|
数据可视化 关系型数据库 MySQL
解决用软件登陆的Mysql8数据库时,报错:Authentication plugin ‘caching_sha2_password‘ cannot be loaded
解决用软件登陆的Mysql8数据库时,报错:Authentication plugin ‘caching_sha2_password‘ cannot be loaded
429 0
解决用软件登陆的Mysql8数据库时,报错:Authentication plugin ‘caching_sha2_password‘ cannot be loaded
|
10月前
|
Oracle 关系型数据库 Shell
‘show parameter ‘ for openGauss or PostgreSQL
对于oracle DBA查看数据库实例参数可以在sqlplus中使用show prameter xxx 模糊匹配非隐藏参数或已修改隐藏参数,当然也可以查询v$ 的视图, 在openGauss或postgresql当前版本中需要匹配输入参数名,当然参数名我们不可能完全记的全名,模糊搜索需要手动创建个shell方法。
146 0
|
11月前
|
关系型数据库 MySQL
MySQL 8 默认身份验证插件caching_sha2_password
默认身份验证插件caching_sha2_password
207 0
|
数据安全/隐私保护
Mysql8.0升级后,Navicat连接报错caching_sha2_password 问题
Mysql8.0升级后,Navicat连接报错caching_sha2_password 问题
84 0
|
存储 Oracle 安全
PostgreSQL user、db、schema、权限
本文探讨 PostgreSQL中的 user、db、schema、权限
6100 0
PostgreSQL user、db、schema、权限
|
关系型数据库 MySQL Windows
2059 - authentication plugin 'caching_sha2_password'” mysql8.0 Navicat for mysql 登陆错误
最近在windows服务器部署最新版mysql8.0时发现 navicat for mysql登陆不了。 根据错误提示 2059 - authentication plugin 'caching_sha2_password'” 搜索得知,原来是新版mysql8.0登陆验证改变导致的。
4731 0
|
SQL 存储 关系型数据库
|
NoSQL 数据库 数据库管理