ไม่พบ Trust Anchor สำหรับการเชื่อมต่อ Android SSL


185

ฉันกำลังพยายามเชื่อมต่อกับกล่อง IIS6 ที่เรียกใช้ใบรับรอง SSL ของ godaddy 256bit และฉันได้รับข้อผิดพลาด:

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

เคยพยายามระบุว่าอะไรเป็นสาเหตุของสิ่งนั้น แต่การวาดช่องว่างตอนนี้

นี่คือวิธีที่ฉันกำลังเชื่อมต่อ:

HttpsURLConnection conn;              
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream()); 

คำตอบ:


78

ทางออกของ @Chrispix นั้นอันตราย! การเชื่อถือใบรับรองทั้งหมดจะทำให้ใครก็ตามสามารถโจมตีชายกลาง! เพียงแค่ส่งใบรับรองใด ๆ ให้กับลูกค้าและมันจะยอมรับมัน!

เพิ่มใบรับรองของคุณไปยังผู้จัดการความเชื่อถือที่กำหนดเองเช่นที่อธิบายไว้ในโพสต์นี้: ความไว้วางใจใบรับรองทั้งหมดโดยใช้ HttpClient ผ่าน HTTPS

แม้ว่ามันจะซับซ้อนกว่านี้เล็กน้อยในการสร้างการเชื่อมต่อที่ปลอดภัยด้วยใบรับรองที่กำหนดเอง แต่มันจะทำให้คุณต้องการความปลอดภัยในการเข้ารหัส SSL โดยไม่ต้องเสี่ยงอันตรายจากการโจมตีของคนกลาง!


1
สิ่งนี้ใช้ได้สำหรับการทำงานกับใบรับรองที่สร้างขึ้นเอง แต่สำหรับหนึ่ง (เช่น OP) ซึ่งมีห่วงโซ่ที่ถูกต้องกลับไปที่รูท CA มันเป็นเพียงวิธีแก้ปัญหาสำหรับเซิร์ฟเวอร์ที่กำหนดค่าไม่ดี - ดูคำตอบของฉัน
Stevie

4
@Stevie การยอมรับใบรับรอง EVERY เป็นเพียงตัวเลือกสำหรับหลักฐานการทดสอบแนวคิดซึ่งการเชื่อมต่อ SSL ไม่ใช่ส่วนที่คุณต้องการทดสอบ มิฉะนั้นคุณไม่จำเป็นต้องใช้ SSL หากคุณยอมรับทุกใบรับรองเนื่องจากการเชื่อมต่อไม่ปลอดภัย!
Matthias B

1
อาฉันขอโทษฉันคิดว่ามีความเข้าใจผิด - ฉันยอมรับอย่างสมบูรณ์ว่าไม่มีใครควรยอมรับใบรับรองทุกใบ! :) ความคิดเห็นของฉันเกี่ยวกับย่อหน้าที่ 2 ของคุณ - ข้อเสนอแนะในการใช้ผู้จัดการความเชื่อถือที่กำหนดเอง - ซึ่ง IMHO ควรเป็นวิธีการแก้ปัญหาสุดท้ายแทนที่จะเป็นวิธีแก้ปัญหาที่แนะนำ
Stevie

2
Jut a head up .. ฉันลบ 'solution' ฉันวางเป็น work-around เพื่อไม่ให้เกิดปัญหามากขึ้นเนื่องจากคนไม่เห็นว่าเป็น 'งานชั่วคราว'
Chrispix

7
@Chrispix คุณไม่ควรลบการแก้ไขบางส่วนออกไปมันก็ดีสำหรับจุดประสงค์ในการทดสอบเท่านั้น
Hugo Allexis Cardona

224

ตรงกันข้ามกับคำตอบที่ยอมรับคุณไม่จำเป็นต้องมีผู้จัดการความเชื่อถือที่กำหนดเองคุณต้องแก้ไขการกำหนดค่าเซิร์ฟเวอร์ของคุณ!

ฉันพบปัญหาเดียวกันขณะเชื่อมต่อกับเซิร์ฟเวอร์ Apache ที่มีใบรับรอง dynadot / alphassl ที่ติดตั้งไม่ถูกต้อง ฉันกำลังเชื่อมต่อโดยใช้ HttpsUrlConnection (Java / Android) ซึ่งกำลังขว้าง -

javax.net.ssl.SSLHandshakeException: 
  java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

ปัญหาที่เกิดขึ้นจริงคือการกำหนดค่าเซิร์ฟเวอร์ที่ไม่ถูกต้อง - ทดสอบด้วยhttp://www.digicert.com/help/หรือที่คล้ายกันและจะบอกวิธีแก้ปัญหาให้คุณ:

"ใบรับรองไม่ได้ลงนามโดยหน่วยงานที่เชื่อถือได้ (ตรวจสอบกับที่เก็บรูทของ Mozilla) หากคุณซื้อใบรับรองจากหน่วยงานที่เชื่อถือได้คุณอาจต้องติดตั้งใบรับรองระดับกลางหนึ่งใบหรือมากกว่าติดต่อผู้ให้บริการใบรับรองของคุณเพื่อขอความช่วยเหลือ แพลตฟอร์มเซิร์ฟเวอร์ "

คุณสามารถตรวจสอบใบรับรองด้วย openssl:

openssl s_client -debug -connect www.thedomaintocheck.com:443

คุณอาจจะเห็น:

Verify return code: 21 (unable to verify the first certificate)

และก่อนหน้านี้ในผลลัพธ์:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`

ห่วงโซ่ใบรับรองจะมี 1 องค์ประกอบเท่านั้น (ใบรับรองของคุณ):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2

... แต่ควรอ้างอิงผู้มีอำนาจลงนามในห่วงโซ่กลับไปหนึ่งซึ่งเชื่อถือได้โดย Android (Verisign, GlobalSign ฯลฯ ):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

คำแนะนำ (และใบรับรองระดับกลาง) สำหรับการกำหนดค่าเซิร์ฟเวอร์ของคุณมักมีให้โดยหน่วยงานที่ออกใบรับรองของคุณตัวอย่างเช่น: http://www.alphassl.com/support/install-root-certificate.html

หลังจากติดตั้งใบรับรองกลางที่ออกโดยผู้ออกใบรับรองของฉันตอนนี้ฉันไม่มีข้อผิดพลาดเมื่อเชื่อมต่อโดยใช้ HttpsUrlConnection


3
ในกรณีที่ OP เข้าถึงการกำหนดค่าเซิร์ฟเวอร์ SSL ที่เขากำลังเชื่อมต่ออยู่นี่อาจเป็นวิธีแก้ปัญหา แต่ถ้าเขาไม่ใช่ผู้ให้บริการที่เขากำลังเชื่อมต่อกับเขาจะต้องแก้ไขปัญหาด้านข้างของเขาหมายถึงการใช้ผู้จัดการความเชื่อถือที่กำหนดเอง
Matthias B

9
วิธีการแก้ปัญหาของคุณใช้งานได้ไม่มีคำถาม แต่คุณไม่เห็นด้วยหรือไม่ว่ามันเป็นวิธีการแก้ปัญหามากกว่าการแก้ไขสำหรับสาเหตุที่แท้จริง? ถ้าฉันต้องเชื่อมต่อกับเซิร์ฟเวอร์จาก 3 ไคลเอนต์ (Android, iOS, Windows Mobile) ดังนั้นฉันต้องใช้วิธีแก้ปัญหาทั้งหมด 3 ในขณะที่ฉันสามารถแก้ไขเซิร์ฟเวอร์ครั้งเดียวและพวกเขาทั้งหมดจะ "ทำงาน"
Stevie

2
ขอบคุณ Stevie ฉันมีเซิร์ฟเวอร์ของฉันตั้งค่าผิดพลาดเป็นเวลา 3 เดือนและตอนนี้ฉันตรวจพบสิ่งนี้แล้ว! ตอนนี้แอพ android ของฉันใช้งานได้ 100%
jpros

2
@Stevie ฉันโทรไปยัง API ที่แตกต่างกันซึ่งแชร์โดเมนเดียวกัน แต่มีเพียงหนึ่งในนั้นเท่านั้นที่ล้มเหลวด้วย (javax.net.ssl.SSLHandshakeException) ... ความคิดใด ๆ ว่าทำไมสิ่งเช่นนี้จะเกิดขึ้น? และโดยวิธีการใบรับรอง SSL ไม่น่าเชื่อถือ ดังนั้นฉันคิดว่าการโทรทั้งหมดควรล้มเหลวด้วยข้อยกเว้นเดียวกัน
ผู้เล่นที่ยุติธรรม

1
@dvaey ติดต่อกับใครก็ตามที่เป็นเจ้าของเซิร์ฟเวอร์และแจ้งให้ config ทราบว่าพวกเขาเสียและ https ไม่ทำงานอย่างถูกต้อง - ให้ลิงก์นี้เพื่อพิสูจน์digicert.com/help ... ฉันคิดว่าพวกเขาจะประทับใจและรวดเร็วในการ แก้ไข ไม่เช่นนั้นคุณจะต้องทำหนึ่งในขั้นตอนการแก้ปัญหาในคำตอบอื่น ๆ แต่คุณจะต้องยอมรับความปลอดภัย (ไม่สนใจใบรับรอง) หรือปรับใช้แอปของคุณอีกครั้งเมื่อใบรับรองหมดอายุและร้านค้าเชื่อถือที่กำหนดเองของคุณไม่ตรงกับใหม่ ใบรับรอง
Stevie

17

คุณสามารถเชื่อถือใบรับรองเฉพาะตอนรันไทม์
เพียงดาวน์โหลดจากเซิร์ฟเวอร์ใส่ทรัพย์สินและโหลดแบบนี้โดยใช้ssl-utils-android :

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

ในตัวอย่างข้างต้นฉันใช้OkHttpClientแต่SSLContextสามารถใช้กับไคลเอ็นต์ใด ๆ ใน Java

หากคุณมีคำถามใด ๆ อย่าลังเลที่จะถาม ฉันเป็นผู้เขียนห้องสมุดเล็ก ๆ แห่งนี้


แล้ว. pfx ล่ะ
Choletski

2
สิ่งนี้ไม่ปลอดภัยหรือไม่เนื่องจากผู้ใช้รายใดสามารถเข้าถึงโฟลเดอร์เนื้อหาสำหรับแอปเมื่อมี apk
Patrice Andala

1
@PatriceAndala, Root CAs เป็นแบบสาธารณะจึงใช้ได้
BekaBot

17

อัปเดตตามเอกสารล่าสุดของ Android (มีนาคม 2560):

เมื่อคุณได้รับข้อผิดพลาดประเภทนี้:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
        at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
        at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
        at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
        at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
        at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)

ปัญหาอาจเป็นหนึ่งในสิ่งต่อไปนี้:

  1. ไม่ทราบ CA ที่ออกใบรับรองเซิร์ฟเวอร์
  2. ใบรับรองเซิร์ฟเวอร์ไม่ได้ลงนามโดย CA แต่ลงนามด้วยตนเอง
  3. การกำหนดค่าเซิร์ฟเวอร์ขาด CA ระดับกลาง

วิธีแก้ปัญหาคือสอนHttpsURLConnectionให้เชื่อใจ CA ที่เฉพาะเจาะจง อย่างไร? กรุณาตรวจสอบhttps://developer.android.com/training/articles/security-ssl.html#CommonProblems

คนอื่น ๆ ที่มีการใช้AsyncHTTPClientจากcom.loopj.android:android-async-httpห้องสมุดโปรดตรวจสอบการติดตั้ง AsyncHttpClient ใช้ HTTPS


5
จะเกิดอะไรขึ้นถ้าลูกค้าใช้ okhttp
TheLearner

สำหรับ okhttp กรุณาตรวจสอบคำตอบของ @ mklimek
user1506104

14

หากคุณใช้ชุดติดตั้งเพิ่มเติมคุณต้องปรับแต่ง OkHttpClient ของคุณ

retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

รหัสเต็มมีดังนี้

    public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return builder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ApiInterface getApiClient() {
        if (apiInterface == null) {

            try {
                retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

            } catch (Exception e) {

                e.printStackTrace();
            }


            apiInterface = retrofit.create(ApiInterface.class);
        }
        return apiInterface;
    }

}

1
ฉันพยายามใช้รหัส แต่ฉันได้รับข้อผิดพลาดต่อไปนี้อีกครั้ง .. "javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: ไม่ต้องยึดสมอสำหรับเส้นทางการรับรอง" คุณสามารถช่วยได้
Vishwa Pratap

นี่คือความไม่ปลอดภัยอนุมูลอิสระ ไม่ได้ใช้.
มาร์ควิสแห่ง Lorne

ขอบคุณ! เขียนวิธีการgetUnsafeOkHttpClient()ใน Kotlin: stackoverflow.com/a/60507560/2914140
CoolMind

11

ตอบกลับโพสต์เก่ามาก แต่อาจจะช่วยให้มือใหม่บางคนและถ้าไม่ใช่ของข้างต้นทำงานออกมา

คำอธิบาย:ฉันรู้ว่าไม่มีใครต้องการอึอธิบาย; ค่อนข้างจะแก้ปัญหา แต่ในหนึ่งสายการบินคุณกำลังพยายามเข้าถึงบริการจากเครื่องท้องถิ่นของคุณไปยังเครื่องระยะไกลซึ่งไม่น่าเชื่อถือเครื่องของคุณ คุณต้องขอความไว้วางใจจากเซิร์ฟเวอร์ระยะไกล

การแก้ไข:วิธีแก้ไขปัญหาต่อไปนี้อนุมานว่าคุณได้ปฏิบัติตามเงื่อนไขต่อไปนี้แล้ว

  1. กำลังพยายามเข้าถึง api ระยะไกลจากเครื่องท้องถิ่นของคุณ
  2. คุณกำลังสร้างแอพ Android
  3. เซิร์ฟเวอร์ระยะไกลของคุณอยู่ภายใต้การกรองพร็อกซี่ (คุณใช้พร็อกซีในการตั้งค่าเบราว์เซอร์ของคุณเพื่อเข้าถึงบริการ api ระยะไกลซึ่งโดยปกติจะเป็นเซิร์ฟเวอร์ staging หรือเซิร์ฟเวอร์ dev)
  4. คุณกำลังทดสอบบนอุปกรณ์จริง

ขั้นตอน:

คุณต้องมีไฟล์นามสกุล. keystore เพื่อสมัครแอปของคุณ หากคุณไม่ทราบวิธีสร้างไฟล์. keystore จากนั้นทำตามพร้อมกับส่วนต่อไปนี้สร้างไฟล์. keystoreหรือข้ามไปที่ส่วนถัดไปลงชื่อไฟล์ Apk

สร้างไฟล์. keystore

เปิด Android Studio คลิกเมนูด้านบนสร้าง> สร้าง APK ที่ลงชื่อแล้ว ในหน้าต่างถัดไปคลิกสร้างใหม่ ...ปุ่ม ในหน้าต่างใหม่โปรดป้อนข้อมูลในฟิลด์ทั้งหมด จำฟิลด์รหัสผ่านทั้งสองที่ฉันแนะนำควรมีรหัสผ่านเดียวกัน อย่าใช้รหัสผ่านอื่น และยังจำได้ว่าเส้นทางที่ประหยัดที่ด้านบนสนามมากที่สุดเส้นทางที่สำคัญการจัดเก็บ: หลังจากคุณป้อนฟิลด์ทั้งหมดแล้วให้คลิกปุ่มตกลง

ลงชื่อไฟล์ Apk

ตอนนี้คุณต้องสร้างแอปที่เซ็นชื่อด้วยไฟล์. keystore ที่คุณเพิ่งสร้างขึ้น ทำตามขั้นตอนเหล่านี้

  1. สร้าง> ล้างโครงการรอจนกว่าจะเสร็จสิ้นการทำความสะอาด
  2. สร้าง> สร้าง APK ที่ลงชื่อแล้ว
  3. คลิกChoose existing...ปุ่ม
  4. เลือกไฟล์ .keystore ที่เราเพิ่งสร้างขึ้นในการสร้างไฟล์ .keystoreส่วน
  5. ป้อนรหัสผ่านเดียวกับที่คุณสร้างขึ้นในการสร้างในส่วนสร้างไฟล์ . keystore ใช้รหัสผ่านเดียวกันสำหรับKey store passwordและKey passwordฟิลด์ ป้อนนามแฝงด้วย
  6. คลิกปุ่มถัดไป
  7. ในหน้าจอถัดไป ซึ่งอาจจะแตกต่างกันขึ้นอยู่กับการตั้งค่าในbuild.gradleไฟล์คุณต้องเลือกและBuild TypesFlavors
  8. สำหรับการBuild Typesเลือกreleaseแบบเลื่อนลง
  9. สำหรับFlavorsแต่มันจะขึ้นอยู่กับการตั้งค่าในbuild.gradleไฟล์ เลือกstagingจากช่องนี้ ฉันใช้การตั้งค่าต่อไปนี้ในbuild.gradleคุณสามารถใช้เช่นเดียวกับของฉัน แต่ให้แน่ใจว่าคุณเปลี่ยนapplicationIdชื่อแพคเกจของคุณ

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
  10. คลิกSignature Versionsช่องทำเครื่องหมายสองช่องด้านล่างแล้วคลิกFinishปุ่ม

เกือบจะมี:

การทำงานหนักทั้งหมดเสร็จสิ้นในขณะนี้การเคลื่อนไหวของความจริง ในการเข้าถึงเซิร์ฟเวอร์ Staging ที่สำรองโดยพรอกซีคุณต้องทำการตั้งค่าบางอย่างในอุปกรณ์ Android ที่ใช้ทดสอบจริง

การตั้งค่าพร็อกซีในอุปกรณ์ Android:

  1. คลิกการตั้งค่าภายในโทรศัพท์ Android จากนั้น wi-fi
  2. ลองกดที่ wifi ที่เชื่อมต่อและเลือก Modify network
  3. คลิกที่Advanced optionsหากคุณไม่เห็นProxy Hostnameฟิลด์
  4. ในการProxy Hostnameป้อนโฮสต์ IP หรือชื่อที่คุณต้องการเชื่อมต่อ เซิร์ฟเวอร์ staging ทั่วไปจะตั้งชื่อเป็นstg.api.mygoodcompany.com
  5. สำหรับพอร์ตให้ป้อนหมายเลขพอร์ตสี่หลักเช่น 9502
  6. กดSaveปุ่ม

หยุดล่าสุด:

อย่าลืมว่าเราสร้างไฟล์ APK ลงชื่อเข้าใช้เข้าสู่ระบบเอพีเคไฟล์ส่วน ตอนนี้เป็นเวลาที่จะติดตั้งไฟล์ APK

  1. เปิดเทอร์มินัลแล้วเปลี่ยนเป็นโฟลเดอร์ไฟล์ apk ที่ลงชื่อแล้ว
  2. เชื่อมต่ออุปกรณ์ Android ของคุณกับเครื่องของคุณ
  3. ลบไฟล์ apk ที่ติดตั้งก่อนหน้านี้ออกจากอุปกรณ์ Android
  4. วิ่ง adb install name of the apk file
  5. adb command not foundหากมีเหตุผลบางอย่างกลับมากับคำสั่งดังกล่าว ป้อนเส้นทางแบบเต็มเป็นC:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe install name of the apk file

ฉันหวังว่าปัญหาจะได้รับการแก้ไข ถ้าไม่ได้โปรดแสดงความคิดเห็น

ลาม!


4

ข้อความแสดงข้อผิดพลาดที่ฉันได้รับนั้นคล้ายกัน แต่เหตุผลก็คือใบรับรองที่ลงชื่อด้วยตนเองหมดอายุแล้ว เมื่อมีการพยายามลูกค้า openssl มันทำให้ฉันมีเหตุผลที่ถูกมองข้ามเมื่อฉันถูกตรวจสอบโต้ตอบใบรับรองจาก firefox

ดังนั้นโดยทั่วไปหากใบรับรองอยู่ในที่เก็บคีย์และ "VALID" ข้อผิดพลาดนี้จะดับลง


1
หากใบรับรองหมดอายุแสดงว่าใบรับรองนั้นไม่ถูกต้องตามจำนวนมาตรฐาน มันตกลงที่จะใช้กำหนดเองTrustManagerและใช้ชุดของเกณฑ์ที่แตกต่างกัน แต่นอกกรอบนั่นคือสิ่งที่คุณต้องทำงานด้วย
jww

4

ฉันมีปัญหาเดียวกันขณะเชื่อมต่อจากไคลเอนต์ Android กับเซิร์ฟเวอร์ Kurento เซิร์ฟเวอร์ Kurento ใช้ใบรับรอง jks ดังนั้นฉันจึงต้องแปลงค่า pem เป็นอินพุตสำหรับการแปลงฉันใช้ไฟล์ cert.pem และมันนำไปสู่ข้อผิดพลาดดังกล่าว แต่ถ้าใช้fullchain.pemแทนcert.pem - ทั้งหมดก็โอเค


3

ใช้https://www.ssllabs.com/ssltest/เพื่อทดสอบโดเมน

การแก้ปัญหาของShihab Uddinใน Kotlin

import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException

companion object {

    private val gson: Gson
    private val retrofit: Retrofit

    init {

        val okHttpClient = getUnsafeOkHttpClient() // OkHttpClient().newBuilder()
            .build()

        gson = GsonBuilder().setLenient().create()

        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }

    private fun getUnsafeOkHttpClient(): OkHttpClient.Builder =
        try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts: Array<TrustManager> = arrayOf(
                object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
                }
            )
            // Install the all-trusting trust manager
            val sslContext: SSLContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory,
                trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier { _, _ -> true }
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
}

2

ฉันพบปัญหาเดียวกันกับที่ฉันพบคือไฟล์ใบรับรอง. crt ฉันให้ขาดใบรับรองระดับกลาง ดังนั้นฉันจึงถามไฟล์. crt ทั้งหมดจากผู้ดูแลเซิร์ฟเวอร์ของฉัน

อดีต 1. Root.crt 2. Inter.crt 3. myCrt.crt

ใน windows ฉันดำเนินการคัดลอก Inter.crt + Root.crt newCertificate.crt

(ที่นี่ฉันไม่สนใจ myCrt.crt)

จากนั้นฉันให้ไฟล์ newCertificate.crt เป็นรหัสผ่านอินพุตสตรีม ทำงานเสร็จแล้ว


เรายังมีปัญหาเดียวกัน ใบรับรองระดับกลางหายไป
Nidhin Chandran

1

ข้อผิดพลาด Trust anchor สามารถเกิดขึ้นได้จากหลายสาเหตุ สำหรับฉันมันเป็นเพียงว่าผมพยายามที่จะเข้าถึงแทนhttps://example.com/https://www.example.com/

ดังนั้นคุณอาจต้องการตรวจสอบ URL ของคุณอีกครั้งก่อนที่จะเริ่มสร้าง Trust Manager ของคุณเอง (เหมือนที่ฉันทำ)


0

ในโทรศัพท์ Gingerbread ฉันมักจะได้รับข้อผิดพลาดนี้: Trust Anchor not found for Android SSL Connectionแม้ว่าฉันจะตั้งค่าให้ใช้ใบรับรองของฉัน

นี่คือรหัสที่ฉันใช้ (ในภาษา Scala):

object Security {
    private def createCtxSsl(ctx: Context) = {
        val cer = {
            val is = ctx.getAssets.open("mycertificate.crt")
            try
                CertificateFactory.getInstance("X.509").generateCertificate(is)
            finally
                is.close()
        }
        val key = KeyStore.getInstance(KeyStore.getDefaultType)
        key.load(null, null)
        key.setCertificateEntry("ca", cer)

        val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    tmf.init(key)

        val c = SSLContext.getInstance("TLS")
        c.init(null, tmf.getTrustManagers, null)
        c
    }

    def prepare(url: HttpURLConnection)(implicit ctx: Context) {
        url match {
            case https: HttpsURLConnection 
                val cSsl = ctxSsl match {
                    case None 
                        val res = createCtxSsl(ctx)
                        ctxSsl = Some(res)
                        res
                    case Some(c)  c
                }
                https.setSSLSocketFactory(cSsl.getSocketFactory)
            case _ 
        }
    }

    def noSecurity(url: HttpURLConnection) {
        url match {
            case https: HttpsURLConnection 
                https.setHostnameVerifier(new HostnameVerifier {
                    override def verify(hostname: String, session: SSLSession) = true
                })
            case _ 
        }
    }
}

และนี่คือรหัสการเชื่อมต่อ:

def connect(securize: HttpURLConnection  Unit) {
    val conn = url.openConnection().asInstanceOf[HttpURLConnection]
    securize(conn)
    conn.connect();
    ....
}

try {
    connect(Security.prepare)
} catch {
    case ex: SSLHandshakeException /*if ex.getMessage != null && ex.getMessage.contains("Trust anchor for certification path not found")*/ 
        connect(Security.noSecurity)
}

โดยทั่วไปฉันตั้งค่าให้เชื่อถือในใบรับรองที่กำหนดเองของฉัน หากสิ่งนั้นล้มเหลวฉันจะปิดการใช้งานความปลอดภัย นี่ไม่ใช่ตัวเลือกที่ดีที่สุด แต่เป็นทางเลือกเดียวที่ฉันรู้จักกับโทรศัพท์เก่าและบั๊กกี้

โค้ดตัวอย่างนี้สามารถแปลเป็นชวาได้อย่างง่ายดาย


โซลูชันสำหรับ android 2.3.x ในกรณีที่มีคนต้องการใช้งานstackoverflow.com/a/46465722/7125370
Newbie009

0

ในกรณีของฉันสิ่งนี้เกิดขึ้นหลังจากอัพเดตเป็น Android 8.0 ใบรับรอง Android ที่ลงชื่อด้วยตัวเองได้รับการตั้งค่าให้น่าเชื่อถือกำลังใช้อัลกอริทึมลายเซ็น SHA1withRSA เปลี่ยนเป็นใบรับรองใหม่โดยใช้อัลกอริธึมลายเซ็น SHA256withRSA เพื่อแก้ไขปัญหา


0

ฉันรู้ว่าคุณไม่จำเป็นต้องเชื่อถือใบรับรองทั้งหมด แต่ในกรณีของฉันฉันมีปัญหากับสภาพแวดล้อมการดีบักบางอย่างที่เรามีใบรับรองที่ลงชื่อด้วยตนเองและฉันต้องการโซลูชันที่สกปรก

สิ่งที่ฉันต้องทำคือเปลี่ยนการเริ่มต้นของ sslContext

mySSLContext.init(null, trustAllCerts, null); 

ที่trustAllCertsสร้างขึ้นเช่นนี้:

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }

    public void checkClientTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }
} };

หวังว่าสิ่งนี้จะมีประโยชน์


นั่นคือฉันต้องการที่จะหา! ขอบคุณ
oxied

Hostname '192.168.0.16' was not verifiedฉันได้รับข้อผิดพลาด ฉันกำลังทดสอบ webapi ของฉันผ่านตัวดีบักเกอร์ (IIS Express) ในเครื่อง ความคิดวิธีการแก้ไขปัญหานี้? ขอบคุณ :)
Sam

1
สิ่งนี้ไม่ปลอดภัยอย่างรุนแรง ไม่ได้ใช้.
มาร์ควิสแห่ง Lorne

0

ฉันมีปัญหาที่คล้ายกันและฉันได้ตัดกลยุทธ์การไว้วางใจแหล่งที่มาทั้งหมดอย่างสมบูรณ์แล้ว

ฉันแบ่งปันโซลูชันของฉันที่นี่กับแอปพลิเคชันที่ใช้ใน Kotlin

ก่อนอื่นฉันขอแนะนำให้ใช้เว็บไซต์ต่อไปนี้เพื่อรับข้อมูลเกี่ยวกับใบรับรองและความถูกต้องของใบรับรอง

หากไม่ปรากฏเป็น'ผู้ออกที่ได้รับการยอมรับ'ในร้านค้าที่เชื่อถือได้เริ่มต้นของ Androidเราจะต้องได้รับใบรับรองนั้นและรวมไว้ในแอปพลิเคชันเพื่อสร้างที่เก็บที่เชื่อถือได้ที่กำหนดเอง

ทางออกที่ดีที่สุดในกรณีของฉันคือการสร้างTrust Manager ระดับสูงที่รวมไว้ใน Trust Store แบบกำหนดเองและค่าเริ่มต้นของ Android

นี่เขาเปิดเผยรหัสระดับสูงที่ใช้ในการกำหนดค่า OkHttpClient ที่เขาใช้กับ Retrofit

override fun onBuildHttpClient(httpClientBuild: OkHttpClient.Builder) {

        val trustManagerWrapper = createX509TrustManagerWrapper(
            arrayOf(
                getCustomX509TrustManager(),
                getDefaultX509TrustManager()
            )
        )

        printX509TrustManagerAcceptedIssuers(trustManagerWrapper)

        val sslSocketFactory = createSocketFactory(trustManagerWrapper)
        httpClientBuild.sslSocketFactory(sslSocketFactory, trustManagerWrapper)

    }

ด้วยวิธีนี้ฉันสามารถสื่อสารกับเซิร์ฟเวอร์ด้วยใบรับรองแบบลงนามด้วยตนเองและกับเซิร์ฟเวอร์อื่น ๆ ด้วยใบรับรองที่ออกโดยหน่วยงานออกใบรับรองที่เชื่อถือได้

ฉันหวังว่ามันจะช่วยใครซักคน


0

ฉันรู้ว่านี่เป็นบทความที่เก่ามาก แต่ฉันเจอบทความนี้เมื่อพยายามแก้ไขปัญหาจุดยึดที่เชื่อถือได้ของฉัน ฉันโพสต์แล้วฉันแก้ไขได้อย่างไร หากคุณติดตั้ง Root CA ไว้ล่วงหน้าคุณจะต้องเพิ่มการกำหนดค่าลงในไฟล์ Manifest

https://stackoverflow.com/a/60102517/114265


สำหรับ API
24+ เท่านั้น

@BekaBot - นี่อาจเป็นจริง แต่ตามเอกสาร 23 และด้านล่างเชื่อถือ certs ผู้ใช้โดยค่าเริ่มต้นการเชื่อมต่อที่ปลอดภัย (ใช้โปรโตคอลเช่น TLS และ HTTPS) จากแอปทั้งหมดเชื่อถือ CA ของระบบที่ติดตั้งไว้ล่วงหน้าและแอปที่กำหนดเป้าหมาย Android 6.0 (API ระดับ 23) และที่ต่ำกว่ายังไว้วางใจ CA store ที่ผู้ใช้เพิ่มเป็นค่าเริ่มต้น
GR Envoy

-1
**Set proper alias name**
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
            X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
            String alias = cert.getSubjectX500Principal().getName();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);

-2

ฉันยังประสบปัญหาเดียวกัน ฉันเพิ่งลบ hhtps ไปที่ http เช่น

final public static String ROOT_URL = "https://example.com"; ถึง final public static String ROOT_URL = "http://example.com";

ขั้นสุดท้ายฉันแก้ไขปัญหานี้


แน่นอนว่านี่เป็นเพียงการลบความปลอดภัย SSL ออกจากสมการซึ่งอาจเป็นความคิดที่ดีสำหรับสภาพแวดล้อมการใช้งานจริง
Dragon Thoughts

นี่ไม่ใช่วิธีแก้ปัญหา แต่เป็นการลบความปลอดภัย SSL
omega1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.