Oracle 19c 为何必须手动绑定密码校验函数
Oracle 19c 默认启用的 ora12c_verify_function 相比旧版确实在密码强度上有了明显提升,但直接使用它,部分业务特定需求可能无法覆盖。例如,禁止用户名倒序、禁用常见弱口令子串——这些场景,内置函数往往无法满足。
因此,手动绑定并验证密码校验函数是否生效,不是可选项,而是必选项。许多 DBA 以为修改完 profile 就万事大吉,结果却发现新密码依然可以设置为 oracle123,因为 PASSWORD_VERIFY_FUNCTION 仍然是 NULL。

如何确认当前密码校验函数是否已启用
不要仅凭猜测,通过 SQL 执行结果即可确认。按以下三步操作:
- 执行
SELECT limit FROM dba_profiles WHERE profile = 'DEFAULT' AND resource_name = 'PASSWORD_VERIFY_FUNCTION';——如果返回NULL或空值,说明未启用。 - 如果返回了函数名(例如
ORA12C_VERIFY_FUNCTION),再确认该函数是否存在:SELECT owner, object_name, status FROM dba_objects WHERE object_name IN ('ORA12C_VERIFY_FUNCTION', 'ORA_STIG_VERIFY_FUNCTION') AND object_type = 'FUNCTION'; - 关键点:函数必须位于
SYSschema 下,且状态为VALID。否则,绑定后修改密码时会报ORA-28003,且不提示具体原因。
运行 utlpwdmg.sql 后,为什么密码仍然可以设置得很弱
脚本执行成功 ≠ 策略自动生效。以下三个常见断点容易被忽略:
@?/rdbms/admin/utlpwdmg.sql仅创建函数并修改DEFAULTprofile 的PASSWORD_VERIFY_FUNCTION参数,但不会自动将已有用户从DEFAULT切换过去。请检查:SELECT username, profile FROM dba_users WHERE username NOT IN ('SYS','SYSTEM');- 函数创建后必须显式授权:
GRANT EXECUTE ON ORA12C_VERIFY_FUNCTION TO PUBLIC;——否则非 SYS 用户调用时会静默失败。 - 19c 中
ORA12C_VERIFY_FUNCTION默认要求至少 8 位、包含大小写字母+数字+特殊字符。但如果数据库字符集是AL32UTF8,某些 Unicode 特殊字符(如中文标点)会被忽略校验,实际仅按 ASCII 范围判断。
自定义 verify_function 函数时最容易踩的三个坑
想要添加“禁止密码包含用户名拼音”或“禁用近三个月用过的密码哈希”?手写函数时,以下三点错一处,ALTER USER ... IDENTIFIED BY 就会直接报 ORA-28003,且不给出提示。
- 签名必须严格为:
FUNCTION my_verify (username IN VARCHAR2, password IN VARCHAR2, old_password IN VARCHAR2) RETURN BOOLEAN——多一个参数、少一个IN、返回NUMBER,都会导致编译通过但运行时失效。 - 函数体内不能出现
INSERT/UPDATE/DBMS_OUTPUT.PUT_LINE。调试时可以用CREATE OR REPLACE PROCEDURE debug_log(p_msg VARCHAR2) AS BEGIN NULL; END;占位,避免误触副作用。 - 长度检查必须放在最前面:
IF LENGTH(password) < 8 THEN RETURN FALSE; END IF;——否则后续REGEXP_LIKE在空密码或超短密码下可能抛出异常,中断校验流程。
生产环境启用前必须验证的边界场景
不要只测试 Abc123!@# 这种理想密码。真实用户会输入各种你写函数时未曾考虑到的诡异组合,而 Oracle 的校验函数对这些输入的处理非常“直白”。
- 密码含前导/尾随空格:
' Abc123!@# '——LENGTH返回 13,但 Oracle 实际存储时会 trim,导致校验通过后真实密码变短。 - 用户名全小写但密码用大写开头:
username='scott',password='SCOTT123'——内置函数默认不校验大小写敏感匹配,需在自定义函数里加INSTR(UPPER(username), UPPER(password)) > 0。 - 使用
ALTER PROFILE DEFAULT LIMIT PASSWORD_REUSE_MAX 5后,用户修改密码时若旧密码哈希未存储够 5 条(例如之前未开启过该策略),首次修改会绕过重用检查。
真正困难的并非编写函数,而是验证它在所有用户、所有客户端(SQL*Plus、JDBC、OCI)以及所有字符集下都能稳定触发。建议在测试库中使用脚本批量测试 100 多种弱密码样本,这比仅阅读文档要可靠得多。
