HTTPS / SSL पर जावा क्लाइंट सर्टिफिकेट


116

मैं जावा 6 का उपयोग कर रहा हूं और HttpsURLConnectionक्लाइंट सर्टिफिकेट का उपयोग कर रिमोट सर्वर के खिलाफ बनाने की कोशिश कर रहा हूं ।
सर्वर स्व-निर्दिष्ट रूट प्रमाणपत्र का उपयोग कर रहा है, और इसके लिए पासवर्ड-संरक्षित क्लाइंट प्रमाणपत्र प्रस्तुत करना पड़ता है। मैंने सर्वर रूट सर्टिफिकेट और क्लाइंट सर्टिफिकेट को डिफॉल्ट जावा कीस्टोर में जोड़ा है जो मुझे /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/security/cacerts(OSX 10.5) में मिला है । कीस्टोर फ़ाइल का नाम ऐसा प्रतीत होता है कि ग्राहक प्रमाणपत्र को वहां नहीं जाना है?

वैसे भी, इस स्टोर में रूट सर्टिफिकेट को जोड़ने से कुख्यात हल हो गया javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed' problem.

हालाँकि, मैं अब इस बात पर अड़ा हुआ हूं कि क्लाइंट सर्टिफिकेट का उपयोग कैसे किया जाए। मैं दो तरीकों की कोशिश की है और न ही मुझे कहीं भी मिलता है।
सबसे पहले, और पसंदीदा, कोशिश करें:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://somehost.dk:3049");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
// The last line fails, and gives:
// javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

मैंने HttpsURLConnection वर्ग को छोड़ देने की कोशिश की है (आदर्श नहीं है क्योंकि मैं सर्वर से HTTP बात करना चाहता हूं), और इसके बजाय यह करें:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("somehost.dk", 3049);
InputStream inputstream = sslsocket.getInputStream();
// do anything with the inputstream results in:
// java.net.SocketTimeoutException: Read timed out

मुझे यह भी पक्का नहीं है कि क्लाइंट सर्टिफिकेट यहां की समस्या है।


मैं ग्राहक से दो प्रमाण पत्र दे दिया है जो एक की जरूरत है कुंजीस्टोर में जोड़ने के लिए पहचान करने के लिए कैसे और truststore यदि आपको मदद की इस समस्या को पहचानने के रूप में आप पहले से ही जारी किए जाने की समान प्रकार के माध्यम से चले गए हैं तो कृपया सकता है stackoverflow.com/questions/61374276/...
henrycharles

जवाबों:


100

अंत में इसे हल किया;); यहां एक मजबूत संकेत मिला (गैंडाल्स उत्तर ने उस पर थोड़ा सा स्पर्श किया)। नीचे दिए गए मापदंडों में से लापता लिंक (ज्यादातर) था, और कुछ हद तक कि मैंने कीस्टोर्स और ट्रस्टीओर्स के बीच के अंतर को अनदेखा किया था।

स्व-हस्ताक्षरित सर्वर प्रमाणपत्र को एक ट्रस्टस्टोर में आयात किया जाना चाहिए:

keytool -import -alias gridserver -file gridserver.crt -storepass $ PASS -keystore gridserver.keystore

इन गुणों को सेट करने की आवश्यकता है (या तो कमांडलाइन पर, या कोड में):

-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=gridserver.keystore
-Djavax.net.debug=ssl # very verbose debug
-Djavax.net.ssl.keyStorePassword=$PASS
-Djavax.net.ssl.trustStorePassword=$PASS

कार्य उदाहरण कोड:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://gridserver:3049/cgi-bin/ls.py");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

String string = null;
while ((string = bufferedreader.readLine()) != null) {
    System.out.println("Received " + string);
}

मैं एक यूआरएल का उपयोग करता हूं जैसे: लोकलहोस्ट: 8443 / Application_Name / getAttributes । मेरे पास एक तरीका है / getAttribute url मैपिंग। यह विधि तत्वों की सूची लौटाती है। मैंने HttpsUrlConnection का उपयोग किया है, कनेक्शन रिपीट कोड 200 है, लेकिन इसकी विशेषता सूची मुझे नहीं दे रही है जब मैं inputStream का उपयोग करता हूं, तो यह मुझे मेरे लॉगिन पृष्ठ की HTML सामग्री प्रदान करता है। मैंने प्रमाणीकरण किया है और JSON के रूप में सामग्री प्रकार सेट किया है। कृपया सुझाव दें
दीपक

83

अनुशंसित नहीं होने पर, आप SSL प्रमाणपत्र सत्यापन को पूरी तरह से अक्षम कर सकते हैं:

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

public class SSLTool {

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

    // Ignore differences between given hostname and certificate hostname
    HostnameVerifier hv = new HostnameVerifier() {
      public boolean verify(String hostname, SSLSession session) { return true; }
    };

    // Install the all-trusting trust manager
    try {
      SSLContext sc = SSLContext.getInstance("SSL");
      sc.init(null, trustAllCerts, new SecureRandom());
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
      HttpsURLConnection.setDefaultHostnameVerifier(hv);
    } catch (Exception e) {}
  }
}

72
यह ध्यान दिया जाना चाहिए कि प्रमाणपत्र सत्यापन को अक्षम करना इस तरह संभव MITM हमलों के कनेक्शन को खोलता है: उत्पादन में उपयोग न करें
ब्रूनो

3
कोड संकलित नहीं करता है, शुक्र है। यह 'समाधान' मौलिक रूप से असुरक्षित है।
लोर्ने

5
@ neu242, नहीं, यह वास्तव में इस बात पर निर्भर नहीं करता है कि आप इसके लिए क्या उपयोग करते हैं। यदि आप SSL / TLS का उपयोग करना चाहते हैं, तो आप MITM हमलों के खिलाफ अपने कनेक्शन को सुरक्षित करना चाहते हैं, यही पूरा बिंदु है। सर्वर प्रमाणीकरण आवश्यक नहीं है यदि आप गारंटी दे सकते हैं कि कोई भी ट्रैफ़िक को बदलने में सक्षम नहीं होगा, लेकिन जिन स्थितियों पर आपको संदेह है, वे ईवसड्रॉपर हो सकते हैं जो नेटवर्क ट्रैफ़िक को भी बदलने की स्थिति में नहीं होंगे, वे भी बहुत दुर्लभ हैं।
ब्रूनो

1
@ neu242 कोड स्निपेट के लिए धन्यवाद। मैं वास्तव में एक बहुत ही विशिष्ट उद्देश्य (वेब ​​क्रॉलिंग) के लिए उत्पादन में इसका उपयोग करने के बारे में सोच रहा हूं, और मैंने आपके प्रश्न ( stackoverflow.com/questions/13076511/… ) में आपके कार्यान्वयन का उल्लेख किया है । यदि आपके पास समय है, तो क्या आप कृपया इसे देख सकते हैं, और मुझे बता सकते हैं कि क्या कोई सुरक्षा जोखिम हैं जो मुझे याद हैं?
साल

1
@Bruno अगर मैं केवल सर्वर को पिंग कर रहा हूं, तो क्या यह वास्तव में मुझे MITM हमलों से प्रभावित करेगा?
फूनोएन

21

क्या आपने KeyStore और / या TrustStore सिस्टम गुण सेट किए हैं?

java -Djavax.net.ssl.keyStore=pathToKeystore -Djavax.net.ssl.keyStorePassword=123456

या कोड के साथ

System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);

Javax.net.ssl.trustStore के साथ भी


13

यदि आप एक्सिस फ्रेमवर्क का उपयोग कर एक वेब सेवा कॉल के साथ काम कर रहे हैं, तो बहुत सरल उत्तर है। यदि सभी चाहते हैं कि आपके ग्राहक एसएसएल वेब सेवा को कॉल करने में सक्षम हों और एसएसएल प्रमाणपत्र त्रुटियों को अनदेखा करें, तो बस किसी भी वेब सेवाओं को लागू करने से पहले यह विवरण दें:

System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory");

सामान्य रूप से इस बारे में अस्वीकरण एक उत्पादन वातावरण में करने के लिए एक बहुत खराब बात है।

मुझे यह एक्सिस विकी में मिला


ओपी एक HttpsURLConnection के साथ काम कर रहा है, न कि एक्सिस
neu242

2
मै समझता हुँ। मेरा मतलब यह नहीं था कि सामान्य मामले में मेरा जवाब बेहतर था। यह सिर्फ इतना है कि यदि आप एक्सिस ढांचे का उपयोग कर रहे हैं , तो आपके पास उस संदर्भ में ओपी का प्रश्न हो सकता है। (यही कारण है कि मैंने इस सवाल को पहली जगह में पाया है।) उस मामले में, मैंने जो तरीका प्रदान किया है वह सरल है।
मार्क मेउर

5

मेरे लिए, यह अपाचे HttpCompords ~ HttpClient 4.x का उपयोग करके काम किया है:

    KeyStore keyStore  = KeyStore.getInstance("PKCS12");
    FileInputStream instream = new FileInputStream(new File("client-p12-keystore.p12"));
    try {
        keyStore.load(instream, "helloworld".toCharArray());
    } finally {
        instream.close();
    }

    // Trust own CA and all self-signed certs
    SSLContext sslcontext = SSLContexts.custom()
        .loadKeyMaterial(keyStore, "helloworld".toCharArray())
        //.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) //custom trust store
        .build();
    // Allow TLSv1 protocol only
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //TODO
    CloseableHttpClient httpclient = HttpClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) //TODO
        .setSSLSocketFactory(sslsf)
        .build();
    try {

        HttpGet httpget = new HttpGet("https://localhost:8443/secure/index");

        System.out.println("executing request" + httpget.getRequestLine());

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    } finally {
        httpclient.close();
    }

P12 फ़ाइल में क्लाइंट प्रमाणपत्र और क्लाइंट निजी कुंजी है, जिसे BouncyCastle के साथ बनाया गया है:

public static byte[] convertPEMToPKCS12(final String keyFile, final String cerFile,
    final String password)
    throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException,
    NoSuchProviderException
{
    // Get the private key
    FileReader reader = new FileReader(keyFile);

    PEMParser pem = new PEMParser(reader);
    PEMKeyPair pemKeyPair = ((PEMKeyPair)pem.readObject());
    JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter().setProvider("BC");
    KeyPair keyPair = jcaPEMKeyConverter.getKeyPair(pemKeyPair);

    PrivateKey key = keyPair.getPrivate();

    pem.close();
    reader.close();

    // Get the certificate
    reader = new FileReader(cerFile);
    pem = new PEMParser(reader);

    X509CertificateHolder certHolder = (X509CertificateHolder) pem.readObject();
    java.security.cert.Certificate x509Certificate =
        new JcaX509CertificateConverter().setProvider("BC")
            .getCertificate(certHolder);

    pem.close();
    reader.close();

    // Put them into a PKCS12 keystore and write it to a byte[]
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
    ks.load(null);
    ks.setKeyEntry("key-alias", (Key) key, password.toCharArray(),
        new java.security.cert.Certificate[]{x509Certificate});
    ks.store(bos, password.toCharArray());
    bos.close();
    return bos.toByteArray();
}

वह keyStoreहै जिसमें निजी कुंजी और प्रमाणपत्र शामिल हैं।
एपिकपांडाफॉर्सेज

1
आपको काम करने के लिए ConvertPEMtoP12 कोड के लिए इन 2 निर्भरताओं को शामिल करने की आवश्यकता है: <निर्भरता> <groupId> org.b Councilycastle </ groupId> <विरूपण साक्ष्य> bcprov-jdk155 </ विरूपण साक्ष्य> <संस्करण> 1.53 </ संस्करण> </ निर्भरता> निर्भरता> <groupId> org.b Councilycastle </ groupId> <विरूपण साक्ष्य> bcpkix-jdk15on </ विरूपण साक्ष्य> <संस्करण> 1.53 </ संस्करण> </ निर्भरता
O

@EpicPandaForce में मुझे एक त्रुटि मिलती है: पकड़ा गया: org.codehaus.groovy.runtime.typehandling.GroovyCastException: कक्षा के साथ ऑब्जेक्ट नहीं डाल सकते हैं। org.b Councilycastle .jcajce.provider.asymmetric.x509.X509CertificateObjectOjectject setKeyEntry - कोई भी सुराग क्या गलत हो सकता है
विशाल बियानी

हाँ, आप कड़ाई से टाइप की गई भाषा के बजाय ग्रूवी का उपयोग कर रहे हैं। (तकनीकी रूप से यह विधि एक आईडी और एक प्रमाण पत्र लेती है, न कि केवल एक प्रमाण पत्र)
एपिकपांडफ्रीज

4

मैं अपने वर्तमान प्रोजेक्ट में ऐसा करने के लिए अपाचे कॉमन्स HTTP क्लाइंट पैकेज का उपयोग करता हूं और यह एसएसएल और एक स्व-हस्ताक्षरित प्रमाण पत्र के साथ ठीक काम करता है (इसे आपके द्वारा बताए गए कैचर में इंस्टॉल करने के बाद)। कृपया इसे यहाँ देखें:

http://hc.apache.org/httpclient-3.x/tutorial.html

http://hc.apache.org/httpclient-3.x/sslguide.html


1
यह एक बहुत साफ पैकेज की तरह लगता है, लेकिन वर्ग है कि यह सब काम करना चाहिए 'AuthSSLProtocolSocketFactory' आधिकारिक तौर पर आधिकारिक वितरण का हिस्सा नहीं है, न ही 4.0beta में (जारी नोटों के बावजूद कि यह है), या 3.1। मैं इसके साथ एक बिट के आसपास काट दिया है और अब यह कनेक्शन छोड़ने से पहले स्थायी रूप से एक 5 मिनट लटका के साथ अटक गया लगता है। यह वास्तव में अजीब है - अगर मैं सीए और क्लाइंट को किसी भी ब्राउज़र में प्रमाणित करता हूं, तो यह उड़ जाता है।
जनवरी

1
अपाचे HTTP क्लाइंट 4 को SSLContextसीधे ले जा सकते हैं , इसलिए आप उपयोग करने के बजाय, यह सब इस तरह से कॉन्फ़िगर कर सकते हैं AuthSSLProtocolSocketFactory
ब्रूनो

1
क्या एक बाहरी कीस्टॉर के माध्यम से सभी क्लाइंट सर्टिफिकेट सामान को मेमोरी में करने का कोई तरीका है?
श्रीधर सरनोबत

4

मुझे लगता है कि आपके पास अपने सर्वर प्रमाणपत्र के साथ एक मुद्दा है, एक वैध प्रमाण पत्र नहीं है (मुझे लगता है कि इस मामले में "हैंडशेक_फेल्योर" का मतलब है):

क्लाइंट के JRE पर अपने ट्रस्ट सर्किल में अपने सर्वर प्रमाणपत्र को आयात करें। यह आसानी से कीटल के साथ किया जाता है :

keytool
    -import
    -alias <provide_an_alias>
    -file <certificate_file>
    -keystore <your_path_to_jre>/lib/security/cacerts

मैंने सफाई शुरू करने और ऊपर जाने की कोशिश की, और हैंडशेक की विफलता चली गई। अब मैं कनेक्शन समाप्त होने से पहले सिर्फ 5 मिनट की मृत चुप्पी प्राप्त करता हूं: ओ
जनवरी

1

नीचे दिए गए कोड का उपयोग करना

-Djavax.net.ssl.keyStoreType=pkcs12

या

System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);

आवश्यक नहीं है। इसके अलावा अपने खुद के कस्टम एसएसएल कारखाने बनाने की कोई जरूरत नहीं है।

मुझे भी इसी मुद्दे का सामना करना पड़ा, मेरे मामले में एक मुद्दा यह था कि पूर्ण प्रमाणपत्र श्रृंखला को ट्रस्टस्टोर्स में आयात नहीं किया गया था। Keytool उपयोगिता सही fom रूट प्रमाणपत्र का उपयोग करके आयात प्रमाण पत्र, आप नोटपैड में कैसर्ट फ़ाइल भी खोल सकते हैं और देख सकते हैं कि पूर्ण प्रमाण पत्र श्रृंखला आयात की गई है या नहीं। प्रमाण पत्र आयात करते समय आपके द्वारा दिए गए उपनाम नाम के खिलाफ जांच करें, प्रमाण पत्र खोलें और देखें कि इसमें कितने हैं, उसी संख्या के प्रमाण पत्र कैसर्ट फ़ाइल में होने चाहिए।

साथ ही कैसैटर फ़ाइल को आपके द्वारा चलाए जा रहे सर्वर में कॉन्फ़िगर किया जाना चाहिए, दो सर्वर सार्वजनिक / निजी कुंजी के साथ एक दूसरे को प्रमाणित करेंगे।


अपनी खुद की कस्टम एसएसएल फैक्ट्री बनाना दो प्रणाली गुणों को स्थापित करने की तुलना में बहुत अधिक जटिल और त्रुटि-प्रवण है।
लोर्ने का
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.