等保测评2.0:Oracle身份鉴别(中)

2020-05-03 76176人围观 数据安全标准与合规

一、说明

本篇文章主要说一说oracle数据库中身份鉴别控制点中测评项a的相关内容和理解,关于身份鉴别的基础知识点在《等保测评2.0:Oracle身份鉴别(上)》中,请大家先阅读它。

二、测评项a

a)应对登录的用户进行身份标识和鉴别,身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换;

三、测评项a要求1

应对登录的用户进行身份标识和鉴别

oracle使用用户名对登录用户进行身份标识,这没啥好说的。oracle在身份鉴别这一块,拥有密码文件验证和操作系统验证两种方式。

密码文件验证的话,是需要登录用户输入用户名、口令的,但是操作系统验证则不需要。

对于数据库特殊账户的操作系统验证,仅由sqlnet.ora文件中的SQLNET.AUTHENTICATION_SERVICES进行控制,至于它有什么值以及代表什么意义,请大家去看上篇。

这里大家如果不想麻烦的话,其实也没有必要把SQLNET.AUTHENTICATION_SERVICES参数的值在linux和windows系统中代表的意义都搞清楚,测评的时候直接测试即可。

以centos系统为例子,也就是测评的时候先登录oracle数据库服务器的oracle账户,如果被测评方不清楚oracle账户的口令,也可以登录到root账户,然后使用“su – oracle”命令切换过去。

其实这里需要登录的是属于oinstall用户组的用户,但是一般情况下没人会去改默认配置,默认安装情况下操作系统的oracle用户会属于oinstall用户组。

登录oracle账户成功后,使用sqlplus / as sysdba命令去登录oracle数据库,这里就是使用数据库特殊账户的操作系统验证方式去验证。

如果能登录成功则说明开启了这种验证方式,不能则说明没开启。

如果开启了,那么这个要求项它就不能满足了,顶多是部分符合,因为这种方式登录数据库特殊账户不需要用户名、密码(虽然只能在本地登录,且登录的操作系统账户需要隶属于oinstall用户组),是一个比较大的安全隐患。

还有一种针对数据库普通账户的操作系统验证方式,这种验证方式对于登录的操作系统账户没有啥要求。

先去查看remote_os_authent和os_authent_prefix参数,它们的默认值分别是FALSE和ops$。

如果remote_os_authent是FALSE,那么是否开启这种验证方式还是由SQLNET.AUTHENTICATION_SERVICES决定。

如果开启了,假定os_authent_prefix的值是ops$,假定操作系统中存在一个cv的账户。

那么只要oracle数据库中建立一个名为ops$cv的账户并给与基础权限(连接权限等),用户在登录操作系统中的cv后,可以直接使用sqlplus /或sqlplus / as normal(两个命令是一个意思),以普通账户的身份登录ops$cv账户(当然这里需在cv账户的环境变量里配置一下好方便的使用sqlplus命令)。

同样的,如果开启了这种验证方式,那么也就顶多是部分符合了。

如果remote_os_authent为TRUE,那不用看了,数据库普通账户的操作系统验证方式肯定开启了,并且数据库普通账户的远程操作系统验证方式也开启了。

还是用上面的数据举例子,假定os_authent_prefix的值是ops$,假定远程终端存在一个cv的操作系统账户,那么在远程终端那也可以用空用户名、空口令的方式登录ops$cv账户,更不安全了。

至于空口令,在oracle中似乎不能设置空口令,我反正没有尝试成功……

四、测评项a要求2

身份标识具有唯一性

即用户名不会重复,oracle自动实现,默认符合。

五、测评项a要求3

身份鉴别信息具有复杂度要求

这个要从两个方面看,我个人觉得两个方面都符合才能算达到要求。

第一个方面即实际的口令是否具有一定的复杂度,也即口令至少8位,且包含大写字母、小写字母、数字、特殊字符这四类字符种的三种,且口令不包含简单排列规律,如admin!@#123此类弱口令。

第二个方面就是在oracle中是否设置了口令复杂度策略,这里要看的就是配置表中的PASSWORD_VERIFY_FUNCTION字段的值:

select * from dba_profiles;

这里插一句嘴,说一说配置表的规则,用户是可以自定义多个配置给不同的用户使用。

比如这里的PASSWORD_VERIFY_FUNCTION的Profile字段值为Default,某用户要使用Default的相关配置,就要设置DBA_USERS表中的Profile字段值为Default。

默认情况下,用户使用的都是Default:

select username,profile from DBA_USERS

好,咱们说一说PASSWORD_VERIFY_FUNCTION字段是什么意思,该字段的值应该为oracle中某函数对象的名字,当创建、更改用户口令时会调用到该函数对口令进行校验,默认情况下这里的值是null,也即不使用任何函数对口令进行校验。

在初级教材中,让我们去查看utlpwdmg.sql中的相关信息,其实是不准确的。

因为utlpwdmg.sql并不是函数本身,它只是创建函数的一段语句而已。

实际上在oracle11g中,运行utlpwdmg.sql会创建两个函数,一个是新版本的口令校验函数,一个是老版本的,在里面还会对配置表进行修改,让PASSWORD_VERIFY_FUNCTION的值为新版本的口令校验函数的名字。

这个是utlpwdmg.sql文件中新版本的口令校验函数FUNCTION verify_function_11G的定义语句:

CREATE OR REPLACE FUNCTION verify_function_11G
(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';

   -- Check for the minimum length of the password
   IF length(password) < 8 THEN
      raise_application_error(-20001, 'Password length less than 8');
   END IF;


   -- Check if the password is same as the username or username(1-100)
   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;

   -- Check if the password is same as the username reversed
   
   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;

   -- Check if the password is the same as server name and or servername(1-100)
   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;

   -- Check if the password is too simple. A dictionary of words may be
   -- maintained and a check may be made so as not to allow the words
   -- that are too simple for the password.
   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;

   -- Check if the password is the same as oracle (1-100)
    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;

   -- Check if the password contains at least one letter, one digit 
   -- 1. Check for the digit
   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. Check for the character
   <<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>>
   -- Check if the password differs from the previous password by at least
   -- 3 letters
   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;
/

然后在这里,对配置文件进行了修改,设置PASSWORD_VERIFY_FUNCTION的值为verify_function_11G:

-- This script alters the default parameters for Password Management
-- This means that all the users on the system have Password Management
-- enabled and set to the following values unless another profile is 
-- created with parameter values set to different value or UNLIMITED 
-- is created and assigned to the user.

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;

这个是老版本的校验函数FUNCTION verify_function的定义语句:

-- Below is the older version of the script

-- This script sets the default password resource parameters
-- This script needs to be run to enable the password features.
-- However the default resource parameters can be changed based 
-- on the need.
-- A default password complexity function is also provided.
-- This function makes the minimum complexity checks like
-- the minimum length of the password, password not same as the
-- username, etc. The user may enhance this function according to
-- the need.
-- This function must be created in SYS schema.
-- connect sys/<password> as sysdba before running the script

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;
   digitarray varchar2(20);
   punctarray varchar2(25);
   chararray varchar2(52);

BEGIN 
   digitarray:= '0123456789';
   chararray:= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
   punctarray:='!"#$%&()``*+,-/:;<=>?_';

   -- Check if the password is same as the username
   IF NLS_LOWER(password) = NLS_LOWER(username) THEN
     raise_application_error(-20001, 'Password same as or similar to user');
   END IF;

   -- Check for the minimum length of the password
   IF length(password) < 4 THEN
      raise_application_error(-20002, 'Password length less than 4');
   END IF;

   -- Check if the password is too simple. A dictionary of words may be
   -- maintained and a check may be made so as not to allow the words
   -- that are too simple for the password.
   IF NLS_LOWER(password) IN ('welcome', 'database', 'account', 'user', 'password', 'oracle', 'computer', 'abcd') THEN
      raise_application_error(-20002, 'Password too simple');
   END IF;

   -- Check if the password contains at least one letter, one digit and one
   -- punctuation mark.
   -- 1. Check for the digit
   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(-20003, 'Password should contain at least one digit, one character and one punctuation');
   END IF;
   -- 2. Check for the character
   <<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 findpunct;
         END IF;
      END LOOP;
   END LOOP;
   IF ischar = FALSE THEN
      raise_application_error(-20003, 'Password should contain at least one \
              digit, one character and one punctuation');
   END IF;
   -- 3. Check for the punctuation
   <<findpunct>>
   ispunct:=FALSE;
   FOR i IN 1..length(punctarray) LOOP 
      FOR j IN 1..m LOOP 
         IF substr(password,j,1) = substr(punctarray,i,1) THEN
            ispunct:=TRUE;
             GOTO endsearch;
         END IF;
      END LOOP;
   END LOOP;
   IF ispunct = FALSE THEN
      raise_application_error(-20003, 'Password should contain at least one \
              digit, one character and one punctuation');
   END IF;

   <<endsearch>>
   -- Check if the password differs from the previous password by at least
   -- 3 letters
   IF old_password IS NOT NULL THEN
     differ := length(old_password) - length(password);

     IF abs(differ) < 3 THEN
       IF length(password) < length(old_password) THEN
         m := length(password);
       ELSE
         m := length(old_password);
       END IF;

       differ := abs(differ);
       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(-20004, 'Password should differ by at \
         least 3 characters');
       END IF;
     END IF;
   END IF;
   -- Everything is fine; return TRUE ;   
   RETURN(TRUE);
END;
/

所以,实际上想要知道现在实际使用的校验函数的内容,就应该直接在数据库中查看校验函数的内容,而不是去查看utlpwdmg.sql文件。

在这里,使用的是verify_function_11G,由于其内容我没有修改过,所以和utlpwdmg.sql中所定义的是一样的:

至于其中的内容嘛,注释写得很清楚的,我就从上到下大概说明下:

检查口令的最小长度,如果小于8就返回错误,所以口令的最小长度是9

 -- Check for the minimum length of the password
   IF length(password) < 8 THEN
      raise_application_error(-20001, 'Password length less than 8');
   END IF;

检查被创建或被更改口令的账户的用户名是否和新的口令一样,如果一样返回错误

检查新的口令是是否等于用户名后面加上1到100的数字,比如用户名时user,那么口令如果是user0到user100中的任何一个,也会返回错误。

  -- Check if the password is same as the username or username(1-100)
   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;

这里是检查口令是否等于倒序的用户名,或者与其相似,比如用户名是user,则口令不能是r、re、res、resu中的任何一个

   -- Check if the password is same as the username reversed
   
   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;

这里检查口令是否和数据库名相等,以及是否和数据库名0到数据库名100相等。

我这里是默认的数据库名:ORCL

  -- Check if the password is the same as server name and or servername(1-100)
   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;

检查口令是否是一些简单的单词,只不过这里只是一个示例而已,用户可以根据需要多添加一些弱口令。

   -- Check if the password is too simple. A dictionary of words may be
   -- maintained and a check may be made so as not to allow the words
   -- that are too simple for the password.
   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;

检查口令是否是oracle1到oracle100中的一个,不过这里口令可以等于oracle,不知道为啥这里是否等于oracle的校验

   -- Check if the password is the same as oracle (1-100)
    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;

检查口令是否包含至少一个数字和一个字母(同时包含才可以通过校验)

由于这里字母数组的定义是:chararray:= ‘abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;

所以指的是至少一个大写或小写字母。

  -- Check if the password contains at least one letter, one digit 
   -- 1. Check for the digit
   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. Check for the character
   <<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;

检查口令和旧口令的相似程度:

假设新口令是user,旧口令是admin

新口令长度和旧口令长度的差值大于等于3的话,直接通过校验。

这里的差值是1,所以需要进行校验。

循环的次数为长度小的那一边的口令的长度,也就是user字符串的长度4。

顺序取字符串来对比:

u不等于a,differ的值加1,为1

s不等于d,differ加1,为2

最后循环4次结束,differ为4,

如果最后differ小于3,则未通过校验,大于等3,则通过校验。

 -- Check if the password differs from the previous password by at least
   -- 3 letters
   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;

最后,如果通过了所有的校验(中途没有返回错误),就直接返回true:

 -- Everything is fine; return TRUE ;   
   RETURN(TRUE);

从整个默认的新版的校验函数看来,主要就是口令长度不低于9位,需要同时包含数字、字母(大小写皆可),感觉稍微差了那么一点。

理论上比较好的应该是口令长度不低于8位(这里是9位当然更好了),同时包含数字、大写字母、小写字母、特殊字符其中的3种字符。

另外,不知道为什么,SYS账户的口令的更改,不受到这个校验函数的限制。

登录SYS按道理来说使用的是密码文件或操作系统的验证,所以不知道在USER$中SYS账户的PASSWORD字段的值有什么用,虽然也会跟着口令的更改而更改就是了。

六、测评项a要求4

并定期更换

一方面查看实际的更换时间:

select name,PTIME from USER$

另一方面查看相关的策略,先看和口令过期直接相关的两个参数:

PASSWORD_LIFE_TIME和PASSWORD_GRACE_TIME

这里的时间单位是天,我这里自己修改过,默认情况下PASSWORD_LIFE_TIME的值是180,PASSWORD_GRACE_TIME的值是7。

PASSWORD_LIFE_TIME代表口令过期时间,而PASSWORD_GRACE_TIME则代表口令过期后的宽恕时间。

口令过期但还未超过宽恕期时,登录时会提醒你口令在多久后过期(这里的过期是指超过宽恕期),询问你是否修改口令,可以不修改,然后正常登录账户。

但是超过宽恕期再登录,就无法登录上去了。

oracle在这里的逻辑是这样的,需要通过用户的登录来改变用户的状态。

举个例子,假如PASSWORD_LIFE_TIME的值是1,PASSWORD_GRACE_TIME的值是也是1。

我在2020年4月7日10点整,创建了一个账户,在DBA_USERS表中,该账户的CREATED(创建时间)就是2020年4月7日10点,ACCOUNT_STATUS(账户状态)是OPEN,在USER$表中该账户的PTIME(口令修改时间)也是2020年4月7日10点整。

在DBA_USERS表中,该账户的EXPIRY_DATE是PTIME+PASSWORD_LIFE_TIME的值,也就是2020年4月8日10点整。

(注意,在USER$表中也有一个EXPTIME字段,但是好像这个字段有时候不是实时的,需要用户的登录才会更新,比如现在,该字段就是一个空字符串)

那么,在到达2020年4月8日10点整后,这个账户的ACCOUNT_STATUS是不会自动变成EXPIRED(GRACE)(口令过期但还处于宽恕期内),只要你不登录这个账户,那么该账户会一直处于OPEN状态。哪怕是过了两天,也就是超过PASSWORD_LIFE_TIME+PASSWORD_GRACE_TIME的值,仍然是OPEN状态。

在2020年4月8日10点整后,登录该账户,会更新账户的ACCOUNT_STATUS,更新成EXPIRED(GRACE),而EXPIRY_DATE也会更新,更新为登录时间点+PASSWORD_GRACE_TIME的值。

同样的,如果在这之后一直不登录账户,则超过宽恕期后,账户的状态还是EXPIRED(GRACE),只有等你尝试登录这个账户时,才会更新状态值为EXPIRED,当然这个时候你也登录不上了。

所以根据账户状态值不同,EXPIRY_DATE代表的意思有所不同,状态值为OPEN,则代表过期时间是什么时间。状态值为EXPIRED(GRACE),则代表宽恕期结束是什么时间。

另外,更新PASSWORD_LIFE_TIME值,也会实时的更新账户的EXPIRY_DATE值,但是仅对处于OPEN状态的账户有效。

如某账户为OPEN状态,其EXPIRY_DATE值为2020年4月8日10点,此时将PASSWORD_LIFE_TIME更改为2,则EXPIRY_DATE值就变成2020年4月9日10点了。

但是如果该账户是处于EXPIRED(GRACE)状态,修改PASSWORD_LIFE_TIME或PASSWORD_GRACE_TIME对它都是没用的。

不知道为什么,SYS账户不受到口令过期的限制,我测试的时候确实是这样。

可能是因为它属于特殊账户?毕竟判断是否过期也要去先读取数据库,而SYS账户可以在数据库未开启的时候连接它。

与口令过期间接相关的两个参数:PASSWORD_REUSE_TIME和PASSWORD_REUSE_MAX

PASSWORD_REUSE_TIME:指定了口令在多少天内不能重用,单位为1天。

PASSWORD_REUSE_MAX:指定了当前口令在被重用之前需要更改几次。

这里的重用是针对每个账户的自己的口令,如果不设置这两个参数,设置账户新口令的时候就可以使用当前的口令,那么口令过期就不存在意义了。

这里光看说明是看是不太容易理解的,试一试就明白了:

在PASSWORD_REUSE_TIME、PASSWORD_REUSE_MAX均为默认值UNLIMITED的时候,修改口令的时候可以随意重用,用当前的口令当新口令也都可以。

这里会突然想到verify_function_11G,如果新口令和旧口令一样的话,应该通不过校验的才对。

经过实验,不知道是为什么old_password是空字符串,压根就没有传值进来,所以实际上直接跳过了旧口令和新口令的对比校验……

当PASSWORD_REUSE_TIME、PASSWORD_REUSE_MAX均非默认值UNLIMITED的时候,则需要两个条件都满足才可以更改口令。

如PASSWORD_REUSE_TIME从UNLIMITED变成1,以及PASSWORD_REUSE_MAX从UNLIMITED变成1开始,oracle开始记录使用过的口令。

如某账户,这个时候依次设置新口令a、b、c、d、e,此时的口令是e,在1天内,该账户设置新口令的话,使用a、b、c、d、e中的任何一个都不可以。

超过1天后,a、b、c、d均可作为新口令,但是e不可以,因为PASSWORD_REUSE_MAX的值是1,相当于从e往前数,有1个口令不能被当做新口令,那就是e自己了。如果PASSWORD_REUSE_MAX的值是2,那么e、d均不可以作为新口令。

而如果PASSWORD_REUSE_TIME为unlimited、PASSWORD_REUSE_MAX为某个数值,或者PASSWORD_REUSE_TIME为某个数值,PASSWORD_REUSE_MAX为unlimited的时候,账户使用的口令都不能当做新口令进行设置。

所以为了满足定期更换的要求,PASSWORD_REUSE_TIME、PASSWORD_REUSE_MAX都应该设置为非unlimited的值。

最后,不知道为什么,SYS账户也不受到这两个参数的限制,可以随意重用口令。

*本文作者:起于凡而非于凡,转载请注明来自FreeBuf.COM

相关推荐
取消
Loading...

特别推荐

填写个人信息

姓名
电话
邮箱
公司
行业
职位
css.php