生产中我们不同用户通常有不同的策略,例如应用连接用户我们希望密码永不过期,维护用户为了安全要几个月修订一次,大家知道oracle非常强大,这些功能都能在oracle中实现。但是过程往往觉得很麻烦,如密码策略如何自建,profile格式等问题。其实oracle 自带的脚本中已经给我写好了密码校验策略。
本案就教大家最简洁的如何限定oracle用户密码复杂度,账户过期策略,密码过期策略以及针对不同用户设置不同的策略。
脚本位于$ORACLE_HOME/rdbms/admin/utlpwdmg.sql 中,我们只要修改部分语句就可以建立自己的密码策略。
数据库版本11.2.0.3
脚本如下,基本包含密码的各种策略,可以根据自己的要去自己修改。
CREATE OR REPLACE FUNCTION verify_function
(username varchar2,
password varchar2,
old_password varchar2)
RETURN boolean IS
n boolean;
m integer;
differ integer;
isdigit boolean;
ischar boolean;
ispunct boolean;
db_name varchar2(40);
digitarray varchar2(20);
punctarray varchar2(25);
chararray varchar2(52);
i_char varchar2(10);
simple_password varchar2(10);
reverse_user varchar2(32);
BEGIN
digitarray:= '0123456789';
chararray:= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-- 校验密码长度至少为8位
IF length(password) < 8 THEN
raise_application_error(-20001, 'Password length less than 8');
END IF;
-- 校验密码是否和用户名相同
IF NLS_LOWER(password) = NLS_LOWER(username) THEN
raise_application_error(-20002, 'Password same as or similar to user');
END IF;
FOR i IN 1..100 LOOP
i_char := to_char(i);
if NLS_LOWER(username)|| i_char = NLS_LOWER(password) THEN
raise_application_error(-20005, 'Password same as or similar to user name ');
END IF;
END LOOP;
-- 校验密码是不是用户名的反序
FOR i in REVERSE 1..length(username) LOOP
reverse_user := reverse_user || substr(username, i, 1);
END LOOP;
IF NLS_LOWER(password) = NLS_LOWER(reverse_user) THEN
raise_application_error(-20003, 'Password same as username reversed');
END IF;
-- 校验密码是否是服务名
select name into db_name from sys.v$database;
if NLS_LOWER(db_name) = NLS_LOWER(password) THEN
raise_application_error(-20004, 'Password same as or similar to server name');
END IF;
FOR i IN 1..100 LOOP
i_char := to_char(i);
if NLS_LOWER(db_name)|| i_char = NLS_LOWER(password) THEN
raise_application_error(-20005, 'Password same as or similar to server name ');
END IF;
END LOOP;
-- 检查用户密码是否过于简单,
-- 检查密码是否有列表中的关键字
-- 是否存在弱口令
IF NLS_LOWER(password) IN ('welcome1', 'database1', 'account1', 'user1234', 'password1', 'oracle123', 'computer1', 'abcdefg1', 'change_on_install') THEN
raise_application_error(-20006, 'Password too simple');
END IF;
-- 检查密码是否为oracle
simple_password := 'oracle';
FOR i IN 1..100 LOOP
i_char := to_char(i);
if simple_password || i_char = NLS_LOWER(password) THEN
raise_application_error(-20007, 'Password too simple ');
END IF;
END LOOP;
-- 检验密码至少包含至少一个字母,一个数字
-- 1. 校验数字
isdigit:=FALSE;
m := length(password);
FOR i IN 1..10 LOOP
FOR j IN 1..m LOOP
IF substr(password,j,1) = substr(digitarray,i,1) THEN
isdigit:=TRUE;
GOTO findchar;
END IF;
END LOOP;
END LOOP;
IF isdigit = FALSE THEN
raise_application_error(-20008, 'Password must contain at least one digit, one character');
END IF;
-- 2. 检验字符
<<findchar>>
ischar:=FALSE;
FOR i IN 1..length(chararray) LOOP
FOR j IN 1..m LOOP
IF substr(password,j,1) = substr(chararray,i,1) THEN
ischar:=TRUE;
GOTO endsearch;
END IF;
END LOOP;
END LOOP;
IF ischar = FALSE THEN
raise_application_error(-20009, 'Password must contain at least one \
digit, and one character');
END IF;
<<endsearch>>
-- 检验密码和上一个密码至少有三个不同字符
--
IF old_password IS NOT NULL THEN
differ := length(old_password) - length(password);
differ := abs(differ);
IF differ < 3 THEN
IF length(password) < length(old_password) THEN
m := length(password);
ELSE
m := length(old_password);
END IF;
FOR i IN 1..m LOOP
IF substr(password,i,1) != substr(old_password,i,1) THEN
differ := differ + 1;
END IF;
END LOOP;
IF differ < 3 THEN
raise_application_error(-20011, 'Password should differ from the \
old password by at least 3 characters');
END IF;
END IF;
END IF;
-- Everything is fine; return TRUE ;
RETURN(TRUE);
END;
/
原有的脚本会将默认的profile进行修改,修改后将对所有用户生效,脚本如下
ALTER PROFILE DEFAULT LIMIT
PASSWORD_LIFE_TIME 180
PASSWORD_GRACE_TIME 7
PASSWORD_REUSE_TIME UNLIMITED
PASSWORD_REUSE_MAX UNLIMITED
FAILED_LOGIN_ATTEMPTS 10
PASSWORD_LOCK_TIME 1
PASSWORD_VERIFY_FUNCTION verify_function_11G;
我们不希望对所有用户生效,进行适当修改,创建自己的profile:
CREATE PROFILE safe_control LIMIT
PASSWORD_LIFE_TIME 120
PASSWORD_GRACE_TIME 7
PASSWORD_REUSE_TIME UNLIMITED
PASSWORD_REUSE_MAX UNLIMITED
FAILED_LOGIN_ATTEMPTS 10
PASSWORD_LOCK_TIME 1
PASSWORD_VERIFY_FUNCTION verify_function;
将脚本保存为safe_11g.sql 在服务器下执行脚本
SQL> @/home/oracle/files/safe_11g.sql
Function created.
Profile created.
SQL> create user u01 identified by u01 profile SAFE_CONTROL;
create user u01 identified by u01 profile SAFE_CONTROL
*
ERROR at line 1:
ORA-28003: password verification for the specified password failed
ORA-20001: Password length less than 8
SQL>
可以看到加上profile以后新建用户无法成功,当然我们也可以先建立用户然后,让用户使用profile。
SQL> create user u01 identified by u01;
User created.
SQL> alter user u01 profile safe_control;
User altered.
在用户过期后将修改密码将会根据我们profile要求的来进行修改
这里我们的profile里各个参数可以参见下表
参数名称 |
说明 |
默认值 |
建议值 |
PASSWORD_LIFE_TIME |
账户修改时间 |
180天 |
120天 |
PASSWORD_LOCK_TIME |
账户锁定时间 |
1天 |
30分钟 |
PASSWORD_REUSE_MAX |
最大可用次数 |
Unlimited |
Unlimited |
PASSWORD_REUSE_TIME |
多久后可以重用密码 |
Unlimited |
Unlimited |
PASSWORD_GRACE_TIME |
延期天数 |
7 |
7 |
FAILED_LOGIN_ATTEMPTS |
登录失败次数 |
10 |
10 |
PASSWORD_VERIFY_FUNCTION |
密码校验方法 |
Null |
verify_function |
根据以上的参数,我们基本可以修改部分参数快速建立自己的密码函数,建立自己的profile,让不同用户使用不同的profile。让一切变得超简单。