วิธีแก้ไขข้อผิดพลาด“ java.security.cert.CertificateException: ไม่มีชื่อเรื่องอื่นที่แสดงอยู่”


109

ฉันมีไคลเอนต์บริการเว็บ Java ซึ่งใช้บริการเว็บผ่าน HTTPS

import javax.xml.ws.Service;

@WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...")
public class ISomeService
    extends Service
{

    public ISomeService() {
        super(__getWsdlLocation(), ISOMESERVICE_QNAME);
    }

เมื่อฉันเชื่อมต่อไปยัง URL บริการ ( https://AAA.BBB.CCC.DDD:9443/ISomeService) java.security.cert.CertificateException: No subject alternative names presentผมได้รับข้อยกเว้น

ในการแก้ไขก่อนอื่นฉันเรียกใช้openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txtและได้รับเนื้อหาต่อไปนี้ในไฟล์certs.txt:

CONNECTED(00000003)
---
Certificate chain
 0 s:/CN=someSubdomain.someorganisation.com
   i:/CN=someSubdomain.someorganisation.com
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=someSubdomain.someorganisation.com
issuer=/CN=someSubdomain.someorganisation.com
---
No client certificate CA names sent
---
SSL handshake has read 489 bytes and written 236 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 512 bit
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : RC4-MD5            
    Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Session-ID-ctx:                 
    Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Key-Arg   : None
    Start Time: 1382521838
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---

AFAIK ตอนนี้ฉันต้องการ

  1. สารสกัดจากส่วนหนึ่งของcerts.txtระหว่าง-----BEGIN CERTIFICATE-----และ-----END CERTIFICATE-----,
  2. แก้ไขเพื่อให้ชื่อใบรับรองเท่ากับAAA.BBB.CCC.DDDและ
  3. จากนั้นนำเข้าผลลัพธ์โดยใช้keytool -importcert -file fileWithModifiedCertificate( fileWithModifiedCertificateผลลัพธ์ของการดำเนินการ 1 และ 2 อยู่ที่ไหน)

ถูกต้องหรือไม่

ถ้าเป็นเช่นนั้นฉันจะทำให้ใบรับรองจากขั้นตอนที่ 1 ทำงานกับที่อยู่ IP ( AAA.BBB.CCC.DDD) ได้อย่างไร

อัปเดต 1 (23.10.2013 15:37 MSK):ในคำตอบสำหรับคำถามที่คล้ายกันฉันอ่านสิ่งต่อไปนี้:

หากคุณไม่ได้ควบคุมเซิร์ฟเวอร์นั้นให้ใช้ชื่อโฮสต์ (โดยมีอย่างน้อย CN ตรงกับชื่อโฮสต์นั้นในใบรับรองที่มีอยู่)

"ใช้" หมายความว่าอย่างไร

คำตอบ:


156

ฉันแก้ไขปัญหาโดยปิดใช้งานการตรวจสอบ HTTPS โดยใช้แนวทางที่นำเสนอที่นี่ :

ฉันใส่รหัสต่อไปนี้ในISomeServiceชั้นเรียน:

static {
    disableSslVerification();
}

private static void disableSslVerification() {
    try
    {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
            }
        }
        };

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

        // Create all-trusting host name verifier
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        // Install the all-trusting host verifier
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }
}

เนื่องจากฉันใช้https://AAA.BBB.CCC.DDD:9443/ISomeServiceเพื่อการทดสอบเท่านั้นจึงเป็นทางออกที่ดีพอ


แนวทางที่กล่าวถึงในลิงก์ที่กล่าวถึงข้างต้นดูเหมือนจะถูกบล็อก ( nakov.com/blog/2009/07/16/… ) ใครช่วยอัพเดทลิงค์หน่อย
ยอห์น

ฉันพยายามปิดการใช้งานการตรวจสอบความถูกต้องในกระบวนการนี้ แต่การตรวจสอบความถูกต้องของเบราว์เซอร์สำหรับโปรโตคอล SSL (ช่องโหว่ของพุดเดิ้ล) ทำให้ฉัน: ssl_error_no_cypher_overlap ความคิดใด ๆ ?
will824

สวัสดีฉันได้รับ org.springframework.web.client.HttpClientErrorException: 403 Forbidden

75
การปิดใช้งานการตรวจสอบ HTTPS ไม่ใช่ "วิธีแก้ปัญหา" คุณควรบอกว่าฉันพบ "ปะ"
Jus12

2
ซึ่งจะทำให้เกิดช่องโหว่ใน Pre_prod และ Production 1. สร้างรายการโฮสต์บนไฟล์โฮสต์ windows 2. หรือเพิ่มชื่อ IP หรือ FQDN ในฟิลด์ชื่อทางเลือกของหัวเรื่องในใบรับรอง
Shankar

34

ฉันมีปัญหาเดียวกันและแก้ไขได้ด้วยรหัสนี้ ฉันใส่รหัสนี้ก่อนการโทรครั้งแรกไปยังบริการเว็บของฉัน

javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier(){

    public boolean verify(String hostname,
            javax.net.ssl.SSLSession sslSession) {
        return hostname.equals("localhost");
    }
});

มันง่ายและใช้งานได้ดี

ที่นี่คือแหล่งดั้งเดิม


3
หรือคุณสามารถแทนที่เนื้อหาทั้งหมดของฟังก์ชัน Verify () return hostname.equals("localhost");ได้หากเป็นสิ่งที่คุณต้องการทำ ifเป็นฟุ่มเฟือยสมบูรณ์
ผู้ใช้

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

@ JuanM.Hidalgo HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();ที่ทำงานสำหรับฉันวางโค้ดด้านบนก่อนที่จะเรียกร้องให้ นอกจากนี้สิ่งนี้จะไม่สนใจใบรับรองทั้งหมดหรือไม่ เนื่องจากฉันเห็นว่าวิธีแก้ปัญหาดังกล่าวมีความเสี่ยงต่อความปลอดภัย ขอบคุณ!
ThunderWiring

คำตอบนี้แก้ไขข้อยกเว้นใบรับรอง SSL ของฉันและปัญหาอักขระที่ไม่ใช่ LDH ฉันเห็นว่ามีข้อผิดพลาดที่รายงานใน JDK เปิดbugs.openjdk.java.net/browse/JDK-8170265
Akhil S Kamath

29

นี่เป็นคำถามเก่า แต่ฉันก็มีปัญหาเดียวกันเมื่อย้ายจาก JDK 1.8.0_144 เป็น jdk 1.8.0_191

เราพบคำใบ้ในบันทึกการเปลี่ยนแปลง:

บันทึกการเปลี่ยนแปลง

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

-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true

25

การตรวจสอบข้อมูลประจำตัวของใบรับรองจะดำเนินการกับสิ่งที่ลูกค้าร้องขอ

เมื่อไคลเอนต์ของคุณใช้https://xxx.xxx.xxx.xxx/something(ที่xxx.xxx.xxx.xxxอยู่ IP อยู่ที่ไหน) ข้อมูลประจำตัวใบรับรองจะถูกตรวจสอบเทียบกับที่อยู่ IP นี้ (ตามทฤษฎีใช้เฉพาะส่วนขยาย IP SAN)

หากใบรับรองของคุณไม่มี IP SAN แต่ DNS SAN (หรือถ้าไม่มี DNS SAN ซึ่งเป็นชื่อสามัญใน Subject DN) คุณสามารถทำให้สิ่งนี้ทำงานได้โดยกำหนดให้ไคลเอ็นต์ของคุณใช้ URL กับชื่อโฮสต์นั้นแทน (หรือชื่อโฮสต์ ซึ่งใบรับรองจะถูกต้องหากมีค่าที่เป็นไปได้หลายค่า) ตัวอย่างเช่นถ้าคุณมีชื่อใบรับรองสำหรับการใช้งานwww.example.comhttps://www.example.com/something

แน่นอนคุณจะต้องใช้ชื่อโฮสต์นั้นเพื่อแก้ไขเป็นที่อยู่ IP นั้น

นอกจากนี้หากมี DNS SANs CN ใน Subject DN จะถูกละเว้นดังนั้นให้ใช้ชื่อที่ตรงกับ DNS SAN ในกรณีนี้


1
ฉันไม่สามารถเข้าถึงบริการผ่านhttp://www.example.com/someservice. ถูกต้องหรือไม่เพื่อให้ใบรับรองทำงานกับที่อยู่ตาม IP ( https://AAA.BBB.CCC.DDD:9443/ISomeService) ฉันต้องตั้งค่าCNฟิลด์ทั้งหมดเป็นAAA.BBB.CCC.DDD(แทนที่someSubdomain.someorganisation.comด้วยAAA.BBB.CCC.DDDไฟล์ด้านบน) และนำเข้าไฟล์ใบรับรองที่เป็นผลลัพธ์
Mentiflectax

คุณไม่สามารถทำอะไรเกี่ยวกับ CN หรือใบรับรองได้หากคุณไม่ได้ควบคุมเซิร์ฟเวอร์
Bruno

ในการเข้าถึงที่อยู่ IP เพื่อวัตถุประสงค์ในการทดสอบคุณสามารถแก้ไข/etc/hostsไฟล์ของคุณชั่วคราวหรือเทียบเท่า
tyoc213

1
ในรหัสของฉันฉันกำลังส่งคำขอไปยัง IP สาธารณะ แต่ใบรับรอง CN เป็นชื่อโฮสต์ ดังนั้นในรหัสของฉันฉันจึงแทนที่ IP ด้วยชื่อโฮสต์และกำหนดค่า / etc / hosts ของฉันเพื่อเชื่อมโยงชื่อโฮสต์นี้กับ IP แก้ไขแล้ว!
Leopold Gault

15

ในการนำเข้าใบรับรอง:

  1. ดึงใบรับรองออกจากเซิร์ฟเวอร์เช่นopenssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txtสิ่งนี้จะดึงใบรับรองในรูปแบบ PEM
  2. แปลงใบรับรองเป็นรูปแบบ DER เนื่องจากนี่คือสิ่งที่ keytool คาดหวังเช่น openssl x509 -in certs.txt -out certs.der -outform DER
  3. ตอนนี้คุณต้องการนำเข้าใบรับรองนี้ไปยังไฟล์ 'cacert' เริ่มต้นของระบบ ค้นหาไฟล์ 'cacerts' เริ่มต้นของระบบสำหรับการติดตั้ง Java ของคุณ ดูที่วิธีการขอรับตำแหน่งของ cacerts ของการติดตั้ง java เริ่มต้น?
  4. นำเข้าใบรับรองไปยังไฟล์ cacerts นั้น: sudo keytool -importcert -file certs.der -keystore <path-to-cacerts>รหัสผ่าน cacerts เริ่มต้นคือ 'changeit'

หากมีการออกใบรับรองสำหรับ FQDN และคุณกำลังพยายามเชื่อมต่อด้วยที่อยู่ IP ในโค้ด Java ของคุณสิ่งนี้อาจได้รับการแก้ไขในรหัสของคุณแทนที่จะไปยุ่งกับใบรับรองเอง เปลี่ยนรหัสของคุณเพื่อเชื่อมต่อโดย FQDN หาก FQDN ไม่สามารถแก้ไขได้บนเครื่อง dev ของคุณให้เพิ่มลงในไฟล์โฮสต์ของคุณหรือกำหนดค่าเครื่องของคุณด้วยเซิร์ฟเวอร์ DNS ที่สามารถแก้ไข FQDN นี้ได้


"ถ้า FQDN ไม่สามารถแก้ไขได้บนเครื่อง dev ของคุณเพียงแค่เพิ่มลงในไฟล์โฮสต์ของคุณ" - ช่วย ขอบคุณมาก!
Woland

ฉันทำสิ่งเดียวกัน แต่ก็ยังคงมีปัญหาอยู่ มีอะไรอีกบ้างที่สามารถทำได้โดยใช้แนวทางนี้?
pkgajulapalli

9

ฉันแก้ไขปัญหานี้ด้วยวิธีที่ถูกต้องโดยการเพิ่มชื่อ alt ของหัวเรื่องในใบรับรองแทนที่จะทำการเปลี่ยนแปลงใด ๆ ในโค้ดหรือปิดใช้ SSL ซึ่งแตกต่างจากคำตอบอื่น ๆ ที่แนะนำที่นี่ หากคุณเห็นอย่างชัดเจนข้อยกเว้นระบุว่า "Subject alt names are missing" ดังนั้นควรเพิ่มวิธีที่ถูกต้อง

โปรดดูที่นี้มีการเชื่อมโยงที่จะเข้าใจทีละขั้นตอน

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

  1. คัดลอก openssl.cnf ลงในไดเร็กทอรีปัจจุบัน
  2. echo '[ subject_alt_name ]' >> openssl.cnf
  3. echo 'subjectAltName = DNS:example.mydomain1.com, DNS:example.mydomain2.com, DNS:example.mydomain3.com, DNS: localhost'>> openssl.cnf
  4. openssl req -x509 -nodes -newkey rsa:2048 -config openssl.cnf -extensions subject_alt_name -keyout private.key -out self-signed.pem -subj '/C=gb/ST=edinburgh/L=edinburgh/O=mygroup/OU=servicing/CN=www.example.com/emailAddress=postmaster@example.com' -days 365
  5. ส่งออกไฟล์คีย์สาธารณะ (.pem) เป็นรูปแบบ PKS12 เพื่อขอรหัสผ่าน

    openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in
    self-signed.pem -inkey private.key -name myalias -out keystore.p12
  6. สร้าง a.JKS จาก PEM ที่ลงนามด้วยตนเอง (Keystore)

    keytool -importkeystore -destkeystore keystore.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore keystore.p12
  7. สร้างใบรับรองจากด้านบน Keystore หรือไฟล์ JKS

    keytool -export -keystore keystore.jks -alias myalias -file selfsigned.crt
  8. เนื่องจากใบรับรองข้างต้นเป็นแบบลงนามด้วยตนเองและ CA ไม่ได้รับการตรวจสอบความถูกต้องจึงจำเป็นต้องเพิ่มใน Truststore (ไฟล์ Cacerts ในตำแหน่งด้านล่างสำหรับ MAC สำหรับ Windows ค้นหาว่า JDK ของคุณติดตั้งไว้ที่ใด)

    sudo keytool -importcert -file selfsigned.crt -alias myalias -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts

คำตอบเดิมโพสต์ที่ลิงค์นี้ที่นี่


4

คุณอาจไม่ต้องการปิดการใช้งาน ssl Verificatication ทั้งหมดดังนั้นคุณสามารถปิดการใช้งานการยืนยันชื่อโฮสต์ผ่านทางนี้ซึ่งค่อนข้างน่ากลัวน้อยกว่าทางเลือกอื่น:

HttpsURLConnection.setDefaultHostnameVerifier(
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

[แก้ไข]

ดังที่กล่าวไว้ใน conapart3 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIERเลิกใช้งานแล้วดังนั้นจึงอาจถูกลบออกในเวอร์ชันที่ใหม่กว่าดังนั้นในอนาคตคุณอาจถูกบังคับให้หมุนของคุณเองแม้ว่าฉันจะยังคงบอกว่าฉันจะหลีกเลี่ยงโซลูชันใด ๆ ที่ปิดการตรวจสอบทั้งหมด


2
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIERเลิกใช้งานแล้ว
conapart3

3

ปัญหาของฉันในการรับข้อผิดพลาดนี้ได้รับการแก้ไขโดยใช้ URL แบบเต็ม "qatest.ourCompany.com/webService" แทนที่จะเป็นเพียง "qatest / webService" เหตุผลคือใบรับรองความปลอดภัยของเรามีสัญลักษณ์แทนคือ "* .ourCompany.com" เมื่อฉันใส่ที่อยู่แบบเต็มข้อยกเว้นก็หายไป หวังว่านี่จะช่วยได้


2

มีคำตอบมันมีอยู่แล้วในhttps://stackoverflow.com/a/53491151/1909708

สิ่งนี้ล้มเหลวเนื่องจากไม่มีชื่อสามัญของใบรับรอง ( CNในการรับรองSubject) หรือชื่ออื่นใด ๆ ( Subject Alternative Nameในใบรับรอง) ที่ตรงกับชื่อโฮสต์เป้าหมายหรือที่อยู่ IP

ตัวอย่างเช่นจาก JVM เมื่อพยายามเชื่อมต่อกับที่อยู่ IP ( WW.XX.YY.ZZ) และไม่ใช่ชื่อ DNS ( https://stackoverflow.com ) การเชื่อมต่อ HTTPS จะล้มเหลวเนื่องจากใบรับรองที่เก็บไว้ใน java truststore ต้องการcacertsชื่อสามัญ (หรือ ใบรับรองชื่อสำรองเช่น stackexchange.com หรือ * .stackoverflow.com เป็นต้น) เพื่อให้ตรงกับที่อยู่เป้าหมาย

โปรดตรวจสอบ: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#HostnameVerifier

    HttpsURLConnection urlConnection = (HttpsURLConnection) new URL("https://WW.XX.YY.ZZ/api/verify").openConnection();
    urlConnection.setSSLSocketFactory(socketFactory());
    urlConnection.setDoOutput(true);
    urlConnection.setRequestMethod("GET");
    urlConnection.setUseCaches(false);
    urlConnection.setHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession sslSession) {
            return true;
        }
    });
    urlConnection.getOutputStream();

ด้านบนส่งผ่านHostnameVerifierวัตถุที่ใช้งานซึ่งจะส่งคืนเสมอtrue:

new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession sslSession) {
            return true;
        }
    }

1

สำหรับ Spring Boot RestTemplate:

  • เพิ่มการorg.apache.httpcomponents.httpcoreพึ่งพา
  • ใช้NoopHostnameVerifierสำหรับโรงงาน SSL:

    SSLContext sslContext = new SSLContextBuilder()
            .loadTrustMaterial(new URL("file:pathToServerKeyStore"), storePassword)
    //        .loadKeyMaterial(new URL("file:pathToClientKeyStore"), storePassword, storePassword)
            .build();
    SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
    CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client);
    RestTemplate restTemplate = new RestTemplate(factory);

0

ฉันได้รับคำถามนี้หลังจากได้รับข้อความแสดงข้อผิดพลาดเดียวกันนี้หรือไม่ อย่างไรก็ตามในกรณีของฉันเรามี URL สองรายการที่มีโดเมนย่อยต่างกัน ( http://example1.xxx.com/someserviceและhttp://example2.yyy.com/someservice ) ซึ่งถูกส่งไปยังเซิร์ฟเวอร์เดียวกัน เซิร์ฟเวอร์นี้มีใบรับรองตัวแทนเพียงรายการเดียวสำหรับโดเมน * .xxx.com เมื่อใช้บริการผ่านโดเมนที่สองใบรับรองที่พบ (* .xxx.com) ไม่ตรงกับโดเมนที่ร้องขอ (* .yyy.com) และเกิดข้อผิดพลาด

ในกรณีนี้เราไม่ควรพยายามแก้ไขข้อผิดพลาดดังกล่าวโดยการลดความปลอดภัยของ SSL แต่ควรตรวจสอบเซิร์ฟเวอร์และใบรับรอง


0
public class RESTfulClientSSL {

    static TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // TODO Auto-generated method stub
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // TODO Auto-generated method stub
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }
    }};

    public class NullHostNameVerifier implements HostnameVerifier {
        /*
         * (non-Javadoc)
         *
         * @see javax.net.ssl.HostnameVerifier#verify(java.lang.String,
         * javax.net.ssl.SSLSession)
         */
        @Override
        public boolean verify(String arg0, SSLSession arg1) {
            // TODO Auto-generated method stub
            return true;
        }
    }

    public static void main(String[] args) {

        HttpURLConnection connection = null;
        try {

            HttpsURLConnection.setDefaultHostnameVerifier(new RESTfulwalkthroughCer().new NullHostNameVerifier());
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());


            String uriString = "https://172.20.20.12:9443/rest/hr/exposed/service";
            URL url = new URL(uriString);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            //connection.setRequestMethod("POST");

            BASE64Encoder encoder = new BASE64Encoder();
            String username = "admin";
            String password = "admin";
            String encodedCredential = encoder.encode((username + ":" + password).getBytes());
            connection.setRequestProperty("Authorization", "Basic " + encodedCredential);

            connection.connect();
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                StringBuffer stringBuffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    stringBuffer.append(line);
                }
                String content = stringBuffer.toString();
                System.out.println(content);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
}

1
โปรดเพิ่มข้อความอธิบายรหัสของคุณ ดูstackoverflow.com/help/how-to-answer
jasie

1
นี่เป็นข้อบกพร่องด้านความปลอดภัย นี่คือวิธีปิดการใช้งานการตรวจสอบใบรับรองตั้งแต่แรก ทุกคนที่คัดลอกวางโซลูชันนี้จะสร้างข้อบกพร่องด้านความปลอดภัยในซอฟต์แวร์ของตน
Marek Puchalski

0

ฉันกำลังใช้ SSL 2 ทางใน springboot ฉันได้สร้างเซิร์ฟเวอร์ tomcat บริการกำหนดค่าที่ถูกต้องทั้งหมดและ RestTemplate ผู้เรียกบริการแล้ว แต่ฉันได้รับข้อผิดพลาดเป็น"java.security.cert.CertificateException: ไม่มีชื่อเรื่องอื่นอยู่"

หลังจากทำตามแนวทางแก้ไขแล้วฉันพบว่า JVM ต้องการใบรับรองนี้มิฉะนั้นจะทำให้เกิดข้อผิดพลาดในการจับมือ

ตอนนี้วิธีเพิ่มสิ่งนี้ใน JVM

ไปที่ไฟล์ jre / lib / security / cacerts เราจำเป็นต้องเพิ่มไฟล์ใบรับรองเซิร์ฟเวอร์ของเราลงในไฟล์ cacerts ของ jvm

คำสั่งเพื่อเพิ่มใบรับรองเซิร์ฟเวอร์ไปยังไฟล์ cacerts ผ่านทางบรรทัดคำสั่งใน windows

C: \ Program Files \ Java \ jdk1.8.0_191 \ jre \ lib \ security> keytool -import -noprompt -trustcacerts -alias sslserver -file E: \ spring_cloud_sachin \ ssl_keys \ sslserver.cer -keystore cacerts -storepass changeit

ตรวจสอบการติดตั้งใบรับรองเซิร์ฟเวอร์หรือไม่:

C: \ Program Files \ Java \ jdk1.8.0_191 \ jre \ lib \ security> keytool -list -keystore cacerts

คุณสามารถดูรายการใบรับรองที่ติดตั้ง:

สำหรับรายละเอียดเพิ่มเติม: https://sachin4java.blogspot.com/2019/08/javasecuritycertcertificateexception-no.html


0

เพิ่มรายการโฮสต์ด้วย ip ที่สอดคล้องกับ CN ในใบรับรอง

CN = someSubdomain.someorganisation.com

ตอนนี้อัปเดต ip ด้วยชื่อ CN ที่คุณพยายามเข้าถึง url

มันได้ผลสำหรับฉัน


0

รหัสนี้จะทำงานเหมือน charm และใช้ออบเจ็กต์ restTemple สำหรับส่วนที่เหลือของโค้ด

  RestTemplate restTemplate = new RestTemplate();   
  TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
            @Override
            public boolean isTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) {
                return true;
            }

        };

        SSLContext sslContext = null;
        try {
            sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy)
                    .build();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);

        restTemplate.setRequestFactory(requestFactory);
}

0

เมื่อคุณมีใบรับรองที่มีทั้ง CN และ Subject Alternative Names (SAN) หากคุณส่งคำขอตามเนื้อหา CN เนื้อหานั้นจะต้องอยู่ภายใต้ SAN ด้วยมิฉะนั้นจะล้มเหลวด้วยข้อผิดพลาดที่เป็นปัญหา

ในกรณีของฉัน CN มีบางอย่าง SAN มีอย่างอื่น ฉันต้องใช้ SAN URL แล้วมันก็ใช้ได้ดี


0

ฉันได้แก้ไขปัญหาดังกล่าวแล้ว

MqttException (0) - javax.net.ssl.SSLHandshakeException: ไม่มี subjectAltNames บนใบรับรองที่ตรงกัน

เกิดข้อผิดพลาดโดยการเพิ่มชื่อเรื่องอื่น (สามารถเพิ่มได้หลายตัว) ในใบรับรองเซิร์ฟเวอร์ (มี CN = example.com) ซึ่งหลังจากพิมพ์ส่วนของใบรับรองดังต่อไปนี้:

Subject Alternative Name:
DNS: example.com

ฉันใช้ KeyExplorer บน windows เพื่อสร้างใบรับรองเซิร์ฟเวอร์ของฉัน คุณสามารถไปที่ลิงค์นี้เพื่อเพิ่มชื่อเรื่องอื่น (ทำตามส่วนเดียวเพื่อเพิ่ม)


-3

เพิ่มที่อยู่ IP ของคุณในไฟล์โฮสต์ซึ่งอยู่ในโฟลเดอร์ของ C: \ Windows \ System32 \ drivers \ etc เพิ่ม IP และชื่อโดเมนของที่อยู่ IP ด้วย ตัวอย่าง: aaa.bbb.ccc.ddd abc@def.com


-5

ฉันได้แก้ไขปัญหาโดยวิธีต่อไปนี้

1. การสร้างคลาส ชั้นเรียนมีการใช้งานที่ว่างเปล่า

class MyTrustManager implements X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    return null;
}

public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

public void checkServerTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
        throws CertificateException {
    // TODO Auto-generated method stub

}

@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
        throws CertificateException {
    // TODO Auto-generated method stub

}

2. การสร้างวิธีการ

private static void disableSSL() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[] { new MyTrustManager() };

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

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