
写在前面,小编的话: 
对于不定期修改密码这个例行维护工作,以前我们往往需要安排到停机时间,以便于我们可以更改数据库用户密码,然后遍历所有应用程序服务器和应用,更改它们的连接信息。
从Oracle 21c开始,Oracle提供了一个新的安全特性:Gradual Database Password Rollover(GDPR,嘿嘿,此GDPR非彼GDPR^|^),我们这里姑且把它翻译成渐进式数据库密码轮转更新,详细信息可以参见这里的在线文档说明。这个安全特性,允许我们在密码轮转期间,同时使用旧密码和新密码进行连接。这意味着更改数据库用户密码,任何应用程序的连接都正常进行,无需硬切断新连接。从另外一个维度来看的话,也是进一步简化了运维,降低了停机时间。
这个特性也向后兼容到Oracle Database 19.12(截止到本文写作时,19c最新的RU是19.18),所有Offering都可使用。并且无需更改兼容性参数。借助这个渐进式数据库密码轮转更新特性,以前更改数据库用户密码需要同时停止/重启应用的时代,总算真正改变了。

Gradual Database Password Rollover概述
Gradual Database Password Rollover特性是基于Oracle Profiles(配置文件)来定义的,配置文件已经存在于Oracle数据库中几十年了,绝大多数Oracle DBA都知道Profile对象的存在,Profile与User相关联, 它定义了两种不同类别的配置文件资源:一是内核资源,可以为一个或多个用户组成的组指定资源可用性。二是密码资源,可以为一个或多个用户指定密码行为。
其中密码资源有如下几种:

密码资源说明如下

所有Oracle用户都分配有一个配置文件,如果没有分配,Oracle将分配它在创建数据库时创建的DEFAULT配置文件,Oracle不建议直接修改DEFAULT配置文件,而是应该创建一个或多个新的客户配置文件,分别用于DBA管理团队以及应用程序或其他人员。
缺省的DEFAULT配置文件设置可以通过如下SQL获得:
SQL> col profile for a12 SQL> col limit for a15 SQL> select profile,resource_name,limit from dba_profiles where profile='DEFAULT' and resource_type='PASSWORD'; PROFILE RESOURCE_NAME LIMIT ------------ -------------------------------- --------------- DEFAULT FAILED_LOGIN_ATTEMPTS 10 DEFAULT PASSWORD_LIFE_TIME 180 DEFAULT PASSWORD_REUSE_TIME UNLIMITED DEFAULT PASSWORD_REUSE_MAX UNLIMITED DEFAULT PASSWORD_VERIFY_FUNCTION NULL DEFAULT PASSWORD_LOCK_TIME 1 DEFAULT PASSWORD_GRACE_TIME 7 DEFAULT INACTIVE_ACCOUNT_TIME 365 DEFAULT PASSWORD_ROLLOVER_TIME 0 9 rows selected. SQL> |
Gradual Database Password Rollover特性就是通过这个新增加的资源参数PASSWORD_ROLLOVER_TIME来控制,当该参数设置为非0限制就允许更改应用程序数据库用户的密码,同时允许旧密码在PASSWORD_ROLLOVER_TIME限定的时间内保持有效,在这期间应用程序可以使用旧密码或新密码连接到数据库。当轮转切换时间(password_rollover_time)到期时,就只能用新密码连接访问了。

•PASSWORD_ROLLOVER_TIME资源设置说明
1. 缺省设置为0表示禁用Password Rollover
2. 单位是天,最小值为1小时,比如把限制设置为4个小时:4/24
3. 最大值不能超过60天,也不能超过当前配置文件中的MIN(PASSWORD_GRACE_TIME,PASSWORD_LIFE_TIME)
4. 粒度如果是秒,例如(1/24) +(3/1440) +(5/86400)) 表示限制为1小时加3分5秒

•PASSWORD_ROLLOVER_TIME、PASSWORD_GRACE_TIME、PASSWORD_LIFE_TIME三个资源的缺省设置如下


•Gradual Database Password Rollover特性带来的相关变化
üCreate Profile和Alter Profile中增加新的PASSWORD_ROLLOVER_TIME子句
ü在Alter User语句中也增加了expire password rollover period允许手动提前结束rollover有效期
üDBA_USERS相关视图中增加新的password_change_date列,并和account_status列配合增加了新的状态值,这些值标识当前密码的滚动状态


•Gradual Database Password Rollover后密码更改生命周期
创建或更改密码后,它会经历四个阶段的生命周期和宽限期。下图显示了密码生存期和宽限期的生命周期。

阶段1:当启用Gradual Database Password Rollover后,创建和修改密码后,密码生存期有1a和1b两个阶段。
阶段1a:新旧2个密码同时有效,持续时间缺省是PASSWORD_ROLLOVER_TIME设定的时间,管理员可以手动提前结束。
阶段1b: 对应于密码轮转到期后剩余的时间,直到PASSWORD_LIFE_TIME 结束。在阶段 1b 期间,用户只能使用新密码登录。
阶段2:表示密码轮转到期后,用户使用新密码再次登录之前的时间,Oracle 数据库需要正确的凭据才能更新帐户状态。否则,账户状态将保持不变。
阶段3:就进入密码宽限期,和以前一样了。然后Oracle 数据库使用当前时间加上帐户密码配置文件中 PASSWORD_GRACE_TIME 设置的值,将DBA_USERS.EXPIRY_DATE 列更新为一个新值。届时用户收到密码即将过期的ORA-28002警告信息(例如,ORA-28002 The password will expire within 7 days if set PASSWORD_GRACE_TIME is 7 days),但用户仍然可以登录 在不更改密码的情况下。DBA_USERS.EXPIRY_DATE 列显示将来提示用户更改密码的时间。
阶段4:宽限期结束,提示用户修改密码才能登录,出现ORA-28001: The password has expired这样的错误,进入下一个密码修改周期。

•Gradual Database Password Rollover的支持限制
无法为以下连接类型配置Gradual Database Password Rollover
•Oracle Real Application Security 用户的直接登录
•采用外部身份验证的用户(Kerberos,PKI,Radius)
•集中管理的用户(CMU,EUS)
•采用10g Password Verfiers的用户
•Role Passwords
•系统管理用户(SYSDBA,SYSOPER,SYS*...)

•Gradual Database Password Rollover与连接池
连接池一般仅在连接的初始创建期间进行身份验证。如果连接池的初始大小设置为10,那么这 10 个连接将使用提供的密码进行身份验证。稍后在池中检出这些连接时,不会发生任何身份验证,创建的连接仍然有效,并且能够执行SQL。
如果需要的连接数多于初始数量,则在连接池中创建这些连接时进行身份验证。比如在使用 10 个连接初始化池后更改了密码,那么在创建第 11 个连接期间将抛出 ORA-1017。因此,使用密码轮转机制后,只要修改连接池中的密码则可以避免ORA-1017。
密码轮转期结束后,对于新的连接就使用新的密码了。如果要释放旧密码的连接,可以kill session或重启一下应用服务器,一般应用服务器都是多台,采用滚动的方式可以最小化业务中断。

Gradual Database Password Rollover体验
这里我们再回顾一下Gradual Database Password Rollover的工作流程:
1、启用Gradual Database Password Rollover;
2、在数据库端修改用户密码,这时新、旧密码在一定时间内同时有效;
3、在应用端修改用户新的连接密码;
4、让旧的密码过期,就只有新的密码有效了;
5、禁用Gradual Database Password Rollover。
下面我们通过一个简单的练习直观感受一下这个特性,这里以多租户架构下PDB1容器中的ywsl用户为例。
1、给用户ywsl定义一个Profile
SQL> alter session set container=pdb1; Session altered. SQL> create profile ywslprofile 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 INACTIVE_ACCOUNT_TIME 60 PASSWORD_VERIFY_FUNCTION ora12c_verify_function; Profile created. SQL> alter user ywsl profile ywslprofile; User altered. SQL> col username for a12 SQL> col profile for a20 SQL> select username,profile from dba_users where username='YWSL'; USERNAME PROFILE ------------ -------------------- YWSL YWSLPROFILE SQL> |
现在ywsl用户的密码是ywsl,没有启用Gradual Database Password Rollover。
SQL> conn ywsl/ywsl@pdb1; Connected. SQL> col limit for a20 SQL> select profile,limit from dba_profiles where profile='YWSLPROFILE' and resource_name= 'PASSWORD_ROLLOVER_TIME'; PROFILE LIMIT -------------------- -------------------- YWSLPROFILE DEFAULT SQL> |
2、修改用户ywsl的profile,启用Gradual Database Password Rollover
SQL> alter session set container=pdb1; Session altered. SQL> alter profile YWSLPROFILE limit PASSWORD_ROLLOVER_TIME 1; Profile altered. SQL> |
3、现在进入渐进式数据库密码轮转期了,修改用户ywsl的密码
SQL> alter session set container=pdb1; Session altered. SQL> alter user ywsl identified by AfterCh##01; User altered. SQL> |
这个时候旧密码和新密码都可以连接,因为在profile中我们设定的rollver period是1天,所以ywsl用户在1天内可以同时使用旧密码和新密码登录。
4、连接验证
##用旧的密码
SQL> conn ywsl/ywsl@pdb1 Connected. SQL> |
##用新的密码
SQL> conn ywsl/AfterCh##01@pdb1; Connected. SQL> |
可以看到,这个时候新旧密码都成功地完成了连接。查询dba_users可以看到rollover的状态。
SQL> select username,account_status from dba_users where username='YWSL'; USERNAME ACCOUNT_STATUS ------------ -------------------------------- YWSL OPEN & IN ROLLOVER SQL> |
在渐进式数据库密码轮转期,如果新密码设置不合理,可以多次修改,以最后一次为准。比如:
SQL> alter user ywsl identified by AfterCh##02; User altered. SQL> alter user ywsl identified by AfterCh##03 replace AfterCh##02; User altered. SQL> |
那么这个时候,只有最初的旧密码和最后一次设置的AfterCh##03才可以连接
SQL> conn ywsl/ywsl@pdb1; Connected. SQL> conn ywsl/AfterCh##03@pdb1 Connected. SQL> conn ywsl/AfterCh##02@pdb1; ERROR: ORA-01017: invalid credential or not authorized; logon denied Warning: You are no longer connected to ORACLE. SQL> |
5、结束Password Rollover period
当所有客户端都已经修改完密码,那么可以结束Password Rollover period,有2个方法:
1)自动等待PASSWORD_ROLLOVER_TIME设置的时间过期
2)DBA主动结束
我们这里假设DBA知道所有的客户端都已经修改完毕了,但PASSWORD_ROLLOVER_TIME设置的时间还没到,所以主动结束
SQL> conn as sysdba Connected. SQL> alter session set container=pdb1; Session altered. SQL> alter user ywsl expire password rollover period; User altered. SQL> alter profile YWSLPROFILE limit password_rollover_time 0; Profile altered. SQL> col username for a12 SQL> col account_status for a20 SQL> select username,account_status from dba_users where username='YWSL'; USERNAME ACCOUNT_STATUS ------------ -------------------- YWSL OPEN SQL> |
现在再用旧的密码就无法登录了。
SQL> conn ywsl/ywsl@pdb1 ERROR: ORA-01017: invalid credential or not authorized; logon denied Warning: You are no longer connected to ORACLE. SQL> |
6、需要注意的地方
渐进式数据库密码轮转更新可能会不定期使用,有一点需要注意的是,必须确保在禁用和重新启用渐进密码轮转之间至少有一次连接尝试,否则可能无法获得我们想要的密码重置。比如:
#禁用 SQL> alter profile YWSLPROFILE limit password_rollover_time 0; #启用 SQL> alter profile YWSLPROFILE limit password_rollover_time 1; |
如果在禁用之前没有手动结束password rollover period,中间也没有任何新的连接发生,那么紧接着再次启用后,之前的2个密码任然可用。
所以正确的做法有两个:
1)先手动结束,然后禁用,最后再根据需要启用
2)先禁用,然后尝试连接,再根据需要启用

如何找出密码轮转期间使用旧密码的连接
在实际运营中,如果应用端已经修改完密码,应该通知DBA立刻结束pas sword rollover period,然后禁用。但现实中可能没有那么理想,有些人由于各种原因没有即时反馈,所以一个比较实际的问题就是DBA如何找出密码轮转期间仍在使用旧密码的连接,这是可以做到的。
统一的审计跟踪可以识别哪些用户仍在使用旧密码连接到数据库。LOGON 审计记录的 AUTHENTICATION_TYPE 字段可以显示是否使用了旧的验证程序。此信息使我们能够找到尚未通过渐进式数据库密码轮转更新以使用新密码的应用程序。
执行类似如下的查询,可根据需要修改查询条件
select DBUSERNAME, AUTHENTICATION_TYPE, OS_USERNAME, USERHOST, EVENT_TIMESTAMP from unified_audit_trail where ACTION_NAME='LOGON' and EVENT_TIMESTAMP > SYSDATE-1 and REGEXP_LIKE(AUTHENTICATION_TYPE, '\(VERIFIER=.*?\-OLD\)'); |
如果有用户仍在使用他们的旧密码,则会出现类似以下的输出,检查 LOGON_INFO,如果值为VERIFIER=12C-OLD,则表示使用旧的密码。

然后可以依据上述查询提醒对应的客户端修改密码,当然了这个方法也不能完全确保所有的客户端满足,因为目前不运行的定时程序之类的应用可能在LOGON审计记录中没有。

Gradual Database Password Rollover工作原理
最后我们再探究一下Gradual Database Password Rollover的工作原理,仍然以前面PDB1的ywslprofile 配置文件和ywsl用户为例。
1、再次启用Gradual Database Password Rollover
SQL> col profile for a20 SQL> col limit for a10 SQL> select profile,limit from dba_profiles where resource_name= 'PASSWORD_ROLLOVER_TIME' and profile='YWSLPROFILE'; PROFILE LIMIT -------------------- ---------- YWSLPROFILE 0 SQL> SQL> alter profile YWSLPROFILE limit password_rollover_time 1; Profile altered. SQL> |
2、当前用户ywsl的密码HASH
重置ywsl初始密码还是ywsl
SQL> select user_id from dba_users where username= 'YWSL'; USER_ID ---------- 155 SQL> select replace(spare4, ';' ,chr( 10 )) spare4 from user$ where USER#= 155; SPARE4 ----------------------------------------------------------------------- S:CC18E4934223745DE855E54F36FFB96FE43956453C8E3956492F40D776CE T:77D13B6A2292F0803B3EA1F03CCA072369BF433493E039C71661E82918FFD06007566BD35D7CFCF62632259EC05ECB4C3534634D9A4480B687E2D809513DABD86C66413AA45486B78807DA8EF500BA1D SQL> |
S: 11g密码版本
T: 12c密码版本
3、在渐进式数据库密码轮转更新期间,第一次修改ywsl用户的密码
SQL> alter user ywsl identified by WelOra#01; User altered. SQL> select replace(spare4, ';' ,chr( 10 )) spare4 from user$ where USER#= 155; SPARE4 ------------------------------------------------------------------------ S:CC18E4934223745DE855E54F36FFB96FE43956453C8E3956492F40D776CE T:77D13B6A2292F0803B3EA1F03CCA072369BF433493E039C71661E82918FFD06007566BD35D7CFCF62632259EC05ECB4C3534634D9A4480B687E2D809513DABD86C66413AA45486B78807DA8EF500BA1D t:BCBB478FFB10654DE60E0F3A73DA0CB0A1BAB312DDFBEBC931B68C53EF9742CAA4AF63969DA5A0F1D915AD3E5F230B7C24F2F4F9E89C32CCD0BFD51D437116A06C66413AA45486B78807DA8EF500BA1D V:7801545C3A2D01FAC8B53C8E299134A450714B7E56577296794473DD9F5F4B79C88CC65952D746276FEA7A266F9296C299863EE0F613AF517A41CC96B871A67186A5B58789FCD49B5CCBA29AC2DA7FDE s:FFB0E377C118B5AC5919BF1826F39E5A1A77BD533C8E3956492F40D776CE U:0AA720C27E3E7FEF9B197451A9E833FCD3DC9D3C910426C683DFBF5CAA36 SQL> |
仔细看,会发现几个以前没见过的FLAG
S: 之前的 SHA1 hash
T: 之前的 SHA2 hash
U: 修改后(新的) SHA1 hash
V: 修改后(新的) SHA2 hash
s: 修改后(新的) SHA1 hash using old SALT
t: 修改后(新的) SHA2 hash using old SALT
其中“s”和“S”对于 SHA1 具有相同的SALT(最后 20 个字符),对于 SHA2,“t”和“T”也具有相同的 SALT(最后 32个字符)。
4、在渐进式数据库密码轮转更新期间,第二次修改ywsl用户的密码
SQL> alter user ywsl identified by WelOra#02; User altered. SQL> select replace(spare4, ';' ,chr( 10 )) spare4 from user$ where USER#= 155; SPARE4 ------------------------------------------------------------------------ S:CC18E4934223745DE855E54F36FFB96FE43956453C8E3956492F40D776CE T:77D13B6A2292F0803B3EA1F03CCA072369BF433493E039C71661E82918FFD06007566BD35D7CFCF62632259EC05ECB4C3534634D9A4480B687E2D809513DABD86C66413AA45486B78807DA8EF500BA1D t:577B22F54EF69EBD8E3EE21A2D8A4621098C526785C970613ADC7CF2A54CDDD446BA0DAF56500BF9EA124DE8BBE28877A8314CC5FD39CC9A3D5648DB0A834E8A6C66413AA45486B78807DA8EF500BA1D V:F79A345C0465031E93245FF524A1AE0E3DC0855E8CD993ADD161BC4BA825DABCC22483AE05D06B5AA5401E2750AF13B34304BF0EFA2B1E3FDC7E80038A845C59D34A7AF0F7ED2F500F1DEA4945E68E35 s:620511619EA5621B3AA4AF3837E368BCD193A1413C8E3956492F40D776CE U:963E1CCBB909C9C8A583C631AA91F01792707A12CF27325A9A0EC7FC1091 SQL> |
U,V,s,t都发生了改变,而老的S,T都不变
这个时候,最初的密码和最后修改的密码都可以登录,但第一次修改的密码不可以再次登录了。
5、结束Password Rollover period
SQL> alter user ywsl expire password rollover period; User altered. SQL> select replace(spare4, ';' ,chr( 10 )) spare4 from user$ where USER#= 155; SPARE4 ------------------------------------------------------------------------ S:DDBC46685837BAB082E7685581CA2E15BBF63FA5549D0201261383EE5939 T:1D9EB66C6D2AD31C6DA7B3B40BB3CF90FEAF4D6EFDABB910C52377DA01A87E3F161D80255701F20F92E3386EE90298322123715E4BF9DAE1BFD35C597EC817CAFF2A10480E9DF7FE8140CD33E2EAA7D5 SQL> |
就剩下最新修改后密码的HASH了,并且用“U”和“V”条目(带有新的 SALT)取代了“S”和“T”条目。
这时候老的密码就无法连接了。
SQL> conn ywsl/ywsl@pdb1; ERROR: ORA-01017: invalid credential or not authorized; logon denied Warning: You are no longer connected to ORACLE. SQL> conn ywsl/WelOra#02@pdb1 Connected. SQL> |
最后我们再最后禁用渐进式数据库密码轮转更新
SQL> conn /as sysdba Connected. SQL> alter session set container=pdb1; Session altered. SQL> alter profile ywslprofile limit password_rollover_time 0; Profile altered. SQL> select profile,limit from dba_profiles where resource_name= 'PASSWORD_ROLLOVER_TIME' and profile='YWSLPROFILE'; PROFILE LIMIT -------------------- ---------- YWSLPROFILE 0 SQL> |
可以看出,在渐进式数据库密码轮转更新期间,s,t使用了和最初S,T相同的salt来保持新HASH的原因似乎是为了在身份验证流程中使用单一的salt。也就是说,这样任何客户端支持此新功能都是透明的,交给Server端要做的就是将提供的哈希值与2个可能的选项进行比较进行验证,当轮转期结束,就使用新 SALT 将密码将用于安全。

小结
现如今数据的使用变得越来越复杂,在数据驻留和安全性、响应时间和业务连续性几个方面尤为突出。Availability和Security往往是"孪生"出现的,首先是可用性,然后必须考虑安全性,如果老是中断不可用,就算不考虑损失和影响,请问谁能忍受的了?如果安全没有保障,那可用性和合规也是无稽之谈了。
那些“年久失修”的老/旧系统,最容易导致严重的安全隐患。当然了现实中也没有永久足够的安全性,我们只有不断的加强防护,分层防御,拉升威胁的成本,让觊觎者望而却步。
而过时版本的数据库是脆弱的,使用过时版本的数据库,错过了安全加固的机会、缺乏技术支持、与软件和硬件不兼容,以及可能遇到一些bug。所以,单从安全的角度出发,升级到19c也是非常迫切的一个原因,另外19c附带了最新的数据库安全特性和补丁,已知的网络漏洞都已经修补,并且是长期支持版本,未来的漏洞也会继续得到及时的修补。
本文我们介绍的19c&21c安全特性“Gradual Database Password Rollover”就是在应对安全和合规的同时,帮助我们做到最小化业务中断,最大化业务连续,希望对大家有所帮助。
编辑:乔梁





