oracle 19c密码策略生效需三重验证:查profile绑定的password_verify_function是否非空、对应函数是否存在且valid、是否授予public执行权限;failed_login_attempts与password_lock_time必须同条alter profile语句设置;多租户下须在目标pdb中操作。

Oracle 19c 默认不启用任何密码强度校验,即使执行了 utlpwdmg.sql,也必须显式绑定函数到 profile 并验证状态,否则 ALTER USER IDENTIFIED BY 仍允许设 “123” 或用户名本身。
怎么确认 PASSWORD_VERIFY_FUNCTION 是否真生效
别信脚本执行成功,直接查数据字典才是唯一可靠方式:
- 先查 profile 绑定:
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 = 'ORA12C_VERIFY_FUNCTION' AND object_type = 'FUNCTION';—— 必须是SYS下且status = 'VALID' - 最后确认权限:
SELECT grantee FROM dba_tab_privs WHERE table_name = 'ORA12C_VERIFY_FUNCTION' AND privilege = 'EXECUTE' AND grantee = 'PUBLIC';—— 缺少这条授权,非 SYS 用户改密时会静默失败,只报ORA-28003不提示原因
自定义 verify_function 的三个硬性签名要求
手写函数时错一个点,编译能过、绑定能成,但实际调用必失败:
- 函数名任意,但签名必须严格为:
FUNCTION my_verify (username IN VARCHAR2, password IN VARCHAR2, old_password IN VARCHAR2) RETURN BOOLEAN—— 多一个参数、少一个IN、返回NUMBER或VARCHAR2都不行 - 函数体禁止任何副作用操作:
INSERT/UPDATE/DBMS_OUTPUT.PUT_LINE会导致运行时报ORA-28003且无具体错误指向 - 开头建议加空值防护:
IF password IS NULL THEN RETURN FALSE; END IF;,避免空密码绕过校验
FAILED_LOGIN_ATTEMPTS 和 PASSWORD_LOCK_TIME 必须同语句设置
这两个参数是防暴力破解的组合技,拆开配等于白配:
-
FAILED_LOGIN_ATTEMPTS不是数据库参数,ALTER SYSTEM SET failed_login_attempts = 3必报ORA-02095;只能通过ALTER PROFILE DEFAULT LIMIT设置 - 单独设
FAILED_LOGIN_ATTEMPTS = 3而不设PASSWORD_LOCK_TIME,账户锁死后将永久卡在ORA-28000—— 因为默认PASSWORD_LOCK_TIME是UNLIMITED - 推荐写法:
ALTER PROFILE DEFAULT LIMIT FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 1/24;(锁 1 小时),单位是“天”,1/24合法,60(以为是分钟)会被忽略或报错 - 两个参数必须出现在同一条
ALTER PROFILE语句中;分两次执行,中间被其他 DDL 覆盖就失效
多租户环境下 PROFILE 修改只对当前 PDB 生效
在 CDB 中执行 ALTER PROFILE,不会自动同步到所有 PDB,这是最容易被忽略的隔离点:
- 先确认容器:
SHOW CON_NAME;,如果不是目标 PDB,必须先执行:ALTER SESSION SET CONTAINER = QMS; - 查用户是否在该 PDB:
SELECT username, profile FROM dba_users WHERE oracle_maintained = 'N';——dba_users视图只返回当前容器中的用户 - 改完后立刻验证:
SELECT resource_name, limit FROM dba_profiles WHERE profile = 'DEFAULT' AND resource_name IN ('PASSWORD_VERIFY_FUNCTION', 'FAILED_LOGIN_ATTEMPTS'); - 已有用户的
expiry_date不会因 PROFILE 修改自动更新;要重算,必须让其改一次密码(哪怕用相同值:ALTER USER scott IDENTIFIED BY scott REPLACE scott;)











