1. 程式人生 > >從一個案例窺探ORACLE的PASSWORD_VERSIONS

從一個案例窺探ORACLE的PASSWORD_VERSIONS

如果 mar 出了 案例 acl 變化 width 問題 是什麽

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