
本文共 5360 字,大约阅读时间需要 17 分钟。
通过调用函数的方式增强用户密码的安全性
一般来说数据库密码安全管理要考虑以下几个方面 :
1. 密码过期策略, 决定密码的有效期, 多长时间过期.
2. 密码复用策略, 密码修改时需要对比以前的密码, 多少次以后才可以复用, 或者永不能使用与以前密码相同的密码.
3. 密码长度策略, 密码的最小长度, 太短的话很容易被穷举法破解, 一般至少使用8位以上长度的密码.
4. 密码复杂度策略, 密码包含的字符复杂度, 一般要求包含数字字母大小写以及特殊字符. 另外不要使用与数据库名, 用户名相似或一致的密码.
5. 密码字典过滤, 过滤掉一些用户常用的或者有意义的字符, 也是为了避免密码很容易被穷举破解.
6. 密码存储策略, 使用加密存储, 不要使用明文存储.
加密存储在创建用户时使用encrypted password即可.
如果设置了password_encryption=off, 同时创建用户时不加encrypted, 那么密码将以明文存储.
加密存储方法 :
highgo=# create role u1 login encrypted password 'highgo';
CREATE ROLE
highgo=# select * from pg_shadow where usename='u1';
usename | usesysid | usecreatedb | usesuper | userepl | usebypassrls | passwd | v
aluntil | useconfig
---------+----------+-------------+----------+---------+--------------+-------------------------------------+--
--------+-----------
u1 | 131294 | f | f | f | f | md50a0a7a2ef5607a4424f00e4903877f2e |
|
(1 row)
7. 密码锁策略, 密码输入错误多少次后锁用户, 多长时间解锁.
HighgoDB不支持密码锁策略.
8. 密码保护策略, 密码输入错误多少次后延迟认证. 可用来防止暴力破解.
目前HighgoDB在密码管理这块做得较弱, 以下举例通过函数来实现其中的部分安全策略 :
创建一个字典表, 用于存放已经使用过的密码的md5值, 以及用来进行暴力破解的密码字典的md5值.
highgo=# create table pwd_dictionary(pwd text unique);
CREATE TABLE
创建一个记录用户最后一次修改密码时间的表. 用于实施密码过期提醒策略.
highgo=# create table user_pwd(rolename name not null unique, pwd_modify_time timestamp not null);
CREATE TABLE
创建用户的函数 :
highgo=# 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
创建用户密码过短, 不允许创建.
highgo=# select * from create_role('u4','pwd');
NOTICE: password too short, please use password long than 8.
create_role
-------------
(1 row)
创建用户密码过于简单, 不允许创建.
highgo=# 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)
创建用户正常.
highgo=# select * from create_role('u4','aA0ffffffff');
NOTICE: create role u4 successed.
create_role
-------------
(1 row)
创建用户密码与现有密码重复, 不允许创建.
highgo=# 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
修改用户密码的函数 :
highgo=# 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
使用该函数修改用户密码
highgo=# select * from alter_role_pwd('u4','new');
NOTICE: password too short, please use password long than 8.
alter_role_pwd
----------------
(1 row)
highgo=# 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)
highgo=# 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)
highgo=# select * from alter_role_pwd('u4','new2222222z2A');
NOTICE: modify role u4 password successed.
alter_role_pwd
----------------
(1 row)
highgo=# 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监控软件中实施密码过期提醒.
highgo=# select * from user_pwd ;
rolename | pwd_modify_time
----------+----------------------------
u4 | 2013-05-25 18:21:59.376404
(1 row)
[小结]
1. 为了密码安全性, 在HighgoDB中, 创建用户请使用create_role函数, 不要直接使用create role 命令.
2. 修改用户密码请使用alter_role_pwd函数. 不要直接使用alter role 命令.
登陆【瀚高技术支持平台】,查看更多资料
发表评论
最新留言
关于作者
