1、环境说明

ORACLE 客户端版本

11.2.0.1

ORACLE 服务端版本

12.2.0.1

2、异常现象

客户端(下文也称为Cp)访问服务端(Sp),报了一个错误:

Figure 1

以错误码为关键字在网上查找原因,有网友建议把服务器的sqlnet.ora文件中的SQLNET.ALLOWED_LOGON_VERSION_SERVER参数 和 SQLNET.ALLOWED_LOGON_VERSION_CLIENT参数改为8(原值为12)。如下图所示:

Figure 2

改过之后重新连接,糟糕,出现了新的错误:

Figure 3

可是我从其它的客户端(后来发现这些客户端版本均高于11.2.0.1)连接该Sp均没有问题。我以为是不是有什么后台程序会把输入的所有小写强制转成大写,于是我将账户密码从sys修改为SYS,然后再连接:

Figure 4

成功了。从现象上来看,似乎真的就是大小写的关系。可是真的是的吗?我现在将密码从SYS改回sys,然后再连接:

Figure 5

这回用sys作为密码登陆,也成功了。看来真正的原因,不是什么后台程序强制转换了大小写。那究竟是什么原因呢?

3、原理解释

其实,从现象上来看,变化最初是在设置了

SQLNET.ALLOWED_LOGON_VERSION_CLIENT

和SQLNET.ALLOWED_LOGON_VERSION_SERVER两个参数后产生的。那这两个参数到底起什么作用呢?

先看一下SQLNET.ALLOWED_LOGON_VERSION_CLIENT在官方文档中的说明:

Figure 6

这个参数是12C新引进的参数。它表示Cp在向Sp发送认证(authentication)申请时,所使用的最低版本的认证协议。注意此处的认证协议版本并不等同于Oracle Database的版本。那不同的认证协议版本主要区别在哪儿呢?除了协议语义上的区别,在我看来,最重要的区别在于不同认证协议的版本对应着不同的database version,而不同的database version则可能使用不同的hash算法对密码进行加密。不同的hash算法就是不同的password_version,这个可以从dba_users字典表的password_versions字段中得到说明:

Figure 7

Oracle在存储每个account的密码时,并非是明文存储,而是会将明文进行哈希加密存储,哈希加密算法即为该密码的version,即password_version。从上图Figure 7中可知,password_version实际上表示是同版本(并非完全一致,见最后的附表)的database 所提供的hash算法,例如password_version 10g就表示database 10g所提供的hash算法。如果Oracle所有的新版本都只使用新版本所特有的hash算法,那么一些较早的客户端因为还没有这些hash算法,就没法通过hash算法得到hash值,也就没法让服务器去验证这些hash值。为了解决兼容性的问题,Oracle会同时用多种hash算法(即password_version)对密码进行运算,并将多个运算结果均保留下来。在低版本客户端访问高版本的服务器时,低版本的客户端可以通报自己使用的认证协议以及使用该协议对应的hash算法所得到的密码hash值,服务器根据认证协议去查看是否存储了该协议对应的hash算法的hash值,如果存在,就比对两个hash值是否一致;如果不存在或两个hash值不一致,就报错。其流程图大致如下所示(仅代表自己的理解):

在上述密码认证流程图中,标红的子流程——"判断该账户的password_versions中是否包含client version",有一个疑问:account有哪些password version,是由什么决定的呢?这就引出了另一个参数:SQLNET.ALLOWED_LOGON_VERSION_SERVER。

关于这个参数的作用,它介绍了为这个参数设置不同的值所带来的影响,主要是对PASSWORD_VERSIONS的影响。最后附带了一张表,详细了列出了SQLNET.ALLOWED_LOGON_VERSION_SERVER设置不同值,所对应的password_versions。也说明了如果要与设置成当前值的12C数据库进行密码认证,所支持的client version。从上图可以看出,即使SQLNET.ALLOWED_LOGON_VERSION_SERVER设置为8,但生成的最低版本的password version也是10G。因此也说明,8I,9I的客户端因为没法理解10G的哈希函数,也就没法完成登陆认证。关于客户端到服务器端相互之间的兼容性如下表:

4、案例重演

  1. 在SQLNET.ALLOWED_LOGON_VERSION_SERVE=12时,为sys用户设置了密码,因此sys账户的password_versions=11G,12C

  2. 这时用client version 11.2.0.1请求登陆,因为client version 11.2.0.1的认证协议版本为11(该版本小于11.2.0.3,并没有打CPUOct2012补丁,因为认证协议版本为11),所以流程如红线1所示:

  3. 然后手动将SQLNET.ALLOWED_LOGON_VERSION_SERVE改为8,但因为只是参数变化,并没有重建密码,因此该account的实际password仍然为11G,12C,所以请求登陆的流程如红线2所示:

  4. 重新生成密码。因为是在SQLNET.ALLOWED_LOGON_VERSION_SERVE=8的情况下生成的密码,因此该account所对应的password_versions=10G,11G,12C,如下图所示:

    而该password_versions是支持client version 11.2.0.1密码认证的,所以请求登陆的流程如红线3所示:

5、认证协议版本、database版本与password版本之间的关系

如下表:

从一个案例窥探ORACLE的PASSWORD_VERSIONS的更多相关文章

  1. 通过一个案例彻底读懂10046 trace--字节级深入破解

    转载请注明出处:http://blog.csdn.net/guoyjoe/article/details/37840583 2014.7.23晚20:30 Oracle support组猫大师分享&l ...

  2. 案例:Oracle报错ASM磁盘组不存在或没有mount

    案例:Oracle报错ASM磁盘组不存在或没有mount 环境:RHEL 6.5 + Oracle Standby RAC 11.2.0.4 我做Standby RAC实验时,在恢复控制文件时,报错无 ...

  3. Vue一个案例引发「内容分发slot」的最全总结

    今天我们继续来说说 Vue,目前一直在自学 Vue 然后也开始做一个项目实战,我一直认为在实战中去发现问题然后解决问题的学习方式是最好的,所以我在学习一些 Vue 的理论之后,就开始自己利用业余时间做 ...

  4. Vue一个案例引发的递归组件的使用

    今天我们继续使用 Vue 的撸我们的实战项目,只有在实战中我们才会领悟更多,光纸上谈兵然并卵,继上篇我们的<Vue一个案例引发的动态组件与全局事件绑定总结> 之后,今天来聊一聊我们如何在项 ...

  5. 【权限设计】一个案例,三个角色,简单说下B端产品的权限设计

    入行以来也接触过一些B端产品,这些产品之中权限管理是重中之重,权限管理不仅仅是整个系统的一个小小的模块,它一直贯穿整个系统,从登陆到操作到最后的登出.说它相当的复杂真不为过. 对于权限,如果从控制力来 ...

  6. urlretrieve关于循环下载的一个案例

    # -*- coding: cp936 -*- #python 27 #xiaodeng #urlretrieve关于循环下载的一个案例 import urllib def down_list(sto ...

  7. sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)

    sql server 关于表中只增标识问题   由于我们系统时间用的过长,数据量大,设计是采用自增ID 我们插入数据的时候把ID也写进去,我们可以采用 关闭和开启自增标识 没有关闭的时候 ,提示一下错 ...

  8. 从零写一个兼容MySQL/Oracle的Proxy中件间(一)《初识Oracle的通信协议》

    0.前言 MySQL由于开源的原因,有各式各样的中件间Proxy ,极大的丰富了做高可用或迁移的方案,习惯了MySQL生态圈的灵活和便利,Oracle官方不开源代码和协议,没有中间件proxy,显得很 ...

  9. 作为一个新手的Oracle(DBA)学习笔记【转】

    一.Oracle的使用 1).启动 *DQL:数据查询语言 *DML:数据操作语言 *DDL:数据定义语言 DCL:数据控制语言 TPL:事务处理语言 CCL:指针控制语言 1.登录 Win+R—cm ...

随机推荐

  1. python开发应用之-时间戳

    golang 获取时间戳用time.Now().Unix(),格式化时间用t.Format,解析时间用time.Parse package main import ( "fmt" ...

  2. 101 More Security Best Practices for Kubernetes

    https://rancher.com/blog/2019/2019-01-17-101-more-kubernetes-security-best-practices/ The CNCF recen ...

  3. if语句的嵌套:从键盘输入3个实数,利用条件表达式求其最大者。

    #include<stdio.h>void main(){ float a,b,c,max; scanf("%f%f%f",&a,&b,&c); ...

  4. php for循环遍历索引数组

    遍历二字,从字面解释就是一个接一个全读访问一次,显示出来. 因为for循环是一个单纯的计数型循环,而索引数组的下标为整型的数值.因此,我们可以通过for循环来遍历索引数组. 我们知道索引数组下标为整型 ...

  5. solidworks 学习 (一)

    螺丝刀建模

  6. 持续集成学习8 jenkins权限控制

    一.总体配置 1.系统管理---> Configure Global Security 2.配置基于角色授权 创建角色 ----> 分配角色 代表着所有以dev-开头的 job全部都分配给 ...

  7. web大附件上传,支持断点续传

    一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输. ...

  8. BZOJ 1034: [ZJOI2008]泡泡堂BNB 贪心+排序

    比较神奇的贪心 有点类似于田忌赛马. 如果我方最弱强于对面最弱,则直接最弱pk最弱. 如果我方最强强于对面最强,那么直接最强间pk. 否则,试着用我方最弱 pk 对方最强,看是否能打成平手. code ...

  9. 2-开发共享版APP(接入指南)-设备接入说明:快速接入

    https://www.cnblogs.com/yangfengwu/p/11249674.html 该APP安装包下载链接: http://www.mnif.cn/appapk/IotDevelop ...

  10. 【转】Java 8新特性(四):新的时间和日期API

    Java 8另一个新增的重要特性就是引入了新的时间和日期API,它们被包含在java.time包中.借助新的时间和日期API可以以更简洁的方法处理时间和日期. 在介绍本篇文章内容之前,我们先来讨论Ja ...