ยอมรับใบรับรอง SSL ที่ลงนามเองของเซิร์ฟเวอร์ในไคลเอ็นต์ Java


215

ดูเหมือนคำถามทั่วไป แต่ฉันไม่สามารถหาเส้นทางที่ชัดเจนได้ทุกที่

ฉันมีรหัส java พยายามเชื่อมต่อกับเซิร์ฟเวอร์ที่อาจมีใบรับรองที่ลงชื่อด้วยตนเอง (หรือหมดอายุ) รหัสรายงานข้อผิดพลาดต่อไปนี้:

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught 
when processing request: sun.security.validator.ValidatorException: PKIX path 
building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

ตามที่ฉันเข้าใจฉันต้องใช้keytoolและบอก java ว่าตกลงเพื่ออนุญาตการเชื่อมต่อนี้

คำแนะนำทั้งหมดในการแก้ไขปัญหานี้ถือว่าฉันมีความเชี่ยวชาญอย่างเต็มที่กับ keytool เช่น

สร้างไพรเวตคีย์สำหรับเซิร์ฟเวอร์และนำเข้าสู่ที่เก็บคีย์

มีใครบ้างที่สามารถโพสต์คำแนะนำโดยละเอียด?

ฉันใช้ระบบยูนิกซ์ดังนั้นสคริปต์ทุบตีจะดีที่สุด

ไม่แน่ใจว่าสำคัญหรือไม่ แต่มีการใช้รหัสใน jboss


2
ดูฉันจะยอมรับใบรับรองที่ลงนามเองด้วย Java HttpsURLConnection ได้อย่างไร . เห็นได้ชัดว่ามันจะดีกว่าถ้าคุณสามารถให้ไซต์ใช้ใบรับรองที่ถูกต้อง
Matthew Flaschen

2
ขอบคุณสำหรับลิงค์ฉันไม่เห็นมันในขณะค้นหา แต่โซลูชันทั้งสองนั้นมีรหัสพิเศษเพื่อส่งคำขอและฉันใช้รหัสที่มีอยู่ (amazon ws ไคลเอ็นต์สำหรับ java) เป็นไซต์ที่ฉันติดต่อด้วยและฉันไม่สามารถแก้ไขปัญหาใบรับรองได้
Nikita Rybak

2
@MatthewFlaschen - "เห็นได้ชัดว่ามันจะดีกว่าถ้าคุณสามารถให้เว็บไซต์ใช้ใบรับรองที่ถูกต้อง ... " - ใบรับรองที่ลงชื่อด้วยตนเองเป็นใบรับรองที่ถูกต้องหากลูกค้าเชื่อถือ หลายคนคิดว่าการมอบความไว้วางใจให้กับพันธมิตรของ CA / Browser เป็นข้อบกพร่องด้านความปลอดภัย
jww

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

คำตอบ:


307

โดยทั่วไปคุณมีสองตัวเลือกที่นี่: เพิ่มใบรับรองที่ลงนามเองใน JVM truststore ของคุณหรือกำหนดค่าไคลเอ็นต์ของคุณ

ตัวเลือกที่ 1

ส่งออกใบรับรองจากเบราว์เซอร์ของคุณและนำเข้าใน JVM truststore ของคุณ (เพื่อสร้างเครือข่ายความไว้วางใจ):

<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit 

ตัวเลือก 2

ปิดใช้งานการตรวจสอบใบรับรอง:

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

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
} 
// Now you can access an https URL without having the certificate in the truststore
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) {
} 

โปรดทราบว่าฉันไม่แนะนำตัวเลือก # 2เลย การปิดการใช้งานโปรแกรมจัดการความน่าเชื่อถือจะเอาชนะ SSL บางส่วนและทำให้คุณเสี่ยงต่อการถูกโจมตีจากคนกลาง ต้องการตัวเลือก # 1 หรือดีกว่าให้เซิร์ฟเวอร์ใช้ใบรับรอง "ของจริง" ที่ลงนามโดย CA ที่รู้จักกันดี


7
ไม่ใช่แค่การโจมตี MIM มันทำให้คุณเสี่ยงต่อการเชื่อมต่อกับเว็บไซต์ผิด มันไม่ปลอดภัยอย่างสมบูรณ์ ดู RFC 2246 ฉันไม่เห็นด้วยกับการโพสต์ TrustManager นี้ตลอดเวลา มันไม่ถูกต้องแม้กระทั่ง WRT สเปคของตัวเอง
มาร์ควิสแห่ง Lorne

10
@EJP ฉันไม่แนะนำตัวเลือกที่สอง (ฉันได้อัปเดตคำตอบเพื่อให้ชัดเจน) อย่างไรก็ตามการไม่โพสต์มันจะไม่แก้ปัญหาใด ๆ (นี่คือข้อมูลสาธารณะ) และ IMHO ไม่สมควรได้รับ downvote
Pascal Thivent

135
@EJP มันคือการสอนคนที่คุณให้ความรู้แก่พวกเขาไม่ใช่โดยการซ่อนสิ่งต่าง ๆ ดังนั้นการเก็บสิ่งต่าง ๆ ไว้เป็นความลับหรือคลุมเครือจึงไม่ใช่ทางออกเลย รหัสนี้เป็นแบบสาธารณะ, Java API เป็นแบบสาธารณะ, ดีกว่าที่จะพูดคุยเกี่ยวกับมันมากกว่าที่จะไม่สนใจมัน แต่ฉันสามารถอยู่กับคุณไม่เห็นด้วย
Pascal Thivent

10
ตัวเลือกอื่น - ที่คุณไม่ได้กล่าวถึง - คือการขอใบรับรองของเซิร์ฟเวอร์โดยแก้ไขด้วยตนเองหรือโดยการติดต่อผู้สนับสนุนที่เกี่ยวข้อง ใบรับรองโฮสต์เดี่ยวราคาถูกมากจริงๆ การซื้อขายล่วงหน้าด้วยสิ่งของที่ลงนามด้วยตนเองนั้นเป็นเงินปอนด์ที่ฉลาด (เช่นสำหรับคนที่ไม่คุ้นเคยกับสำนวนภาษาอังกฤษชุดลำดับความสำคัญอันโง่เขลาทั้งหมดที่มีค่าใช้จ่ายมากมาย
Donal Fellows

2
@ Rich ปลาย 6 ปี แต่คุณสามารถระงับใบรับรองเซิร์ฟเวอร์ใน firefox ได้โดยคลิกที่ไอคอนล็อค -> ข้อมูลเพิ่มเติม -> ดูใบรับรอง -> แท็บรายละเอียด -> ส่งออก ... มันถูกซ่อนไว้อย่างดี
Siddhartha

9

ผมไล่ลงปัญหานี้กับผู้ให้บริการใบรับรองที่ไม่เป็นส่วนหนึ่งของการเริ่มต้น JVM JDK 8u74ที่เชื่อถือได้เป็นเจ้าภาพของ ผู้ให้บริการคือwww.identrust.comแต่นั่นไม่ใช่โดเมนที่ฉันพยายามเชื่อมต่อ โดเมนนั้นได้รับใบรับรองจากผู้ให้บริการนี้ ดูที่ความน่าเชื่อถือของใบปะหน้าข้ามรากโดยรายการเริ่มต้นใน JDK / JRE - อ่านรายการสองสามรายการ ยังเห็นเบราว์เซอร์ซึ่งระบบปฏิบัติการและสนับสนุน Let 's เข้ารหัส

ดังนั้นเพื่อเชื่อมต่อกับโดเมนที่ฉันสนใจซึ่งมีใบรับรองที่ออกให้จากidentrust.comฉันทำตามขั้นตอนต่อไปนี้ โดยพื้นฐานแล้วฉันต้องได้รับการDST Root CA X3รับรองจากเชื่อถือได้โดย JVM ฉันสามารถทำได้โดยใช้ Apache HttpComponents 4.5 เช่นนั้น:

1: ขอรับใบรับรองจาก indettrust ที่รับรองโซ่ดาวน์โหลดคำแนะนำ คลิกที่ลิงก์DST Root CA X3

2: บันทึกสตริงลงในไฟล์ชื่อ "DST Root CA X3.pem" อย่าลืมเพิ่มบรรทัด "----- BEGIN CERTIFICATE -----" และ "----- END CERTIFICATE -----" ในไฟล์ที่จุดเริ่มต้นและจุดสิ้นสุด

3: สร้างไฟล์ที่เก็บคีย์ java, cacerts.jks ด้วยคำสั่งต่อไปนี้:

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4: คัดลอก cacerts.jks keystore ผลลัพธ์ลงในไดเร็กทอรี resources ของแอ็พพลิเคชัน java / (maven) ของคุณ

5: ใช้รหัสต่อไปนี้เพื่อโหลดไฟล์นี้และแนบกับ Apache 4.5 HttpClient สิ่งนี้จะแก้ปัญหาสำหรับโดเมนทั้งหมดที่มีใบรับรองที่ออกจากindetrust.comutil oracle รวมถึงใบรับรองในที่เก็บคีย์ดีฟอลต์ JRE

SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
                new TrustSelfSignedStrategy())
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

เมื่อโครงการสร้างแล้ว cacerts.jks จะถูกคัดลอกลงใน classpath และโหลดจากที่นั่น ในเวลานี้ฉันไม่ได้ทดสอบไซต์ ssl อื่น ๆ แต่ถ้ารหัส "โซ่" ข้างต้นในใบรับรองนี้พวกเขาจะใช้งานได้เช่นกัน แต่อีกครั้งฉันไม่รู้

การอ้างอิง: บริบท SSL ที่กำหนดเองและฉันจะยอมรับใบรับรองที่ลงนามเองด้วย Java HttpsURLConnection ได้อย่างไร


คำถามเกี่ยวกับใบรับรองที่ลงนามด้วยตนเอง คำตอบนี้ไม่ใช่
มาร์ควิสแห่ง Lorne

4
อ่านคำถาม (และตอบ) ให้ใกล้หน่อย
K.Nicholas

9

Apache HttpClient 4.5 รองรับการยอมรับใบรับรองที่ลงนามเอง:

SSLContext sslContext = SSLContexts.custom()
    .loadTrustMaterial(new TrustSelfSignedStrategy())
    .build();
SSLConnectionSocketFactory socketFactory =
    new SSLConnectionSocketFactory(sslContext);
Registry<ConnectionSocketFactory> reg =
    RegistryBuilder.<ConnectionSocketFactory>create()
    .register("https", socketFactory)
    .build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);        
CloseableHttpClient httpClient = HttpClients.custom()
    .setConnectionManager(cm)
    .build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse sslResponse = httpClient.execute(httpGet);

สิ่งนี้จะสร้างโรงงานซ็อกเก็ต SSL ซึ่งจะใช้TrustSelfSignedStrategyลงทะเบียนกับผู้จัดการการเชื่อมต่อที่กำหนดเองจากนั้นจะทำการ HTTP GET โดยใช้ตัวจัดการการเชื่อมต่อนั้น

ฉันเห็นด้วยกับผู้ที่สวดมนต์ "อย่าทำเช่นนี้ในการผลิต" แต่มีกรณีการใช้งานสำหรับการยอมรับใบรับรองที่ลงชื่อด้วยตนเองนอกการผลิต เราใช้พวกเขาในการทดสอบการรวมอัตโนมัติเพื่อให้เราใช้ SSL (เช่นในการผลิต) แม้ว่าจะไม่ได้ทำงานบนฮาร์ดแวร์การผลิต


6

แทนที่จะตั้งค่าโรงงานซ็อกเก็ตเริ่มต้น (ซึ่ง IMO เป็นสิ่งที่ไม่ดี) - มันจะส่งผลต่อการเชื่อมต่อปัจจุบันมากกว่าการเชื่อมต่อ SSL ทุกครั้งที่คุณพยายามเปิด:

URLConnection connection = url.openConnection();
    // JMD - this is a better way to do it that doesn't override the default SSL factory.
    if (connection instanceof HttpsURLConnection)
    {
        HttpsURLConnection conHttps = (HttpsURLConnection) connection;
        // Set up a Trust all manager
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
        {

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

            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }

            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }
        } };

        // Get a new SSL context
        SSLContext sc = SSLContext.getInstance("TLSv1.2");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        // Set our connection to use this SSL context, with the "Trust all" manager in place.
        conHttps.setSSLSocketFactory(sc.getSocketFactory());
        // Also force it to trust all hosts
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        // and set the hostname verifier.
        conHttps.setHostnameVerifier(allHostsValid);
    }
InputStream stream = connection.getInputStream();

2
คุณcheckServerTrustedไม่ได้ใช้ตรรกะที่จำเป็นในการเชื่อถือใบรับรองจริงและรับรองว่าใบรับรองที่ไม่น่าเชื่อถือนั้นถูกปฏิเสธ ซึ่งอาจทำให้บางการอ่านที่ดี: รหัสที่อันตรายที่สุดในโลก: การตรวจสอบใบรับรอง SSL ในซอฟแวร์ที่ไม่ใช่เบราว์เซอร์
jww

1
getAcceptedIssuers()วิธีการของคุณไม่สอดคล้องกับข้อมูลจำเพาะและ 'โซลูชัน' นี้ยังไม่ปลอดภัยอย่างสิ้นเชิง
มาร์ควิสแห่ง Lorne

4

มีทางเลือกที่ดีกว่าที่จะไว้วางใจใบรับรองทั้งหมดเป็น: สร้างTrustStoreที่เฉพาะไว้ใจใบรับรองให้และใช้นี้เพื่อสร้างSSLContextจากการที่จะได้รับชุดบนSSLSocketFactory HttpsURLConnectionนี่คือรหัสที่สมบูรณ์:

File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

คุณสามารถโหลดKeyStoreโดยตรงจากไฟล์หรือดึงใบรับรอง X.509 จากแหล่งที่เชื่อถือได้

โปรดทราบว่าด้วยรหัสนี้ใบรับรองในcacertsจะไม่ถูกใช้ เฉพาะนี้HttpsURLConnectionจะเชื่อถือได้เฉพาะใบรับรองนี้


1

เชื่อถือใบรับรอง SSL ทั้งหมด: - คุณสามารถเลี่ยง SSL ได้หากคุณต้องการทดสอบบนเซิร์ฟเวอร์ทดสอบ แต่อย่าใช้รหัสนี้ในการผลิต

public static class NukeSSLCerts {
protected static final String TAG = "NukeSSLCerts";

public static void nuke() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[] { 
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    X509Certificate[] myTrustedAnchors = new X509Certificate[0];  
                    return myTrustedAnchors;
                }

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

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

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }
        });
    } catch (Exception e) { 
    }
}

}

กรุณาเรียกใช้ฟังก์ชันนี้ในฟังก์ชั่น onCreate () ใน Activity หรือใน Application Class ของคุณ

NukeSSLCerts.nuke();

สามารถใช้กับ Volley ใน Android ได้


ไม่แน่ใจว่าทำไมคุณถึงถูกโหวตไม่เว้นแต่ว่ารหัสจะไม่ทำงาน อาจเป็นไปได้ว่าสมมติฐานที่ว่า Android นั้นเกี่ยวข้องกับเมื่อคำถามเดิมไม่ได้ติดแท็ก Android
Lo-Tan

1

คำตอบที่ยอมรับนั้นใช้ได้ แต่ฉันต้องการเพิ่มสิ่งนี้เนื่องจากฉันใช้ IntelliJ บน Mac และไม่สามารถใช้งานได้โดยใช้JAVA_HOMEตัวแปรเส้นทาง

ปรากฎว่า Java Home แตกต่างกันเมื่อรันแอปพลิเคชันจาก IntelliJ

หากต้องการทราบว่าอยู่ตรงไหนคุณสามารถทำSystem.getProperty("java.home")ตามที่เป็นที่เชื่อถือได้สำหรับการอ่านใบรับรอง


0

หาก 'พวกเขา' กำลังใช้ใบรับรองที่ลงนามเองมันขึ้นอยู่กับพวกเขาที่จะทำตามขั้นตอนที่จำเป็นเพื่อให้เซิร์ฟเวอร์ของพวกเขาสามารถใช้งานได้ โดยเฉพาะนั่นหมายถึงการมอบใบรับรองของพวกเขาให้กับคุณแบบออฟไลน์ในรูปแบบที่น่าเชื่อถือ ดังนั้นให้พวกเขาทำอย่างนั้น จากนั้นคุณอิมพอร์ตสิ่งนั้นไปยัง truststore ของคุณโดยใช้ keytool ดังอธิบายในคู่มืออ้างอิง JSSE อย่าคิดแม้แต่เรื่อง TrustManager ที่ไม่ปลอดภัยที่โพสต์ที่นี่

แก้ไขเพื่อประโยชน์ของผู้ลงคะแนนสิบเจ็ด (!) และผู้แสดงความคิดเห็นด้านล่างจำนวนมากที่ยังไม่ได้อ่านสิ่งที่ฉันเขียนที่นี่จริง ๆ นี่ไม่ใช่ jeremiad ต่อใบรับรองที่ลงชื่อด้วยตนเอง ไม่มีอะไรผิดปกติกับใบรับรองที่ลงชื่อด้วยตนเองเมื่อดำเนินการอย่างถูกต้อง แต่วิธีที่ถูกต้องในการนำไปใช้นั้นคือการส่งมอบใบรับรองอย่างปลอดภัยผ่านกระบวนการออฟไลน์แทนที่จะใช้แชนเนลที่ไม่ผ่านการตรวจสอบสิทธิ์ซึ่งจะใช้ในการตรวจสอบสิทธิ์ แน่นอนว่านี่ชัดเจน เห็นได้ชัดว่าเป็นองค์กรที่ตระหนักถึงความปลอดภัยทุกอย่างตั้งแต่ธนาคารที่มีสาขาหลายพันแห่งไปจนถึง บริษัท ของฉันเอง 'การแก้ปัญหา' ด้านรหัสลูกค้าด้านการเชื่อถือทั้งหมดใบรับรองรวมถึงใบรับรองลงนามด้วยตนเองลงนามโดยใครแน่นอนหรือร่างกายโดยพลการตั้งตัวเองขึ้นเป็น CA เป็นIPSO อันที่จริงไม่ได้ที่เชื่อถือได้ มันเป็นแค่การเล่นที่ความปลอดภัย มันไม่มีจุดหมาย คุณกำลังสนทนากับใครบางคนที่ยุ่งวุ่นวายป้องกันการตอบรับการฉีดยากับ ... ใครบางคน ใคร ๆ ผู้ชายอยู่ตรงกลาง ตัวตน ใคร ๆ คุณอาจใช้คำธรรมดา


2
เพียงเพราะบางเซิร์ฟเวอร์ตัดสินใจใช้ https ไม่ได้หมายความว่าบุคคลที่มีไคลเอ็นต์จะให้ความปลอดภัยกับจุดประสงค์ของตนเอง
กัส

3
ฉันประหลาดใจที่คำตอบนี้ได้รับการโหวตลดลงมาก ฉันชอบที่จะเข้าใจมากขึ้นว่าทำไม ดูเหมือนว่า EJP จะแนะนำว่าคุณไม่ควรทำตัวเลือกที่ 2 เพราะจะทำให้เกิดข้อบกพร่องด้านความปลอดภัยที่สำคัญ มีคนอธิบายได้ไหมว่าทำไม (นอกเหนือจากการตั้งค่าล่วงหน้า) ทำไมคำตอบนี้ถึงมีคุณภาพต่ำ
cr1pto

2
ฉันเดาทั้งหมด อะไร"มันขึ้นอยู่กับพวกเขาที่จะใช้ขั้นตอนที่จำเป็นเพื่อให้เซิร์ฟเวอร์ของตนสามารถใช้งานได้"หมายถึง? ผู้ให้บริการเซิร์ฟเวอร์ต้องทำอะไรเพื่อให้สามารถใช้งานได้ คุณมีขั้นตอนอะไรในใจ? คุณสามารถให้รายชื่อพวกเขาได้หรือไม่? แต่ก้าวกลับไปที่ 1,000 ฟุตนั่นเป็นสิ่งที่เกี่ยวข้องกับปัญหาที่ OP ถามหรือไม่ เขาต้องการที่จะรู้วิธีที่จะทำให้ลูกค้ายอมรับใบรับรองที่ลงนามด้วยตนเองใน Java นั่นเป็นเรื่องง่ายที่จะให้ความไว้วางใจในรหัสเนื่องจาก OP พบว่าใบรับรองยอมรับได้
jww

2
@EJP - แก้ไขให้ถูกต้องหากฉันผิด แต่การยอมรับใบรับรองที่ลงนามด้วยตนเองเป็นการตัดสินใจเชิงนโยบายของลูกค้า มันไม่เกี่ยวอะไรกับการทำงานของฝั่งเซิร์ฟเวอร์ ลูกค้าจะต้องตัดสินใจ parities ต้องทำงานร่วมกันเพื่อแก้ไขปัญหาการกระจายคีย์ แต่นั่นไม่เกี่ยวข้องกับการทำให้เซิร์ฟเวอร์ใช้งานได้
jww

3
@EJP - แน่นอนฉันไม่ได้พูด"ไว้วางใจใบรับรองทั้งหมด" บางทีฉันอาจขาดอะไรบางอย่าง (หรือคุณกำลังอ่านสิ่งต่าง ๆ มากเกินไป) ... OP มีใบรับรองและเป็นที่ยอมรับของเขา เขาต้องการทราบวิธีเชื่อถือได้ ฉันอาจแยกเส้นผม แต่ใบรับรองไม่จำเป็นต้องส่งแบบออฟไลน์ ออกจากวงของการตรวจสอบควรจะใช้ แต่ที่ไม่เหมือนกัน"จะต้องส่งมอบให้กับลูกค้าครับ" เขาอาจเป็นร้านที่ผลิตเซิร์ฟเวอร์และลูกค้าดังนั้นเขาจึงมีความรู้เบื้องต้น
jww

0

นี่ไม่ใช่วิธีการแก้ปัญหาที่สมบูรณ์ แต่ oracle มีเอกสารรายละเอียดที่ดีเกี่ยวกับวิธีการใช้ keytool นี้ สิ่งนี้จะอธิบายวิธีการ

  1. ใช้ keytool
  2. สร้าง certs / self certs ที่ลงชื่อโดยใช้ keytool
  3. นำเข้า certs ที่สร้างขึ้นไปยังไคลเอนต์ java

https://docs.oracle.com/cd/E54932_01/doc.705/e54936/cssg_create_ssl_cert.htm#CSVSG178


0

แทนที่จะใช้ keytool ตามที่แนะนำโดยความคิดเห็นสูงสุดบน RHEL คุณสามารถใช้ update-ca-trust เริ่มต้นใน RHEL รุ่นใหม่กว่า 6 คุณจะต้องมีใบรับรองในรูปแบบ pem แล้วก็

trust anchor <cert.pem>

แก้ไข /etc/pki/ca-trust/source/cert.p11-kit และเปลี่ยน "หมวดหมู่ใบรับรอง: รายการอื่น ๆ " เป็น "หมวดหมู่ใบรับรอง: ผู้มีอำนาจ" (หรือใช้ sed เพื่อทำสิ่งนี้ในสคริปต์) จากนั้นทำ

update-ca-trust

คำเตือนคู่:

  • ฉันไม่พบ "ความน่าเชื่อถือ" บนเซิร์ฟเวอร์ RHEL 6 ของฉันและ yum ไม่ได้เสนอให้ติดตั้ง ฉันลงเอยด้วยการใช้มันบนเซิร์ฟเวอร์ RHEL 7 และคัดลอกไฟล์. p11-kit ไป
  • update-ca-trust enableเพื่อให้งานนี้สำหรับคุณคุณอาจจำเป็นต้องทำ สิ่งนี้จะแทนที่ / etc / pki / java / cacerts ด้วยลิงก์สัญลักษณ์ที่ชี้ไปที่ / etc / pki / ca-trust / คลายบีบอัด / java / cacerts (ดังนั้นคุณอาจต้องการสำรองข้อมูลอดีตก่อน)
  • หากไคลเอนต์ java ของคุณใช้ cacerts ที่เก็บไว้ในตำแหน่งอื่นคุณจะต้องแทนที่ด้วยตนเองด้วย symlink ไปยัง / etc / pki / ca-trust / คลายบีบอัด / java / cacerts หรือแทนที่ด้วยไฟล์นั้น

0

ฉันมีปัญหาที่ฉันส่ง URL ไปยังห้องสมุดซึ่งเรียกว่าurl.openConnection();ฉันปรับคำตอบของ Jon-daniel

public class TrustHostUrlStreamHandler extends URLStreamHandler {

    private static final Logger LOG = LoggerFactory.getLogger(TrustHostUrlStreamHandler.class);

    @Override
    protected URLConnection openConnection(final URL url) throws IOException {

        final URLConnection urlConnection = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile()).openConnection();

        // adapated from
        // /programming/2893819/accept-servers-self-signed-ssl-certificate-in-java-client
        if (urlConnection instanceof HttpsURLConnection) {
            final HttpsURLConnection conHttps = (HttpsURLConnection) urlConnection;

            try {
                // Set up a Trust all manager
                final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

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

                    @Override
                    public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
                    }

                    @Override
                    public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
                    }
                } };

                // Get a new SSL context
                final SSLContext sc = SSLContext.getInstance("TLSv1.2");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                // Set our connection to use this SSL context, with the "Trust all" manager in place.
                conHttps.setSSLSocketFactory(sc.getSocketFactory());
                // Also force it to trust all hosts
                final HostnameVerifier allHostsValid = new HostnameVerifier() {
                    @Override
                    public boolean verify(final String hostname, final SSLSession session) {
                        return true;
                    }
                };

                // and set the hostname verifier.
                conHttps.setHostnameVerifier(allHostsValid);

            } catch (final NoSuchAlgorithmException e) {
                LOG.warn("Failed to override URLConnection.", e);
            } catch (final KeyManagementException e) {
                LOG.warn("Failed to override URLConnection.", e);
            }

        } else {
            LOG.warn("Failed to override URLConnection. Incorrect type: {}", urlConnection.getClass().getName());
        }

        return urlConnection;
    }

}

เมื่อใช้คลาสนี้จะสามารถสร้าง URL ใหม่ด้วย:

trustedUrl = new URL(new URL(originalUrl), "", new TrustHostUrlStreamHandler());
trustedUrl.openConnection();

URL.openConnectionนี้มีความได้เปรียบที่ว่ามันเป็นภาษาท้องถิ่นและไม่เปลี่ยนค่าเริ่มต้น

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