כשלים בלחיצת יד של SSL - אישור לקוח פגום

כרגע מוצג התיעוד של Apigee Edge.
כניסה למסמכי התיעוד של Apigee X.
מידע

תיאור הבעיה

אפליקציית הלקוח מקבלת קוד סטטוס HTTP 503 עם ההודעה "Service Unavailable" בתגובה לבקשת API. במעקב בממשק המשתמש, תוכלו לראות ש-error.cause היא Received fatal alert: bad_certificate בתהליך הבקשה ביעד של בקשת ה-API שנכשלה.

אם יש לך גישה ליומנים של מעבד ההודעות, תופיע הודעת השגיאה Received fatal alert: bad_certificate על בקשת ה-API שנכשלה. השגיאה הזו מזוהה במהלך תהליך לחיצת היד של SSL בין מעבד ההודעות לבין השרת העורפי בהגדרת TLS דו-כיוונית.

הודעת שגיאה

אפליקציית הלקוח מקבלת את קוד התגובה הבא:

HTTP/1.1 503 Service Unavailable

בנוסף, עשויה להופיע הודעת השגיאה הבאה:

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

משתמשי ענן פרטי יראו את השגיאה הבאה לבקשת ה-API הספציפית ביומנים של מעבד ההודעות /opt/apigee/var/log/edge-message-processor/system.log:

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 שנעשה בו שימוש בנקודת הקצה של היעד של שרת היעד אין אישור לקוח. משתמשי Edge פרטיים וציבוריים בענן
חוסר התאמה של רשות האישורים רשות האישורים של אישור העלה (האישור הראשון בשרשרת האישורים) ב-Keystore של מעבד ההודעות לא תואמת לאף אחת מרשויות האישורים שנתמכות על ידי שרת הקצה העורפי. משתמשי Edge פרטיים וציבוריים בענן

שלבים נפוצים לאבחון

  1. הפעלת מעקב בממשק המשתמש של Edge, ביצוע הקריאה ל-API ושחזור הבעיה.
  2. בתוצאות המעקב של ממשק המשתמש, מנווטים בין כל שלב וקובעים איפה אירעה השגיאה. השגיאה הייתה מתרחשת בתהליך של יעד הבקשות.
  3. בודקים את הזרימה שמציגה את השגיאה. השגיאה אמורה להופיע בדוגמה הבאה למעקב:

    alt_text

  4. כמו שאפשר לראות בצילום המסך שלמעלה, הערך של error.cause הוא error.cause .
  5. אם אתם משתמשים בענן פרטי, עליכם לפעול לפי ההוראות הבאות:
    1. כדי למצוא את מזהה ההודעה של בקשת ה-API שנכשלה, צריך לקבוע את הערך של כותרת השגיאה 'X-Apigee.Message-ID' בשלב שצוין על ידי AX במעקב.
    2. צריך לחפש את מזהה ההודעה הזה ביומן של מעבד ההודעות /opt/apigee/var/log/edge-message-processor/system.log ולבדוק אם אפשר למצוא מידע נוסף על השגיאה:
      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. כדי לבדוק את הבעיה לעומק, צריך לתעד חבילות TCP/IP באמצעות הכלי tcpdump.
    1. אם אתם משתמשים בענן פרטי, תוכלו לתעד את חבילות ה-TCP/IP בשרת הקצה העורפי או במעבד ההודעות. עדיף לתעד אותן בשרת הקצה העורפי בזמן שהחבילות מפוענחות בשרת הקצה העורפי.
    2. אם אתם משתמשים ב-Public Cloud, עליכם לתעד את חבילות ה-TCP/IP בשרת הקצה העורפי.
    3. לאחר שתחליטו היכן תרצו לתעד מנות TCP/IP, השתמשו בפקודה tcpdump שלמטה כדי לתעד חבילות TCP/IP.
    4. tcpdump -i any -s 0 host <IP address> -w <File name>

      אם אתם משתמשים בחבילות ה-TCP/IP במעבד ההודעות, עליכם להשתמש בכתובת ה-IP הציבורית של שרת הקצה העורפי בפקודה tcpdump.

      אם יש כמה כתובות IP לשרת הקצה העורפי או למעבד ההודעות, צריך להשתמש בפקודת tcpdump אחרת. ב-tcpdump אפשר לקרוא מידע נוסף על הכלי הזה ועל וריאנטים אחרים של הפקודה הזו.

  7. נתח את חבילות ה-TCP/IP באמצעות כלי Wireshark או כלי דומה שאתה מכיר.

הנה ניתוח של נתונים לדוגמה של מנות TCP/IP באמצעות הכלי Wireshark:

alt_text

  1. הודעה מס' 4 ב-tcpdump שלמעלה מראה שמעבד ההודעות (מקור) שלח הודעת "Client Hello" לשרת הקצה העורפי (יעד).
  2. הודעה מס' 5 מציינת ששרת הקצה העורפי מאשר את הודעת Client Hello שהתקבלה ממעבד ההודעות.
  3. השרת העורפי שולח את ההודעה 'Server Hello' יחד עם האישור שלו, ואז מבקש מהלקוח לשלוח את האישור שלו בהודעה מס' 7.
  4. מעבד ההודעות משלים את אימות האישור ומאשר את ההודעה ServerHello של השרת העורפי בהודעה מס' 8.
  5. מעבד ההודעות שולח את האישור שלו לשרת הקצה העורפי בהודעה מס' 9.
  6. שרת הקצה העורפי מאשר שקיבל את האישור ממעבד ההודעות בהודעה מס' 11.
  7. עם זאת, היא שולחת באופן מיידי התראה חמורה: אישור פגום למעבד ההודעות (הודעה מס' 12). זה סימן שהאישור שנשלח על ידי מעבד ההודעות היה פגום ולכן אימות האישור נכשל בשרת הקצה העורפי. כתוצאה מכך, לחיצת היד של SSL נכשלה והחיבור ייסגר.


    alt_text

  8. נביט בהודעה מס' 9 של תוכן האישור שנשלח על ידי מעבד ההודעות:


    alt_text

  9. כפי שאפשר לראות, שרת הקצה העורפי לא קיבל אישור מהלקוח (Certificate Length: 0). לכן, שרת הקצה העורפי שולח את ההתראה חמורה: אישור שגוי.
  10. לרוב זה קורה כשהלקוח, כלומר מעבד ההודעות (תהליך מבוסס Java):
    1. לא מכיל אישור לקוח ב-KeyStore, או
    2. אין אפשרות לשלוח אישור לקוח. מצב כזה יכול לקרות אם הוא לא מוצא אישור שהונפק על ידי אחת מרשויות האישורים המקובלות בשרת הקצה העורפי. כלומר, אם רשות האישורים של אישור העלה של הלקוח (כלומר, האישור הראשון בשרשרת) לא תואמת לאף אחת מרשויות האישורים המקובלות של השרת העורפי, מעבד ההודעות לא ישלח את האישור.

נבחן כל אחת מהסיבות בנפרד, כפי שמפורט בהמשך.

הסיבה: אין אישור לקוח

אבחון

אם לא מצוין ב-Keystore אישור בקטע SSL Info של נקודת הקצה של היעד, או בשרת היעד שנעשה בו שימוש בנקודת הקצה של היעד, זו הסיבה לשגיאה.

כדי לבדוק אם זו הסיבה:

  1. כדי לקבוע איזה מאגר מפתחות נמצא בשימוש בנקודת הקצה של היעד או בשרת היעד עבור שרת ה-Proxy הספציפי ל-API, יש לפעול לפי השלבים הבאים:
    1. מקבלים את שם ההפניה של Keystore מהאלמנט Keystore בקטע SSLInfo ב-Target Endpoint או ב-Target Server.

      נבחן קטע לדוגמה של SSLInfo בהגדרה של נקודת קצה (Endpoint):

      <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 Proxies -> Environment Configuration (הגדרות סביבה).

      בוחרים בכרטיסייה References (קובצי עזר) ומחפשים את שם ההפניה של Keystore. לרשום למטה את השם בעמודה Reference (הפניה) של הפניה ספציפית מ-Keystore. זה יהיה השם שלך ב-Keystore.


      alt_text

    4. בדוגמה שלמעלה אפשר לראות ש-myKeystoreRef מכיל את ההפניה ל-"myKeystore". לכן, שם ה-Keystore הוא myKeystore.
  2. בודקים אם ה-Keystore הזה מכיל את האישור באמצעות ממשק המשתמש של Edge או באמצעות List certs for keystore API.
  3. אם ה-Keystore מכיל אישורים, צריך לעבור אל הסיבה: חוסר התאמה בין רשויות אישורים.
  4. אם ה-Keystore לא מכיל אישור, זו הסיבה לכך שאישור הלקוח לא נשלח על ידי מעבד ההודעות.

רזולוציה

  1. יש לוודא ששרשרת אישורי הלקוח התקינה והמלאה מועלה למאגר המפתחות הספציפי במעבד ההודעות.

הסיבה: חוסר התאמה של רשות האישורים

באופן כללי, כשהשרת מבקש מהלקוח לשלוח את האישור שלו, הוא מציין את קבוצת המנפיקים או רשויות האישורים הקבילות. אם הרשות המנפיקה/האישור של אישור העלה (כלומר, האישור הראשון בשרשרת האישורים) ב'מאגר המפתחות' של מעבד ההודעות לא תואמת לאף אחת מרשויות האישורים שנתמכות על ידי שרת הקצה העורפי, מעבד ההודעות (שהוא תהליך מבוסס Java) לא ישלח את האישור לשרת הקצה העורפי.

כדי לבדוק אם זה המצב, פועלים לפי השלבים הבאים:

  1. רשימת אישורים ל-Keystore API
  2. אתם יכולים לקבל את הפרטים על כל אישור שהתקבל בשלב 1 למעלה באמצעות Get cert for keystore API.
  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: משתמשים בפקודה opensl שמופיעה בהמשך:

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

    עיין בקטע "שמות CA מקובלים של אישורי לקוח" בפלט של הפקודה הזו, כפי שמוצג בהמשך:

    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: בודקים את החבילה Certificate Request בחבילות TCP/IP, שבהן שרת הקצה העורפי מבקש מהלקוח לשלוח את האישור שלו:

    במנות ה-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. אם אתם משתמשים ב-Public Cloud, עליכם לספק את הפרטים הבאים:
    1. שם הארגון
    2. שם הסביבה
    3. שם שרת proxy ל-API
    4. השלמה של פקודת curl לשחזור השגיאה
    5. קובץ מעקב שמציג את השגיאה
    6. מנות TCP/IP שנקלטו בשרת הקצה העורפי
  2. אם אתם משתמשים בענן פרטי, עליכם לספק את הפרטים הבאים:
    1. זוהתה הודעת השגיאה המלאה
    2. חבילת שרת proxy ל-API
    3. קובץ מעקב שמציג את השגיאה
    4. יומני מעבד ההודעות /opt/apigee/var/log/edge-message-processor/logs/system.log
    5. חבילות TCP/IP שנקלטו בשרת הקצה העורפי או במעבד ההודעות.
    6. פלט של Get cert for keystore API.
  3. פרטים על הקטעים ב-Playbook הזה שניסיתם ותובנות אחרות שיעזרו לנו לפתור את הבעיה במהירות.