標籤:建議 語義 伺服器 相容 pad 產生 最低版本 支援 檔案中
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、案例重演
- 在SQLNET.ALLOWED_LOGON_VERSION_SERVE=12時,為sys使用者佈建了密碼,因此sys賬戶的password_versions=11G,12C
- 這時用client version 11.2.0.1請求登陸,因為client version 11.2.0.1的認證協議版本為11(該版本小於11.2.0.3,並沒有打CPUOct2012補丁,因為認證協議版本為11),所以流程如紅線1所示:
- 然後手動將SQLNET.ALLOWED_LOGON_VERSION_SERVE改為8,但因為只是參數變化,並沒有重建密碼,因此該account的實際password仍然為11G,12C,所以請求登陸的流程如紅線2所示:
- 重建密碼。因為是在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