当你用老版本的Oracle客户端(比如11g)连接新版本的数据库(比如12c R2)时,经常会遇到这个让人头疼的错误:"ORA-28040: 没有匹配的验证协议"。这就像你拿着老式钥匙去开最新款的智能锁,虽然钥匙孔看起来差不多,但内部的认证机制已经升级了。
我去年在给某银行做系统迁移时就遇到过这种情况。他们有个核心业务系统还在用11g客户端,但数据库已经升级到12c R2。每次连接都会报这个错误,搞得整个项目组都很焦虑。其实问题的根源在于Oracle在12c中引入了新的密码验证协议,而老客户端根本不认识这些新协议。
关键点在于SQLNET.ALLOWED_LOGON_VERSION系列参数。在12c之前,这个参数是统一的,但从12c开始被拆分为两个:
SQLNET.ALLOWED_LOGON_VERSION_SERVER:控制哪些版本的客户端可以连接本服务器SQLNET.ALLOWED_LOGON_VERSION_CLIENT:控制本服务器可以连接哪些版本的其他数据库首先找到数据库服务器上的sqlnet.ora文件。这个文件通常位于:
code复制$ORACLE_HOME/network/admin/sqlnet.ora
如果是Windows环境,路径类似:
code复制D:\app\oracle\product\12.1.0\dbhome_1\NETWORK\ADMIN\sqlnet.ora
在文件中添加或修改以下两行:
code复制SQLNET.ALLOWED_LOGON_VERSION_SERVER=8
SQLNET.ALLOWED_LOGON_VERSION_CLIENT=8
这里的数字8代表允许最低8i版本的客户端连接。如果你需要支持更老的客户端,可以设置为更小的数字,但会降低安全性。
修改后不需要重启整个数据库,只需要重启监听服务:
bash复制lsnrctl stop
lsnrctl start
在RAC环境中,很多人会犯一个常见错误:把配置加到Grid用户的sqlnet.ora里。实际上,正确的做法是修改Oracle用户的配置文件:
$ORACLE_HOME环境变量指向的是数据库软件目录,不是Grid目录$ORACLE_HOME/network/admin/sqlnet.ora文件我遇到过不少DBA在RAC上折腾半天没效果,就是因为改错了文件位置。记住:Grid的监听只负责转发请求,真正的认证还是在数据库层面处理。
这些参数的数字值对应Oracle的版本:
设置为8意味着允许从8i到最新版本的所有客户端连接。但要注意,设置过低会降低安全性。
在12c之前使用的是SQLNET.ALLOWED_LOGON_VERSION,但这个参数已经废弃。如果你看到有人建议用这个参数,虽然能解决问题,但会在alert日志里不断产生警告信息。正确的做法是使用新的_SERVER和_CLIENT参数。
有些精简安装的Oracle可能没有sqlnet.ora文件。这时你需要手动创建,权限设置为644即可。我建议至少包含以下基本配置:
code复制SQLNET.ALLOWED_LOGON_VERSION_SERVER=11
SQLNET.ALLOWED_LOGON_VERSION_CLIENT=11
NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)
在开发、测试、生产多套环境时,经常出现改了一个环境忘记改其他环境的情况。建议把这些配置纳入你的配置管理工具(如Ansible、Chef)中统一管理。
虽然设置为8可以最大化兼容性,但会允许使用较弱的加密算法。如果安全要求高,应该尽量使用较高的版本号,必要时升级客户端而不是降低安全标准。
修改后如何确认问题真的解决了?我通常用三步验证法:
sql复制SELECT username, password_versions FROM dba_users;
这个视图会显示每个用户支持的密码版本。修改参数后,老客户端用户的password_versions应该会包含兼容的版本。
虽然修改参数可以快速解决问题,但从长远来看,我建议:
我在金融行业的一个客户那里就吃过亏,他们为了快速解决问题把所有环境都设为8,结果三年后安全审计时被查出使用了不安全的加密算法,不得不紧急升级十几个系统。
有时除了ORA-28040,你可能还会遇到:
这些错误可能与验证协议问题同时出现。我的经验是:先解决验证协议问题,再处理其他错误。因为如果协议不匹配,其他认证流程根本不会执行。
最后提醒一点:修改这些安全相关参数前,一定要做好备份,并在非高峰时段操作。有次我在交易时段修改配置,不小心把参数值设错了,导致所有应用突然无法连接,差点造成重大事故。