নির্দিষ্ট সংযোগগুলিতে আমি কীভাবে বিভিন্ন শংসাপত্র ব্যবহার করতে পারি?


164

আমি আমাদের বৃহত জাভা অ্যাপ্লিকেশনটিতে একটি মডিউল যুক্ত করছি অন্য কোম্পানির এসএসএল-সুরক্ষিত ওয়েবসাইটের সাথে কথা বলতে হবে। সমস্যাটি হ'ল সাইটটি স্ব-স্বাক্ষরিত শংসাপত্র ব্যবহার করে। আমি মাঝারি-মধ্যবর্তী আক্রমণটির মুখোমুখি হচ্ছি না তা যাচাই করার জন্য আমার শংসাপত্রের একটি অনুলিপি রয়েছে এবং সার্ভারের সংযোগটি সফল হতে পারে এমনভাবে আমার এই শংসাপত্রটি আমাদের কোডে অন্তর্ভুক্ত করা দরকার।

এখানে মূল কোডটি রয়েছে:

void sendRequest(String dataPacket) {
  String urlStr = "https://host.example.com/";
  URL url = new URL(urlStr);
  HttpURLConnection conn = (HttpURLConnection)url.openConnection();
  conn.setMethod("POST");
  conn.setRequestProperty("Content-Length", data.length());
  conn.setDoOutput(true);
  OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
  o.write(data);
  o.flush();
}

স্ব-স্বাক্ষরিত শংসাপত্রের জন্য কোনও অতিরিক্ত হ্যান্ডলিং ছাড়াই, নিম্নলিখিত ব্যতিক্রম সহ এটি সংযুক্ত.আউটআউটপুটস্ট্রিম () এ মারা যায়:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

আদর্শভাবে, আমার কোডটিকে জাভাকে এই স্ব-স্বাক্ষরিত শংসাপত্রটি গ্রহণের জন্য অ্যাপ্লিকেশনের এই একটি স্পটের জন্য এবং অন্য কোথাও শেখানো দরকার।

আমি জানি যে আমি জেআরই'র শংসাপত্র কর্তৃপক্ষের দোকানে শংসাপত্রটি আমদানি করতে পারি এবং এটি জাভা এটি স্বীকার করার অনুমতি দেবে। আমি যদি সহায়তা করতে পারি তবে আমি নিতে চাই না এটি এমন একটি উপায় নয়; আমাদের গ্রাহকের সমস্ত মেশিন তারা ব্যবহার না করতে পারে এমন একটি মডিউলের জন্য করা খুব আক্রমণাত্মক বলে মনে হয়; এটি একই জেআরই ব্যবহার করে অন্যান্য সমস্ত জাভা অ্যাপ্লিকেশনগুলিকে প্রভাবিত করবে এবং আমি এটি পছন্দ করি না যদিও এই সাইটটিতে অ্যাক্সেস করা অন্য কোনও জাভা অ্যাপ্লিকেশনের প্রতিক্রিয়া শূন্য রয়েছে। এটি কোনও তুচ্ছ অপারেশনও নয়: ইউএনআইএক্স-এ আমাকে এইভাবে জেআরই সংশোধন করার জন্য অ্যাক্সেসের অধিকার অর্জন করতে হবে।

আমি এটিও দেখেছি যে আমি একটি ট্রাস্ট ম্যানেজার উদাহরণ তৈরি করতে পারি যা কিছু কাস্টম চেকিং করে। দেখে মনে হচ্ছে আমি এমনকি একটি ট্রাস্ট ম্যানেজার তৈরি করতে সক্ষম হতে পারি যা এই এক শংসাপত্র ব্যতীত সকল ক্ষেত্রে প্রকৃত ট্রাস্ট ম্যানেজারকে প্রতিনিধি করে। তবে দেখে মনে হচ্ছে বিশ্বস্তভাবে ট্রাস্ট ম্যানেজারটি ইনস্টল হয়ে গেছে এবং আমি ধারণা করছি আমাদের অ্যাপ্লিকেশন থেকে অন্যান্য সমস্ত সংযোগ প্রভাবিত করবে এবং এটি আমার কাছে খুব একটা গন্ধ পাবে না।

স্ব-স্বাক্ষরিত শংসাপত্র গ্রহণ করার জন্য জাভা অ্যাপ্লিকেশন সেটআপ করার পছন্দের, মানক বা সর্বোত্তম উপায় কী? আমি কি আমার উপরে যে লক্ষ্যগুলি রেখেছি তা সবই পূরণ করতে পারি, বা আমাকে আপস করতে হবে? ফাইল এবং ডিরেক্টরি এবং কনফিগারেশন সেটিংস এবং অল্প-টু-নো কোড যুক্ত কোনও বিকল্প রয়েছে?


ছোট, কাজের ফিক্স: rgagnon.com/javadetails/…

20
@ হাসেনপ্রাইস্টার: দয়া করে এই পৃষ্ঠাটি প্রস্তাব করবেন না। এটি সমস্ত বিশ্বাস যাচাইকরণ অক্ষম করে। আপনি কেবল নিজের স্ব-স্বাক্ষরিত শংসাপত্রটি গ্রহণ করতে যাচ্ছেন না, একজন এমআইটিএম আক্রমণকারী আপনাকে উপস্থাপন করবে এমন কোনও শংসাপত্রও গ্রহণ করতে পারেন।
ব্রুনো

উত্তর:


168

SSLSocketনিজে একটি কারখানা তৈরি করুন এবং HttpsURLConnectionসংযোগের আগে এটিকে সেট করুন ।

...
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslFactory);
conn.setMethod("POST");
...

আপনি একটি তৈরি করতে SSLSocketFactoryএবং এটি চারপাশে রাখতে চাইবেন । এটি কীভাবে শুরু করা যায় তার একটি স্কেচ এখানে দেওয়া হয়েছে:

/* Load the keyStore that includes self-signed cert as a "trusted" entry. */
KeyStore keyStore = ... 
TrustManagerFactory tmf = 
  TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
sslFactory = ctx.getSocketFactory();

আপনার যদি মূল স্টোরটি তৈরি করতে সহায়তা প্রয়োজন হয় তবে মন্তব্য করুন।


মূল স্টোর লোড করার একটি উদাহরণ এখানে:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(trustStore, trustStorePassword);
trustStore.close();

পিইএম ফর্ম্যাট শংসাপত্রের সাথে কী স্টোরটি তৈরি করতে, আপনি নিজের কোডটি ব্যবহার করে লিখতে পারেন CertificateFactory, বা keytoolজেডিকে থেকে এটি আমদানি করতে পারেন (কীটোল "কী এন্ট্রি" এর জন্য কাজ করবে না , তবে "বিশ্বাসযোগ্য এন্ট্রি" এর জন্য ঠিক আছে )।

keytool -import -file selfsigned.pem -alias server -keystore server.jks

3
আপনাকে অনেক ধন্যবাদ! অন্যান্য ছেলেরা আমাকে সঠিক দিকে নির্দেশ করতে সহায়তা করেছিল, তবে শেষ পর্যন্ত আপনারাই আমার গ্রহণ করা পন্থা। আমি একটি JKS জাভা কীস্টোর ফাইল অবশ্যই PEM শংসাপত্র ফাইল রূপান্তর একটি কঠোর টাস্ক ছিল, এবং আমি যে এখানে সহায়তা পাওয়া যায়নি: stackoverflow.com/questions/722931/...
skiphoppy

1
আমি আনন্দিত এটি কাজ করে। আমি দুঃখিত আপনি কী স্টোরের সাথে লড়াই করেছেন; আমার সবেমাত্র এটি আমার উত্তরে অন্তর্ভুক্ত করা উচিত ছিল। শংসাপত্র কারখানার সাথে এটি খুব বেশি কঠিন নয়। আসলে, আমি ভাবি যে পরে যে কেউ আসবে তার জন্য আমি একটি আপডেট করব।
এরিকসন

1
এই সমস্ত কোডটি জেএসএসই রেফারেন্স গাইডে বর্ণিত তিনটি সিস্টেমের বৈশিষ্ট্য সেট করে যা অর্জন করতে পারে তার প্রতিলিপি।
লার্নের মারকুইস

2
@ এজেপি: এটি কিছুক্ষণ আগে ছিল, তাই আমি নিশ্চিত মনে রাখছি না, তবে আমি অনুমান করছি যে "বড় জাভা অ্যাপ্লিকেশন" এর মধ্যে অন্যান্য এইচটিটিপি সংযোগ স্থাপনের সম্ভাবনা রয়েছে। বৈশ্বিক বৈশিষ্ট্যগুলি নির্ধারণ করা কাজের সংযোগগুলিতে হস্তক্ষেপ করতে পারে বা এই একটি পক্ষকে সার্ভারগুলি স্পুফ করার অনুমতি দেয়। কেস বাই কেস ভিত্তিতে বিল্ট-ইন ট্রাস্ট ম্যানেজার ব্যবহারের এটি উদাহরণ।
এরিকসন

2
ওপি যেমন বলেছে, "আমার কোডটিতে জাভাকে এই স্ব-স্বাক্ষরিত শংসাপত্রটি গ্রহণের জন্য অ্যাপ্লিকেশনের এই এক স্পটটির জন্য এবং অন্য কোথাও শেখানো দরকার" "
এরিকসন

18

এই জিনিসটি সমাধান করার জন্য আমি অনলাইনে প্রচুর জায়গাগুলির মাধ্যমে পড়েছি। এটিকে কার্যকর করার জন্য আমি এই কোডটি লিখেছি:

ByteArrayInputStream derInputStream = new ByteArrayInputStream(app.certificateString.getBytes());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
String alias = "alias";//cert.getSubjectX500Principal().getName();

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(trustStore, null);
KeyManager[] keyManagers = kmf.getKeyManagers();

TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
URL url = new URL(someURL);
conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(sslContext.getSocketFactory());

app.cerificationsateString একটি স্ট্রিং যা শংসাপত্র রয়েছে, উদাহরণস্বরূপ:

static public String certificateString=
        "-----BEGIN CERTIFICATE-----\n" +
        "MIIGQTCCBSmgAwIBAgIHBcg1dAivUzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE" +
        "BhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBE" +
        ... a bunch of characters...
        "5126sfeEJMRV4Fl2E5W1gDHoOd6V==\n" +
        "-----END CERTIFICATE-----";

আমি পরীক্ষা করে দেখেছি যে আপনি যদি স্বর স্বাক্ষরিত হন তবে শংসাপত্রের স্ট্রিংয়ে যে কোনও অক্ষর রাখতে পারেন, যতক্ষণ আপনি উপরে সঠিক কাঠামোটি রাখেন না। আমি আমার ল্যাপটপের টার্মিনাল কমান্ড লাইনের সাথে শংসাপত্রের স্ট্রিংটি পেয়েছি।


1
@ জোশ ভাগ করে নেওয়ার জন্য ধন্যবাদ। আমি একটি ছোট গিথুব প্রজেক্ট তৈরি করেছি যা আপনার কোডটি ব্যবহারে প্রদর্শন করে: github.com/aasaru/ConnectToTrustedServerExample
মাস্টার ড্রলস

14

যদি কোনও তৈরি করা SSLSocketFactoryকোনও বিকল্প না হয় তবে কেবল কীটি JVM এ আমদানি করুন

  1. সর্বজনীন কী পুনরুদ্ধার করুন: $openssl s_client -connect dev-server:443, তারপর ফাইল তৈরি দেব-server.pem দেখে মনে হচ্ছে যে

    -----BEGIN CERTIFICATE----- 
    lklkkkllklklklklllkllklkl
    lklkkkllklklklklllkllklkl
    lklkkkllklk....
    -----END CERTIFICATE-----
    
  2. কী আমদানি: #keytool -import -alias dev-server -keystore $JAVA_HOME/jre/lib/security/cacerts -file dev-server.pem। পাসওয়ার্ড: changeit

  3. জেভিএম পুনরায় চালু করুন

উত্স: javax.net.ssl.SSLHandshakeException কীভাবে সমাধান করবেন?


1
আমি মনে করি না এটি মূল প্রশ্নটি সমাধান করে, তবে এটি আমার সমস্যার সমাধান করেছে , তাই ধন্যবাদ!
এড নরিস

এটি করা এটিও দুর্দান্ত ধারণা নয়: এখন আপনার কাছে এই এলোমেলো অতিরিক্ত সিস্টেম প্রশস্ত স্ব স্ব স্বাক্ষরযুক্ত শংসাপত্র রয়েছে যা সমস্ত জাভা প্রক্রিয়াগুলি ডিফল্টরূপে বিশ্বাস করবে।
ব্যবহারকারী268396

12

আমরা জেআরই এর ট্রাস্টস্টোর অনুলিপি করি এবং সেই ট্রাস্টস্টোরে আমাদের কাস্টম শংসাপত্র যুক্ত করি, তারপরে একটি সিস্টেম সম্পত্তি সহ কাস্টম ট্রাস্টস্টোরটি ব্যবহার করতে অ্যাপ্লিকেশনটিকে বলি। এইভাবে আমরা ডিফল্ট জেআরই ট্রাস্টস্টোরকে একা রেখে যাই।

খারাপ দিকটি হ'ল আপনি যখন জেআরই আপডেট করেন আপনি এটির নতুন ট্রাস্টস্টোরটি স্বয়ংক্রিয়ভাবে আপনার কাস্টমটির সাথে একত্রীভূত হন না।

আপনি সম্ভবত কোনও ইনস্টলার বা স্টার্টআপ রুটিন যা ট্রাস্টস্টোর / জেডিকে যাচাই করে এবং কোনও মিল খুঁজে না যায় বা স্বয়ংক্রিয়ভাবে ট্রাস্টোর স্টোর আপডেট করে এই পরিস্থিতিটি পরিচালনা করতে পারেন। অ্যাপ্লিকেশন চলাকালীন আপনি ট্রাস্টস্টোর আপডেট করলে কী হয় তা আমি জানি না।

এই সমাধানটি 100% মার্জিত বা বুদ্ধিমানের নয় তবে এটি সহজ, কাজ করে এবং কোনও কোডের প্রয়োজন হয় না।


12

স্ব-স্বাক্ষরিত শংসাপত্রের সাথে অভ্যন্তরীণ https সার্ভারটি অ্যাক্সেস করতে কমন্স-httpclient ব্যবহার করার সময় আমাকে এই জাতীয় কিছু করতে হয়েছিল। হ্যাঁ, আমাদের সমাধানটি হ'ল একটি কাস্টম ট্রাস্ট ম্যানেজার তৈরি করা যা কেবল সমস্ত কিছু পাস করে (একটি ডিবাগ বার্তা লগইন করে)।

এটি আমাদের নিজস্ব এসএসএসকেটফ্যাক্টরিতে নেমে আসে যা আমাদের স্থানীয় এসএসএল কনটেক্সট থেকে এসএসএল সকেট তৈরি করে, যা এটির সাথে কেবল আমাদের স্থানীয় ট্রাস্ট ম্যানেজারের সাথে যুক্ত রয়েছে set আপনার মোটেও কোনও কীস্টোর / সার্টিস্টোরের কাছে যাওয়ার দরকার নেই।

সুতরাং এটি আমাদের লোকাল এসএসএলসকেট ফ্যাক্টরিতে রয়েছে:

static {
    try {
        SSL_CONTEXT = SSLContext.getInstance("SSL");
        SSL_CONTEXT.init(null, new TrustManager[] { new LocalSSLTrustManager() }, null);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Unable to initialise SSL context", e);
    } catch (KeyManagementException e) {
        throw new RuntimeException("Unable to initialise SSL context", e);
    }
}

public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
    LOG.trace("createSocket(host => {}, port => {})", new Object[] { host, new Integer(port) });

    return SSL_CONTEXT.getSocketFactory().createSocket(host, port);
}

সিকিউরপ্রোটোকলসকেট ফ্যাক্টরি প্রয়োগকারী অন্যান্য পদ্ধতির সাথে। স্থানীয় এসএসএল ট্রাস্টম্যানেজারটি পূর্বোক্ত ডামি ট্রাস্ট ম্যানেজার বাস্তবায়ন।


8
আপনি যদি সমস্ত বিশ্বাস যাচাইকরণ অক্ষম করেন তবে এসএসএল / টিএলএস প্রথম স্থানে ব্যবহার করার সামান্য বিষয় রয়েছে। এটি স্থানীয়ভাবে পরীক্ষার জন্য ঠিক আছে, তবে আপনি যদি বাইরে সংযোগ স্থাপন করতে চান তবে তা নয়।
ব্রুনো

জাভা on. এ চালানোর সময় আমি এই ব্যতিক্রমটি পাই j
উরি লুকাচ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.