यह एक समस्या है जो मैं हाल ही में हल करने के लिए वास्तव में संघर्ष कर रहा हूं, क्योंकि मुझे लगा कि इस मुद्दे के बारे में इंटरनेट पर लगभग बहुत अधिक जानकारी थी कि की सहायता नहीं करता था। इसलिए चूंकि मुझे अभी एक समाधान मिला है जो मेरे लिए काम करता है, मैंने फैसला किया कि मैं समस्या और समाधान यहां पोस्ट करूंगा, उम्मीद है कि मैं इंटरनेट के बाद आने वाले लोगों के लिए थोड़ा बेहतर जगह बना सकता हूं! (उम्मीद है कि यह "अनुपयोगी" सामग्री में योगदान नहीं दे रहा है!)स्व-हस्ताक्षरित प्रमाणपत्र का उपयोग कर एंड्रॉइड एसएसएलस्केट्स
मेरे पास एक एंड्रॉइड एप्लिकेशन है जिसे मैं विकसित कर रहा हूं। हाल ही में, मैं अपने ऐप और मेरे सर्वर के बीच संवाद करने के लिए सर्वरस्केट्स और सॉकेट का उपयोग कर रहा हूं। हालांकि, संचार को सुरक्षित होने की आवश्यकता है, इसलिए मैं इन्हें SSLServerSockets और SSLSockets में कनवर्ट करने की कोशिश कर रहा हूं, जो अपेक्षा की अपेक्षा से बहुत कठिन हो गया है।
यह एक प्रोटोटाइप के रूप में देखकर, स्वयं हस्ताक्षरित प्रमाणपत्रों का उपयोग करने में कोई (सुरक्षा) नुकसान नहीं है, जो मैं कर रहा हूं। जैसा कि आपने शायद अनुमान लगाया है, यही वह जगह है जहां समस्याएं आती हैं। यही वह है जो मैंने किया था, और जिन समस्याओं का सामना मैंने किया था।
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
/**
* Server
*/
public class simplesslserver {
// Global variables
private static SSLServerSocketFactory ssf;
private static SSLServerSocket ss;
private static final int port = 8081;
private static String address;
/**
* Main: Starts the server and waits for clients to connect.
* Each client is given its own thread.
* @param args
*/
public static void main(String[] args) {
try {
// System properties
System.setProperty("javax.net.ssl.keyStore","mykeystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword","MY_PASSWORD");
// Start server
ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ss = (SSLServerSocket) ssf.createServerSocket(port);
address = InetAddress.getLocalHost().toString();
System.out.println("Server started at "+address+" on port "+port+"\n");
// Wait for messages
while (true) {
SSLSocket connected = (SSLSocket) ss.accept();
new clientThread(connected).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Client thread.
*/
private static class clientThread extends Thread {
// Variables
private SSLSocket cs;
private InputStreamReader isr;
private OutputStreamWriter osw;
private BufferedReader br;
private BufferedWriter bw;
/**
* Constructor: Initialises client socket.
* @param clientSocket The socket connected to the client.
*/
public clientThread(SSLSocket clientSocket) {
cs = clientSocket;
}
/**
* Starts the thread.
*/
public void run() {
try {
// Initialise streams
isr = new InputStreamReader(cs.getInputStream());
br = new BufferedReader(isr);
osw = new OutputStreamWriter(cs.getOutputStream());
bw = new BufferedWriter(osw);
// Get request from client
String tmp = br.readLine();
System.out.println("received: "+tmp);
// Send response to client
String resp = "You said '"+tmp+"'!";
bw.write(resp);
bw.newLine();
bw.flush();
System.out.println("response: "+resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
यह एंड्रॉयड से एक उद्धरण है:
keytool -genkey -alias serverAlias -keyalg RSA -keypass MY_PASSWORD -storepass MY_PASSWORD -keystore mykeystore.jks
यह सर्वर कोड है:
मैं फ़ाइल "mykeystore.jks" निम्न आदेश के साथ उत्पन्न आवेदन (ग्राहक):
String message = "Hello World";
try{
// Create SSLSocketFactory
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
// Create socket using SSLSocketFactory
SSLSocket client = (SSLSocket) factory.createSocket("SERVER_IP_ADDRESS", 8081);
// Print system information
System.out.println("Connected to server " + client.getInetAddress() + ": " + client.getPort());
// Writer and Reader
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
// Send request to server
System.out.println("Sending request: "+message);
writer.write(message);
writer.newLine();
writer.flush();
// Receive response from server
String response = reader.readLine();
System.out.println("Received from the Server: "+response);
// Close connection
client.close();
return response;
} catch(Exception e) {
e.printStackTrace();
}
return "Something went wrong...";
जब मैं कोड चलाता था, यह काम नहीं करता था, और यह वह आउटपुट है जो मुझे मिल रहा था।
ग्राहक उत्पादन:
Connected to server /SERVER_IP_ADDRESS: 8081
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
... stack trace ...
सर्वर उत्पादन:
received: null
java.net.SocketException: Connection closed by remote host
प्रमाण पत्र के रूप में स्व-हस्ताक्षरित है, एप्लिकेशन यह भरोसा नहीं करता है। मैंने Google के चारों ओर एक नज़र डाली, और सामान्य सहमति यह है कि मुझे एक एसएसएलकॉन्टेक्स्ट (क्लाइंट में) बनाने की ज़रूरत है जो कस्टम ट्रस्टमैनेजर पर आधारित है जो इस स्व-हस्ताक्षरित प्रमाणपत्र को स्वीकार करता है। काफी सरल, मैंने सोचा। अगले हफ्ते में, मैंने इस मुद्दे को हल करने के अधिक तरीकों की कोशिश की, जिसे मैं संभवतः याद कर सकता हूं, इसका कोई फायदा नहीं हुआ। अब मैं आपको अपने मूल कथन पर वापस भेजता हूं: वहां बहुत अधिक अपूर्ण जानकारी है, जिसने समाधान को समझने के लिए बहुत कठिन परिश्रम किया है।
मुझे मिला एकमात्र कामकाजी समाधान, एक ट्रस्टमैनेजर बनाना था जो सभी प्रमाण पत्र स्वीकार करता है।
private static class AcceptAllTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() { return null; }
}
जो इस
SSLContext sslctx = SSLContext.getInstance("TLS");
sslctx.init(new KeyManager[0], new TrustManager[] {new AcceptAllTrustManager()}, new SecureRandom());
SSLSocketFactory factory = sslctx.getSocketFactory();
SSLSocket client = (SSLSocket) factory.createSocket("IP_ADDRESS", 8081);
की तरह इस्तेमाल किया जा सकता और बिना किसी अपवाद के अच्छा और खुश उत्पादन देता है!
Connected to server /SERVER_IP_ADDRESS: 8081
Sending request: Hello World
Received from the Server: You said 'Hello World'!
हालांकि, यह नहीं एक अच्छा विचार, क्योंकि एप्लिकेशन को अभी भी असुरक्षित हो जाएगा, संभावित मैन-इन-द-मिडल हमलों के लिए धन्यवाद है।
तो मैं अटक गया था। मैं ऐप को अपने स्वयं के हस्ताक्षरित प्रमाण पत्र पर भरोसा कैसे प्राप्त कर सकता हूं, लेकिन वहां कोई भी प्रमाणपत्र नहीं है?