Oracle 11g起DBA_USERS.PASSWORD字段始终返回NULL,因Oracle主动弃用该兼容性字段,将哈希值移至SYS.USER$表的SPARE4(SHA-1+salt)或SPARE6(SHA-2-512)字段存储,且仅限SYS用户访问。
oracle 11g 起,dba_users.password 字段已失效(始终返回 null),真正存储哈希值的位置是 sys.user$ 表的 password 或 spare4 字段——但直接查它既不安全,也不一定能拿到可用值。
为什么 DBA_USERS.PASSWORD 查不到东西?
从 Oracle 10gR2 开始,DBA_USERS.PASSWORD 就被标记为兼容性字段;到 11g,它彻底退化为只读空值。这不是 bug,而是 Oracle 主动弃用该字段,把哈希值下沉到更底层、受保护更强的基表中。你执行:
SELECT username, password FROM dba_users WHERE username = 'SCOTT';
结果一定是 NULL。硬要查,得切到 SYS 用户并访问 USER$,但这不是常规操作路径。
查 USER$ 表前必须确认三件事
- 你当前是以
SYS或具备SELECT ANY DICTIONARY权限的用户连接——普通 DBA 角色默认无权访问SYS.USER$,否则报ORA-01031: insufficient privileges -
USER$.PASSWORD字段只在 9i–10g 存 DES 哈希;11g+ 主要用USER$.SPARE4(SHA-1 + salt)或USER$.SPARE6(SHA-2-512,12.2+) - 即使能查,返回值形如
S:8A7F...C3E2或T:9B2D...A1F8,前面的S:/T:是算法标识符,后面才是有效哈希串,不能整字段拿来比对
Java 验证时怎么比对哈希值?别拼错顺序和编码
常见失败原因是:以为哈希输入只是密码本身。实际 Oracle 11g+ 的 SHA-1 哈希输入是 用户名大写 + 明文密码(如 SCOTT + tiger → TIGERtiger),且必须用 US_ASCII 编码字节流,不是 UTF-8。
关键点:
- 用户名转大写必须用
username.toUpperCase(Locale.US),不用Locale.getDefault(),避免土耳其语等 locale 下i→İ导致错误 - 拼接后调
getBytes(StandardCharsets.US_ASCII),不是UTF_8;含中文或 emoji 时,UTF-8 多字节会破坏哈希一致性 - 哈希输出是 20 字节二进制,需逐字节转小写十六进制:
String.format("%02x", b);别用Hex.encodeHexString()(大小写不可控,依赖外部包) - 比对时只取
USER$.SPARE4值去掉S:后的 40 位,全小写,长度严格为 40
生产环境里,真有必要查哈希吗?
绝大多数场景下,不需要。哈希值不可逆、不可迁移、无法用于登录验证(Oracle 内部校验走完整认证栈,不只是比哈希),批量导出还违反等保 2.0 第 8.1.4 条“防止未授权访问敏感信息”。如果目标是同步密码,用 ALTER USER ... IDENTIFIED BY VALUES 'xxx' 复用已有哈希更安全;如果目标是审计默认密码,应查 USER$.SPARE4 并与已知哈希库比对,而不是试图“查看密码”。真正容易被忽略的是:哈希值本身不是凭证,它只是认证链中一个中间产物,脱离 Oracle 实例上下文毫无意义。


















