SSL 握手失敗 - 用戶端憑證錯誤

您正在查看 Apigee Edge 說明文件。
查看 Apigee X 說明文件
資訊

問題

用戶端應用程式收到 503 的 HTTP 狀態碼,以及訊息 "Service Unavailable" 做為對 API 要求的回應。在 UI 追蹤記錄中,您可以觀察到失敗 API 要求的目標要求流程中的 error.cause Received fatal alert: bad_certificate

如果您可以存取訊息處理器記錄檔,則會針對失敗的 API 要求,看到錯誤訊息為 Received fatal alert: bad_certificate。在訊息處理器與後端伺服器之間以傳輸層安全標準 (TLS) 設定的 2 種方法,您可以在進行 SSL 握手程序期間觀察到這個錯誤。

錯誤訊息

用戶端應用程式會取得以下回應代碼:

HTTP/1.1 503 Service Unavailable

此外,您可能會遇到以下錯誤訊息:

{
 "fault": {
    "faultstring":"The Service is temporarily unavailable",
    "detail":{
        "errorcode":"messaging.adaptors.http.flow.ServiceUnavailable"
    }
 }
}

Private Cloud 使用者會在訊息處理器記錄檔 /opt/apigee/var/log/edge-message-processor/system.log 中,看到特定 API 要求出現下列錯誤:

2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461 useCount=1 bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed, message: Received fatal alert: bad_certificate

可能原因

這個問題的可能原因如下:

原因 說明 適用的疑難排解操作說明
沒有用戶端憑證 目標伺服器目標端點中使用的 KeyStore 沒有任何用戶端憑證。 邊緣私人和公有雲使用者
憑證授權單位不符 訊息處理器 KeyStore 中的分葉憑證憑證授權單位 (憑證鏈中的第一個憑證) 與後端伺服器接受的任何憑證授權單位不符。 邊緣私人和公有雲使用者

常見診斷步驟

  1. 在 Edge UI 中啟用追蹤記錄功能,發出 API 呼叫,然後重現問題。
  2. 在 UI 追蹤記錄結果中,瀏覽每個階段,並判斷錯誤發生的位置。目標要求流程中可能會發生錯誤。
  3. 檢查顯示錯誤的流程,您應該觀察到錯誤,如下方範例追蹤記錄所示:

    alt_text

  4. 如上方螢幕截圖所示,error.cause error.cause
  5. 如果您是 Private Cloud 使用者,請按照以下說明操作:
    1. 如要取得失敗 API 要求的訊息 ID,您可以在追蹤記錄中以 AX 指定的階段判斷錯誤標頭「X-Apigee.Message-ID」的值。
    2. 請在訊息處理器記錄 /opt/apigee/var/log/edge-message-processor/system.log 中搜尋這個訊息 ID,然後判斷是否能找到關於該錯誤的更多資訊:
      2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name
      rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() :
      SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461 useCount=1
      bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed, message: Received fatal alert: bad_certificate
      2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name
      rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLInfo:
      KeyStore:java.security.KeyStore@52de60d9 KeyAlias:KeyAlias TrustStore:java.security.KeyStore@6ec45759
      2017-10-23 05:28:57,814 org:org-name env:env-name api:apiproxy-name
      rev:revision-number messageid:message_id NIOThread@0 ERROR ADAPTORS.HTTP.FLOW - RequestWriteListener.onException() :
      RequestWriteListener.onException(HTTPRequest@6071a73d)
      javax.net.ssl.SSLException: Received fatal alert: bad_certificate
      at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[na:1.8.0_101]
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666) ~[na:1.8.0_101]
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634) ~[na:1.8.0_101]
      at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800) ~[na:1.8.0_101]
      at com.apigee.nio.NIOSelector$SelectedIterator.findNext(NIOSelector.java:496) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na]
      at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:312) [nio-1.0.0.jar:na]
      at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:302) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na]
      at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na]
      at com.apigee.nio.handlers.NIOThread.run(NIOThread.java:59) [nio-1.0.0.jar:na]
      

      訊息處理器記錄包含錯誤 Received fatal alert: bad_certificate 的堆疊追蹤,但沒有任何其他資訊可指出這項問題的原因。

  6. 如要進一步調查這個問題,您必須使用 tcpdump 工具擷取 TCP/IP 封包。
    1. 如果您是 Private Cloud 使用者,可以在後端伺服器或訊息處理器中擷取 TCP/IP 封包。建議在後端伺服器上擷取憑證,因為封包已在後端伺服器上解密。
    2. 如果您是公開雲端使用者,請在後端伺服器上擷取 TCP/IP 封包。
    3. 決定好要擷取 TCP/IP 封包的位置後,請使用下列 tcpdump 指令擷取 TCP/IP 封包。
    4. tcpdump -i any -s 0 host <IP address> -w <File name>

      如果您在訊息處理器上接收 TCP/IP 封包,請在 tcpdump 指令中使用後端伺服器的公開 IP 位址。

      如果後端伺服器/訊息處理器有多個 IP 位址,您必須使用不同的 tcpdump 指令。如要進一步瞭解這項工具和這個指令的其他變數,請參閱 tcpdump

  7. 您可以使用 Wireshark 工具或您熟悉的類似工具分析 TCP/IP 封包。

以下說明如何使用 Wireshark 工具分析 TCP/IP 封包資料:

alt_text

  1. 上述 tcpdump 訊息中的訊息 #4 顯示訊息處理器 (來源) 將「Client Hello"」訊息傳送到後端伺服器 (目的地)。
  2. 訊息 #5 顯示後端伺服器已確認訊息處理器的 Client Hello 訊息。
  3. 後端伺服器會傳送「Server Hello」訊息及其憑證,然後要求用戶端在訊息 #7 中傳送憑證。
  4. 訊息處理器會完成憑證驗證,並在訊息 #8 中確認後端伺服器的 ServerHello 訊息。
  5. 訊息處理器將其憑證傳送至「訊息 #9」的後端伺服器。
  6. 後端伺服器會確認已收到訊息 #11 中的訊息處理器憑證。
  7. 不過,它會立即將「嚴重警報:錯誤憑證」傳送給訊息處理者 (訊息 #12)。這表示訊息處理器傳送的憑證有誤,因此後端伺服器的憑證驗證失敗。因此,SSL 握手失敗,連線將會關閉。


    alt_text

  8. 現在,我們來看看「郵件 #9」來檢查「訊息處理器」傳送的憑證內容:


    alt_text

  9. 如您所見,後端伺服器並未從用戶端取得任何憑證 (憑證長度:0)。因此,後端伺服器會傳送嚴重警示:憑證錯誤。
  10. 當用戶端為「訊息處理器」(以 Java 為基礎的程序) 時,通常就會發生此情況:
    1. 其 KeyStore 中沒有任何用戶端憑證,或者:
    2. 無法傳送用戶端憑證。如果系統找不到由後端伺服器可接受的憑證授權單位核發的憑證,就可能發生這種情況。 換句話說,如果用戶端分葉憑證的憑證授權單位 (即鏈結中的第一個憑證) 與後端伺服器接受的任何憑證授權單位不符,則訊息處理器就不會傳送憑證。

以下將分別說明這些原因。

原因:沒有用戶端憑證

診斷

在目標端點的「SSL 資訊」部分,如果 KeyStore 裡沒有任何憑證,或目標端點中使用的目標伺服器,就會發生這個錯誤。

請按照下列步驟判斷原因是否為:

  1. 請按照下列步驟操作,決定要在目標端點或特定 API Proxy 的目標伺服器中使用的 KeyStore:
    1. 透過目標端點或目標伺服器中的 SSLInfo 區段中的 Keystore 元素,取得 KeyStore 參照名稱。

      讓我們看看「目標端點設定」中的 SSLInfo 部分範例:

      <SSLInfo>
        <Enabled>true</Enabled>
        <ClientAuthEnabled>true</ClientAuthEnabled>
        <KeyStore>ref://myKeystoreRef</KeyStore>
        <KeyAlias>myKey</KeyAlias>
        <TrustStore>ref://myTrustStoreRef</TrustStore>
      </SSLInfo>
    2. 在上述範例中,KeyStore 參照名稱為「myKeystoreRef」
    3. 前往 Edge UI 並依序選取「API Proxy」->「Environment Configurations」。

      選取「References」分頁標籤,然後搜尋 KeyStore 參照名稱。請記下特定 KeyStore 參考資料「參考資料」欄中的名稱。這會是您的 KeyStore 名稱。


      alt_text

    4. 在上述範例中,您會發現 myKeystoreRef 具有「myKeystore」的參照。因此,KeyStore 名稱為 myKeystore。
  2. 使用 Edge UI 或列出 KeyStore API 的列出憑證,檢查這個 KeyStore 是否包含憑證。
  3. 如果 KeyStore 含有憑證,請移至「原因:憑證授權單位不相符」
  4. 如果 KeyStore 不包含任何憑證,因此訊息處理器不會傳送用戶端憑證。

解析度

  1. 確認已妥善且完整的用戶端憑證鏈結已上傳至訊息處理器中的特定 KeyStore。

原因:憑證授權單位不相符

一般來說,當伺服器要求用戶端傳送其憑證時,會指示一組可接受的核發者或憑證授權單位。如果訊息處理器 KeyStore 中的分葉憑證核發者/憑證授權單位 (也就是憑證鏈中的第一個憑證) 與後端伺服器接受的任何憑證授權單位不符,則訊息處理器 (屬於 Java 型程序) 就不會將憑證傳送至後端伺服器。

請按照下列步驟確認情況是否如此:

  1. 列出 KeyStore API 的憑證
  2. 使用取得 KeyStore API 的憑證,取得上方步驟 #1 取得的各項憑證詳細資料。
  3. 請記下 KeyStore 中儲存的分葉憑證核發者 (即憑證鏈中的第一個憑證)。

    節能綠葉憑證範例

    {
      "certInfo" : [ {
        "basicConstraints" : "CA:FALSE",
        "expiryDate" : 1578889324000,
        "isValid" : "Yes",
        "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com",
        "publicKey" : "RSA Public Key, 2048 bits",
        "serialNumber" : "65:00:00:00:d2:3e:12:d8:56:fa:e2:a9:69:00:06:00:00:00:d2",
        "sigAlgName" : "SHA256withRSA",
        "subject" : "CN=nonprod-api.mycompany.com, OU=ITS, O=MyCompany, L=MELBOURNE, ST=VIC, C=AU",
        "subjectAlternativeNames" : [ ],
        "validFrom" : 1484281324000,
        "version" : 3
      } ],
      "certName" : "nonprod-api.mycompany.com.key.pem-cert"
    }
    

    在上述範例中,核發者/憑證授權單位為 "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com"

  4. 使用下列其中一種技巧,判斷後端伺服器接受的發行者或憑證授權單位清單:

    技巧 #1:請使用下方的 openssl 指令:

    openssl s_client -host <backend server host name> -port <Backend port#> -cert <Client Certificate> -key <Client Private Key>
    

    在這個指令的輸出內容中,請參閱「Acceptable Client Certificate CA name」一節,如下所示:

    Acceptable client certificate CA names
    /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com
    /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com
    

    技巧 #2:檢查 TCP/IP 封包中的 Certificate Request 封包,後端伺服器會要求用戶端傳送其憑證:

    在上方顯示的 TCP/IP 封包範例中,Certificate Request 封包是 #7 訊息。請參閱「唯一名稱」一節,瞭解後端伺服器的「可接受的憑證授權單位」部分。

    alt_text

  5. 確認步驟 #3 中取得的憑證授權單位與步驟 #4 中取得的後端伺服器接受的核發者或憑證授權單位清單相符。如果不相符,訊息處理器就不會將用戶端憑證傳送至後端伺服器。

    在上述範例中,您可以發現訊息處理器的 KeyStore 中用戶端的分葉憑證核發者與任何後端伺服器的已接受的憑證授權單位不符。因此,訊息處理器不會將用戶端憑證傳送至後端伺服器。這會導致 SSL 握手失敗,後端伺服器會傳送「Fatal alert: bad_certificate」訊息。

解析度

  1. 確認核發者/憑證授權單位的憑證與用戶端節能綠葉憑證的核發者/憑證授權單位相符 (鏈結中的第一個憑證) 會儲存在後端伺服器的 Truststore 中。
  2. 在這份應對手冊所述的範例中,核發者 "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com" 的憑證已新增至後端伺服器的 Truststore,以便解決問題。

如果問題仍未解決,請參閱「必須收集診斷資訊」一文。

收集診斷資訊的必要性

如果按照上述操作說明操作,問題仍未能解決,請收集下列診斷資訊。請與 Apigee Edge 支援團隊聯絡並分享相關資訊:

  1. 如果您是公有雲使用者,請提供下列資訊:
    1. 機構名稱
    2. 環境名稱
    3. API Proxy 名稱
    4. 完成 curl 指令即可重現錯誤
    5. 顯示錯誤的追蹤檔
    6. 後端伺服器擷取的 TCP/IP 封包
  2. 如果您是私有雲使用者,請提供下列資訊:
    1. 發現完整錯誤訊息
    2. API Proxy 套裝組合
    3. 顯示錯誤的追蹤檔
    4. 訊息處理器記錄 /opt/apigee/var/log/edge-message-processor/logs/system.log
    5. 後端伺服器或訊息處理器上擷取的 TCP/IP 封包。
    6. 取得 KeyStore API 的憑證輸出內容。
  3. 詳細說明您曾在本教戰手冊中嘗試的章節,以及任何有助我們快速解決問題的深入分析。