首批通过分布式安全可靠测评,为关键业务系统打造
密码复杂度
更新时间:2026-07-15 22:01:30
OceanBase 数据库 Oracle 模式的密码复杂度策略,兼容 Oracle 数据库的密码策略。为了防止恶意的密码攻击,提升数据库的安全性,OceanBase 数据库用户可以根据需要,设置密码的复杂度函数,验证用户登录身份。
功能适用性
本文档仅适用于 OceanBase 数据库 Oracle 模式。目前 OceanBase 数据库社区版仅提供了 MySQL 模式,有关 MySQL 模式下的密码复杂度,参见 密码复杂度。
前提条件
Oracle 模式下,用户可以使用 Profile 中的 PASSWORD_VERIFY_FUNCTION 属性来验证密码复杂度是否符合要求。用户需要先创建一个用于校验密码复杂度的 PL Function,需要满足如下接口:
FUNCTION verify_function (username IN VARCHAR2,
password IN VARCHAR2,
old_password IN VARCHAR2)
RETURN BOOLEAN;
创建用户或修改密码时,会调用该校验函数,根据函数执行结果来判断新密码是否符合复杂度要求。
设置密码复杂度并启用密码复杂度验证
OceanBase 数据库的 Oracle 模式提供了 PASSWORD_VERIFY_FUNCTION 参数来验证密码复杂度是否符合要求。
PASSWORD_VERIFY_FUNCTION 参数允许将 PL 的密码复杂性验证函数作为参数传递给 CREATE PROFILE 和 ALTER PROFIL 语句。
注意
生产环境建议设置密码长度为 20 位,包括数字、大写字母、小写字母以及特殊字符。密码的复杂度越低,其被破解的可能性就越大,比如包含用户名、使用重复字符等。出于安全性考虑,需确保用户的密码具有较高的复杂度。
使用
SYS用户登录到集群的 Oracle 租户。obclient -usys@oracle -h10.xxx.xxx.1 - P2881 -P*******编写
PASSWORD_VERIFY_FUNCTION参数对应的函数并授权。以下以设置密码复杂度为如下规则,提供操作指导。
密码长度最小为 8 个字符,最大不超过 256 个字符。
至少包含 1 个大写字母、1 个小写字母和 1 个特殊字符。
密码不能是用户名,不能是用户名的反序,也不能是服务器名。
示例如下:
delimiter // CREATE OR REPLACE FUNCTION complexity_check (password varchar2, chars integer := NULL, letter integer := NULL, upper_c integer := NULL, lower_c integer := NULL, digit integer := NULL, special integer := NULL) RETURN boolean IS digit_array varchar2(10) := '0123456789'; alpha_array varchar2(26) := 'abcdefghijklmnopqrstuvwxyz'; cnt_letter integer := 0; cnt_upper integer := 0; cnt_lower integer := 0; cnt_digit integer := 0; cnt_special integer := 0; flag boolean := FALSE; len INTEGER := NVL(length(password), 0); i integer ; ch CHAR(1); BEGIN -- Check that the password length does not exceed 2 * (max DB pwd len) -- The maximum length of any DB User password is 128 bytes. -- This limit improves the performance of the Edit Distance calculation -- between old and new passwords. IF len > 256 THEN raise_application_error(-20020, 'Password length more than 256'); END IF; -- Classify each character in the password. FOR i in 1..len LOOP ch := substr(password, i, 1); IF ch = '"' THEN flag := TRUE; ELSIF instr(digit_array, ch) > 0 THEN cnt_digit := cnt_digit + 1; ELSIF instr(alpha_array, LOWER(ch)) > 0 THEN cnt_letter := cnt_letter + 1; IF ch = LOWER(ch) THEN cnt_lower := cnt_lower + 1; ELSE cnt_upper := cnt_upper + 1; END IF; ELSE cnt_special := cnt_special + 1; END IF; END LOOP; IF flag = 1 THEN raise_application_error(-20012, 'password must NOT contain a ' || 'double-quote character, which is ' || 'reserved as a password delimiter'); END IF; IF chars IS NOT NULL AND len < chars THEN raise_application_error(-20001, 'Password length less than ' || chars); END IF; IF letter IS NOT NULL AND cnt_letter < letter THEN raise_application_error(-20022, 'Password must contain at least ' || letter || ' letter(s)'); END IF; IF upper_c IS NOT NULL AND cnt_upper < upper_c THEN raise_application_error(-20023, 'Password must contain at least ' || upper_c || ' uppercase character(s)'); END IF; IF lower_c IS NOT NULL AND cnt_lower < lower_c THEN raise_application_error(-20024, 'Password must contain at least ' || lower_c || ' lowercase character(s)'); END IF; IF digit IS NOT NULL AND cnt_digit < digit THEN raise_application_error(-20025, 'Password must contain at least ' || digit || ' digit(s)'); END IF; IF special IS NOT NULL AND cnt_special < special THEN raise_application_error(-20026, 'Password must contain at least ' || special || ' special character(s)'); END IF; RETURN(TRUE); END; // CREATE OR REPLACE FUNCTION verify_function (username varchar2, password varchar2, old_password varchar2) -- 此例中自定义了三个函数参数---用户名 username、新密码 password 和旧密码 old_password RETURN boolean IS differ integer; pw_lower varchar2(256); db_name varchar2(40); i integer; simple_password varchar2(10); reverse_user varchar2(32); BEGIN IF NOT complexity_check(password, 8, NULL, 1, 1, NULL, 1) THEN RETURN(FALSE); END IF; -- Check if the password contains the username pw_lower := LOWER(password); IF instr(pw_lower, LOWER(username)) > 0 THEN raise_application_error(-20002, 'Password contains the username'); END IF; -- Check if the password contains the username reversed reverse_user := ''; FOR i in REVERSE 1..length(username) LOOP reverse_user := reverse_user || substr(username, i, 1); END LOOP; IF instr(pw_lower, LOWER(reverse_user)) > 0 THEN raise_application_error(-20003, 'Password contains the username ' || 'reversed'); END IF; -- Check if the password contains the server name db_name := 'oceanbase'; IF instr(pw_lower, LOWER(db_name)) > 0 THEN raise_application_error(-20004, 'Password contains the server name'); END IF; -- Check if the password contains 'oracle' IF instr(pw_lower, 'oracle') > 0 THEN raise_application_error(-20006, 'Password too simple'); END IF; RETURN(TRUE); END; // delimiter ; obclient> GRANT EXECUTE ON verify_function TO PUBLIC; obclient> CREATE PUBLIC SYNONYM verify_function FOR sys.verify_function;创建函数的相关操作,请参见 创建函数。
在 User 的 Profile 中,指定
PASSWORD_VERIFY_FUNCTION参数,启用密码复杂度验证。语句如下:
obclient> ALTER PROFILE profile_name LIMIT PASSWORD_VERIFY_FUNCTION verify_function;其中,
profile_name可以使用您自定义的 Profile,也可以使用DEFAULTProfile。使用
DEFAULTProfile 指定PASSWORD_VERIFY_FUNCTION参数的示例如下:obclient> ALTER PROFILE DEFAULT LIMIT PASSWORD_VERIFY_FUNCTION verify_function; Query OK, 0 rows affected更多
ALTER PROFILE语句的详细信息,参见 ALTER PROFILE。完成后,您可以执行以下语句,确认密码复杂度验证是否开启。
返回值为
NULL则表示密码复杂度验证未开启,值为刚刚指定的函数则表示密码复杂度验证已开启。obclient> SELECT LIMIT FROM DBA_PROFILES WHERE RESOURCE_NAME='PASSWORD_VERIFY_FUNCTION' AND PROFILE='profile_name';示例如下:
obclient> SELECT LIMIT FROM DBA_PROFILES WHERE RESOURCE_NAME='PASSWORD_VERIFY_FUNCTION' AND PROFILE='DEFAULT'; +-----------------+ | LIMIT | +-----------------+ | VERIFY_FUNCTION | +-----------------+ 1 row in set
验证密码复杂度的设置是否有效
使用
SYS用户登录集群的 Oracle 租户。obclient -usys@oracle -h10.xxx.xxx.1 - P2881 -P*******分别使用符合要求的密码和不符合要求的密码创建用户
sectest1。obclient> CREATE USER sectest1 IDENTIFIED BY ******; ERROR-20023: Password must contain at least 1 uppercase character(s) obclient> CREATE USER sectest1 IDENTIFIED BY ******; ERROR-20002: Password contains the username obclient> CREATE USER sectest1 IDENTIFIED BY ******; Query OK, 0 rows affected
查看密码复杂度规则
密码复杂度设置成功后,如果下次需要查看具体的复杂度规则,可以通过查询函数中的内容来获取。
方法如下:
使用 SYS 用户登录集群的 Oracle 租户。
obclient -usys@oracle -h10.xxx.xxx.1 - P2881 -P*******通过
DBA_SOURCE视图查找对应的函数。DBA_SOURCE视图记录了系统中所有的存储过程和函数。更多
DBA_SOURCE视图及其字段的说明,参见 DBA_SOURCE。示例如下:
obclient> SELECT OWNER,NAME,TYPE FROM DBA_SOURCE WHERE TYPE='FUNCTION'; +-------+------------------+----------+ | OWNER | NAME | TYPE | +-------+------------------+----------+ | SYS | COMPLEXITY_CHECK | FUNCTION | | SYS | STRING_DISTANCE | FUNCTION | | SYS | VERIFY_FUNCTION | FUNCTION | +-------+------------------+----------+ 3 rows in set通过
USER_SOURCE视图查看当前用户拥有的函数VERIFY_FUNCTION的内容。USER_SOURCE视图记录了系统中当前用户拥有的所有存储过程和函数。更多
USER_SOURCE视图及其字段的说明,参见 USER_SOURCE。示例如下:
obclient>SELECT TEXT FROM USER_SOURCE WHERE NAME='VERIFY_FUNCTION' AND TYPE='FUNCTION'\G *************************** 1. row *************************** TEXT: FUNCTION verify_function (username varchar2, password varchar2, old_password varchar2) -- 此例中自定义了三个函数参数---用户名 username、新密码 password 和旧密码 old_password RETURN boolean IS differ integer; pw_lower varchar2(256); db_name varchar2(40); i integer; simple_password varchar2(10); reverse_user varchar2(32); BEGIN IF NOT complexity_check(password, 8, NULL, 1, 1, NULL, 1) THEN RETURN(FALSE); END IF; -- Check if the password contains the username pw_lower := LOWER(password); IF instr(pw_lower, LOWER(username)) > 0 THEN raise_application_error(-20002, 'Password contains the username'); END IF; -- Check if the password contains the username reversed reverse_user := ''; FOR i in REVERSE 1..length(username) LOOP reverse_user := reverse_user || substr(username, i, 1); END LOOP; IF instr(pw_lower, LOWER(reverse_user)) > 0 THEN raise_application_error(-20003, 'Password contains the username ' || 'reversed'); END IF; -- Check if the password contains the server name db_name := 'oceanbase'; IF instr(pw_lower, LOWER(db_name)) > 0 THEN raise_application_error(-20004, 'Password contains the server name'); END IF; -- Check if the password contains 'oracle' IF instr(pw_lower, 'oracle') > 0 THEN raise_application_error(-20006, 'Password too simple'); END IF; RETURN(TRUE); END 1 row in set
更多函数管理的相关操作,参见 管理存储过程和函数。