2012-10-15 12 views
5

जावा में जेएसएसई का उपयोग टीएलएस के साथ करते हुए। मैंने सर्वर और क्लाइंट के बीच एक सुरक्षित सॉकेट बनाया है। अंततः सॉकेट को सुरक्षित रूप से कनेक्ट करने के बाद, मेरे पास अभी भी मेरे मौजूदा कोड की सुरक्षा के बारे में एक मौलिक सवाल है। मैंने एक ट्यूटोरियल में निर्देशों का पालन किया, और कभी-कभी जावाडॉक में प्रलेखन बहुत सटीक है लेकिन थोड़ी अस्पष्ट है जब तक कि आप शब्दकोष की स्वैली बोली बोलते हैं ....जावा जेएसएसई टीएलएस - क्या यह कनेक्शन दोनों दिशाओं में सुरक्षित रूप से एन्क्रिप्ट किया गया है?

मैं सी ++ में काफी समय से नेटवर्क प्रोग्रामिंग कर रहा हूं। जावा में संक्रमण आसान था। हाल ही में, हालांकि, मुझे यातायात को सुरक्षित बनाने के लिए समझदार पाया गया है। यह कहा जा रहा है:

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

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

  1. मैं एक सार्वजनिक/निजी कुंजी फ़ाइलें public.key और private.key में संग्रहीत जोड़ी (i इन JSSE के Keytool सुविधा का उपयोग
  2. मैं ग्राहक में public.key शामिल
  3. मैं निजी शामिल किए गए है। सर्वर में महत्वपूर्ण

ग्राहक वर्ग:

KeyStore keyStore; 
    TrustManagerFactory tmf; 
    KeyManagerFactory kmf; 
    SSLContext sslContext; 
    SecureRandom secureRandom = new SecureRandom(); 
    secureRandom.nextInt(); 

     keyStore = KeyStore.getInstance("JKS"); 
     keyStore.load(this.getClass().getClassLoader().getResourceAsStream("server.public"),"public".toCharArray()); 
     tmf = TrustManagerFactory.getInstance("SunX509"); 
     tmf.init(keyStore); 
     kmf = KeyManagerFactory.getInstance("SunX509"); 
     kmf.init(keyStore, "public".toCharArray()); 
     sslContext = SSLContext.getInstance("TLS"); 
     sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), secureRandom); 
     SSLSocketFactory sslsocketfactory = sslContext.getSocketFactory(); 
     SSLSocket sslsocket = (SSLSocket)sslsocketfactory.createSocket("localhost", 9999); 

सर्वर वर्ग:

String passphrase = "secret" 
    KeyStore keyStore; 
    TrustManagerFactory tmf; 
    KeyManagerFactory kmf; 
    SSLContext sslContext; 
    SecureRandom secureRandom = new SecureRandom(); 
    secureRandom.nextInt(); 

     keyStore = KeyStore.getInstance("JKS"); 
     keyStore.load(this.getClass().getClassLoader().getResourceAsStream("server.private"),passphrase.toCharArray()); 
     tmf = TrustManagerFactory.getInstance("SunX509"); 
     tmf.init(keyStore); 
     kmf = KeyManagerFactory.getInstance("SunX509"); 
     kmf.init(keyStore, passphrase.toCharArray()); 
     sslContext = SSLContext.getInstance("TLS"); 
     sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), secureRandom); 
     SSLServerSocketFactory sslserversocketfactory = sslContext.getServerSocketFactory(); 
     SSLServerSocket sslserversocket = 
     (SSLServerSocket)sslserversocketfactory.createServerSocket(9999); 

/* ** * ** * प्रश्न * ** * ** * */

सब कुछ काम करता है! मैं BufferedReader और BufferedWriter को सॉकेट संलग्न करता हूं और स्वीकार करने के बाद खूबसूरती से आगे और आगे बात करना शुरू करता हूं; क्लाइंट से कनेक्शन दर्ज करना और मेरे क्लाइंट और सर्वर को लूप भेजना/प्राप्त करना।

अब मुझे पता है कि इस बिंदु पर क्लाइंट सर्वर संचार सुरक्षित है। केवल सर्वर कुंजी क्लाइंट से आने वाले ट्रैफ़िक को डिक्रिप्ट कर सकती है। लेकिन क्लाइंट संचार के लिए सर्वर के बारे में क्या? क्लाइंट की कुंजी सर्वर से आने वाले संदेशों को डिक्रिप्ट कर सकती है, लेकिन पब्लिक की क्रिप्टो 101 में आप सीखते हैं कि क्लाइंट अब सर्वर पर सार्वजनिक कुंजी भेजना चाहता है। क्या यह इस कोड में दृश्यों के पीछे हो रहा है? क्या SSLContext इसका ख्याल रखता था? या अब मेरे पास क्लाइंट से सर्वर से एन्क्रिप्टेड कनेक्शन है, क्या अब मुझे क्लाइंट के लिए एक निजी/सार्वजनिक कुंजी जोड़ी उत्पन्न करने की उम्मीद है?

मुझे बताएं कि उपर्युक्त कोड में भेजा गया या प्राप्त ट्रैफ़िक वास्तव में दोनों दिशाओं में सुरक्षित है या नहीं।

+0

कैसे आप क्लाइंट और सर्वर पर private.key पर public.key "शामिल हैं" था ?? – raghav

उत्तर

1

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

एक अन्य गायब टुकड़ा यह है कि एसएसएल क्लाइंट और सर्वर के बीच नेटवर्क यातायात भेजने के लिए पीकेआई का उपयोग नहीं करता है। यह सममित एन्क्रिप्शन एल्गोरिदम का उपयोग करता है। हालांकि सममित एन्क्रिप्शन (जिसे सत्र कुंजी कहा जाता है) की कुंजी जटिल जटिल चुनौती-प्रतिक्रिया प्रोटोकॉल का उपयोग करके स्थापित की जाती है जो पीकेआई और प्रमाणपत्रों को नियोजित करती है। इस चरण के दौरान सर्वर क्लाइंट को साबित करता है कि यह मध्य में मनुष्य नहीं है, क्लाइंट वैकल्पिक रूप से सर्वर के प्रमाण पत्र को साबित कर सकता है यदि उसके पास मजबूत प्रमाणीकरण के लिए कोई है, और सममित सत्र कुंजी स्थापित है। अधिक जानकारी के लिए यहाँ हैं http://tools.ietf.org/html/rfc5246

सममित कुंजी RC5 या एईएस की तरह एल्गोरिदम का उपयोग करते यातायात एन्क्रिप्ट करने के लिए प्रयोग किया जाता है

+0

आपकी प्रतिक्रिया के लिए धन्यवाद, लेकिन मैं क्या सोच रहा था कि यदि टीएलएस के लिए जेएसईई के एपीआई का यह कार्यान्वयन सर्वर से क्लाइंट को एन्क्रिप्ट कर रहा है (कोड मैंने पोस्ट किया है) या कोई क्लाइंट सार्वजनिक कुंजी के साथ सक्षम होने जा रहा है सर्वर से क्लाइंट को यातायात डिक्रिप्ट करें? – SigSeg

+1

नोप, टीएलएस और एसएसएल पॉइंट-टू-पॉइंट गोपनीयता को इंगित करते हैं। हैंडशेक में उत्पन्न सममित सत्र कुंजी में क्लाइंट द्वारा उत्पन्न यादृच्छिक डेटा का एक टुकड़ा होता है और सर्वर सार्वजनिक कुंजी के साथ एन्क्रिप्ट किया जाता है। तो केवल सर्वर की निजी कुंजी वाले लोग इसे समझने में सक्षम हैं। यह यादृच्छिक डेटा यातायात के वास्तविक एन्क्रिप्शन के लिए उपयोग की जाने वाली सत्र कुंजी उत्पन्न करने के लिए उपयोग किया जाता है। इस प्रकार, सर्वर की निजी कुंजी के बिना वे सर्वर पर जा रहे इस डेटा को समझने में सक्षम नहीं होंगे और बाद में एन्क्रिप्टेड ट्रैफ़िक पर स्नूप करने के लिए सत्र कुंजी नहीं होगी। – Vlad

+0

वैसे यह अच्छी खबर है। कुछ भी वास्तव में कहता है कि "यह विधि दस्तावेज़ों में 2-तरफा संचार सुरक्षित करने के लिए सत्र कुंजी उत्पन्न करती है", या यदि यह सूक्ष्म है। पीकेआई पर पढ़ने और इस ट्यूटोरियल को ढूंढने के बाद मैं सोच रहा था कि प्रारंभिक सॉकेट स्थापित करने और विभिन्न ग्राहकों के लिए अलग-अलग कुंजियों को प्रबंधित करने के बाद मुझे क्लाइंट से सर्वर पर किसी अन्य सॉकेट पर बातचीत करना होगा ... यह देखने में खुशी है कि यह सब संभाला गया है। बीटीडब्लू मैंने पाया कि ट्यूटोरियल, अभी तक का सबसे अच्छा, http://www.cs.wmich.edu/~alfuqaha/Spring07/cs6030/lectures/jsse.pdf – SigSeg

6

SSL/TLS में प्रमाण पत्र (और उनके निजी कुंजी) केवल SSL/TLS में पार्टियों के सत्यापन के लिए उपयोग किया जाता है (अक्सर, केवल सर्वर प्रमाण पत्र का उपयोग करता है)।

वास्तविक एन्क्रिप्शन साझा/सममित कुंजी है कि हाथ मिलाना के दौरान बातचीत कर रहे उपयोग किया जाता है, पूर्व स्वामी कुंजी से प्राप्त प्रमाणीकृत कुंजी मुद्रा का एक फार्म का उपयोग करके विमर्श (TLS Specification, Section F.1.1 देखते हैं।

इस प्रमाणीकृत कुंजी विनिमय कैसे किया जाता है सिफर सूट पर निर्भर करता है, लेकिन अंतिम परिणाम वही है: दोनों पक्षों के बीच एक साझा प्री-मास्टर रहस्य, केवल ग्राहक के लिए जाना जाता है और इसके प्रमाण पत्र के लिए निजी कुंजी वाला सर्वर।

उसके बाद प्री-मास्टर गुप्त विनिमय, मास्टर गुप्त की गणना की जाती है, जिसमें से गुप्त कुंजी की एक जोड़ी ली जाती है (जैसा किमें वर्णित है): क्लाइंट के लिए लिखने के लिए (और सर्वर को पढ़ने के लिए) और सर्वर के लिए एक लिखने के लिए (और क्लाइंट को पढ़ने के लिए)। (मैक रहस्य भी उत्पन्न कर रहे हैं कनेक्शन अखंडता की गारंटी।)

सिद्धांत रूप में, नहीं सभी सिफ़र सुइट एन्क्रिप्शन प्रदान करते हैं और प्रमाणीकृत कुंजी विनिमय (Cipher Suite Definitions section देखें), लेकिन उन सभी के SunJSSE प्रदाता के साथ JSSE में डिफ़ॉल्ट रूप से सक्षम करना (SunJSSE प्रदाता दस्तावेज़ में Cipher Suite tables देखें)। संक्षेप में, उनके नामों में anon या NULL के साथ सिफर स्वीट सक्षम न करें।

अपने कोड के बारे में:

  • कोड है कि चारों ओर इस तरह कुंजी/TrustManagerFactory एल्गोरिथ्म ("SunX509") तय की कई उदाहरण हैं। यह आमतौर पर कोड है जो जावा 1.4 डिफ़ॉल्ट को हार्ड-कोड करता है। जावा 5 के बाद से, डिफ़ॉल्ट टीएमएफ एल्गोरिदम PKIX है (Customization section of the JSSE Reference Guide देखें)। इसके आसपास जाने का सबसे अच्छा तरीका TrustManagerFactory.getDefaultAlgorithm() (केएमएफ के लिए समान) का उपयोग करना है, जो आपके कोड को अन्य जेआरई पर चलाने की अनुमति देगा जो SunX509 (उदा। आईबीएम) का समर्थन नहीं करते हैं।

  • चूंकि आप क्लाइंट-प्रमाणपत्र प्रमाणीकरण का उपयोग नहीं कर रहे हैं, क्लाइंट पक्ष पर KeyManagerFactory कोई बिंदु नहीं है। इसे एक कीस्टोर के साथ शुरू करना जो संभवतः एक निजी कुंजी नहीं है, जो इसे व्यर्थ बनाता है। आप sslContext.init(null, tmf.getTrustManagers(), null) का भी उपयोग कर सकते हैं। (दोनों मामलों में सुरक्षित यादृच्छिक के लिए वही बात, जेएसएसई को इसके डिफ़ॉल्ट मानों का उपयोग करने दें।)

+0

:) आपके स्पष्टीकरण के लिए धन्यवाद। मैंने उस कोड को ट्यूटोरियल से वहां छोड़ा था क्योंकि उस समय मुझे अभी तक यकीन नहीं था कि अगर मुझे प्रारंभिक कनेक्शन पर बातचीत करने के बाद एक और हैंडशेक जोड़ना होगा। असल में, मैं सार्वजनिक कुंजी क्रिप्टोग्राफी के जेएसएसई कार्यान्वयन पर पूरी तरह से अस्पष्ट था। आपके द्वारा लिंक किए गए संसाधन बहुत उपयोगी थे। – SigSeg

-1

के लिए, क्या इसके लायक इतने सालों इस तथ्य के बाद (और जावा के लिए और अधिक विशिष्ट) एसएसएल सॉकेट हेन्डशेकिंग कॉन्फ़िगर किया गया सुरक्षा प्रदाता द्वारा कार्यान्वित के रूप में कार्य करता है। जब भी एक एसएसएल सॉकेट को लिखना होता है, तो एक हैंडशेक निहित होता है और सुरक्षा प्रदाता द्वारा इसे संभाला जाना चाहिए। हालांकि, कोड में हाथ मिलाना अधिक पारदर्शी बनाने के लिए, विधि का उपयोग कर सकते startHandshake है और यहाँ से प्रलेखित है:

https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLSocket.html#startHandshake()

+1

हैंडशेक * कनेक्ट * चरण द्वारा निहित है, न कि जब भी कोई लेखन होता है '। – EJP

संबंधित मुद्दे