Trong bài viết này, tôi sẽ tạo một bản demo máy chủ HTTPS và máy khách HTTPS có thể thiết lập giao tiếp HTTPS giữa máy chủ và máy khách bằng Java. Điều này sẽ rất hữu ích khi chúng ta muốn kiểm tra sự hiểu biết của mình về giao tiếp SSL. Chúng ta sẽ sử dụng cả một máy khách SSL chi tiết và một HttpsURLConnection đơn giản làm máy khách HTTPS.
Trước khi tạo máy chủ HTTPS và máy khách HTTPS thực tế, trước tiên chúng ta cần tạo kho khóa và kho tin cậy để máy chủ và máy khách sử dụng. Để tạo kho khóa, chúng ta có thể làm theo hướng dẫn tại Các loại kho khóa khác nhau trong Java -- JKS. Trong bản demo này, chúng ta sẽ sử dụng kho khóa được tạo ra làm cả kho khóa và kho tin cậy. Trong các ứng dụng thực tế, kho khóa và kho tin cậy nên là các tệp riêng biệt.
Máy chủ HTTPS
Bây giờ chúng ta tạo máy chủ HTTPS. Dưới đây là đoạn mã.
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.security.KeyStore; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; public class HTTPSServer { private int port = 9999; private boolean isServerDone = false; public static void main(String[] args){ HTTPSServer server = new HTTPSServer(); server.run(); } HTTPSServer(){ } HTTPSServer(int port){ this.port = port; } // Tạo và khởi tạo SSLContext private SSLContext createSSLContext(){ try{ KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream("test.jks"),"passphrase".toCharArray()); // Tạo quản lý khóa KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); keyManagerFactory.init(keyStore, "passphrase".toCharArray()); KeyManager[] km = keyManagerFactory.getKeyManagers(); // Tạo quản lý tin cậy TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); trustManagerFactory.init(keyStore); TrustManager[] tm = trustManagerFactory.getTrustManagers(); // Khởi tạo SSLContext SSLContext sslContext = SSLContext.getInstance("TLSv1"); sslContext.init(km, tm, null); return sslContext; } catch (Exception ex){ ex.printStackTrace(); } return null; } // Bắt đầu chạy máy chủ public void run(){ SSLContext sslContext = this.createSSLContext(); try{ // Tạo nhà máy socket server SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); // Tạo socket server SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(this.port); System.out.println("Máy chủ SSL đã bắt đầu"); while(!isServerDone){ SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); // Bắt đầu luồng máy chủ new ServerThread(sslSocket).start(); } } catch (Exception ex){ ex.printStackTrace(); } } // Luồng xử lý socket từ máy khách static class ServerThread extends Thread { private SSLSocket sslSocket = null; ServerThread(SSLSocket sslSocket){ this.sslSocket = sslSocket; } public void run(){ sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); try{ // Bắt đầu trao đổi khóa sslSocket.startHandshake(); // Lấy phiên sau khi kết nối được thiết lập SSLSession sslSession = sslSocket.getSession(); System.out.println("SSLSession :"); System.out.println("\tGiao thức : "+sslSession.getProtocol()); System.out.println("\tBộ mã hóa : "+sslSession.getCipherSuite()); // Bắt đầu xử lý nội dung ứng dụng InputStream inputStream = sslSocket.getInputStream(); OutputStream outputStream = sslSocket.getOutputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream)); String line = null; while((line = bufferedReader.readLine()) != null){ System.out.println("Đầu vào : "+line); if(line.trim().isEmpty()){ break; } } // Ghi dữ liệu printWriter.print("HTTP/1.1 200\r\n"); printWriter.flush(); sslSocket.close(); } catch (Exception ex) { ex.printStackTrace(); } } } }
Đầu tiên, nó sẽ thiết lập máy chủ SSL với kho khóa và kho tin cậy chính xác được cấu hình. Sau đó, nó sẽ bắt đầu lắng nghe kết nối máy khách. Khi nhận được kết nối máy khách, một ServerThread mới sẽ được tạo để xử lý kết nối máy khách.
Trong ServerThread, đầu tiên nó sẽ bắt đầu thực hiện trao đổi khóa với máy khách và khi trao đổi khóa hoàn tất thành công, dữ liệu ứng dụng có thể được trao đổi giữa máy chủ và máy khách. Khi máy chủ nhận được dữ liệu ứng dụng từ máy khách, nó sẽ gửi mã phản hồi 200 (OK) cho máy khách.
Máy khách HTTPS
Máy khách HTTPS tương tự như máy chủ HTTPS được tạo ở trên,
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.security.KeyStore; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; public class HTTPSClient { private String host = "127.0.0.1"; private int port = 9999; public static void main(String[] args){ HTTPSClient client = new HTTPSClient(); client.run(); } HTTPSClient(){ } HTTPSClient(String host, int port){ this.host = host; this.port = port; } // Tạo và khởi tạo SSLContext private SSLContext createSSLContext(){ try{ KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(new FileInputStream("test.jks"),"passphrase".toCharArray()); // Tạo quản lý khóa KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); keyManagerFactory.init(keyStore, "passphrase".toCharArray()); KeyManager[] km = keyManagerFactory.getKeyManagers(); // Tạo quản lý tin cậy TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); trustManagerFactory.init(keyStore); TrustManager[] tm = trustManagerFactory.getTrustManagers(); // Khởi tạo SSLContext SSLContext sslContext = SSLContext.getInstance("TLSv1"); sslContext.init(km, tm, null); return sslContext; } catch (Exception ex){ ex.printStackTrace(); } return null; } // Bắt đầu chạy máy chủ public void run(){ SSLContext sslContext = this.createSSLContext(); try{ // Tạo nhà máy socket SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); // Tạo socket SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(this.host, this.port); System.out.println("Máy khách SSL đã bắt đầu"); new ClientThread(sslSocket).start(); } catch (Exception ex){ ex.printStackTrace(); } } // Luồng xử lý socket đến máy chủ static class ClientThread extends Thread { private SSLSocket sslSocket = null; ClientThread(SSLSocket sslSocket){ this.sslSocket = sslSocket; } public void run(){ sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites()); try{ // Bắt đầu trao đổi khóa sslSocket.startHandshake(); // Lấy phiên sau khi kết nối được thiết lập SSLSession sslSession = sslSocket.getSession(); System.out.println("SSLSession :"); System.out.println("\tGiao thức : "+sslSession.getProtocol()); System.out.println("\tBộ mã hóa : "+sslSession.getCipherSuite()); // Bắt đầu xử lý nội dung ứng dụng InputStream inputStream = sslSocket.getInputStream(); OutputStream outputStream = sslSocket.getOutputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream)); // Ghi dữ liệu printWriter.println("Hello server"); printWriter.println(); printWriter.flush(); String line = null; while((line = bufferedReader.readLine()) != null){ System.out.println("Đầu vào : "+line); if(line.trim().equals("HTTP/1.1 200\r\n")){ break; } } sslSocket.close(); } catch (Exception ex) { ex.printStackTrace(); } } } }
Đầu tiên, nó sẽ thiết lập máy khách SSL với kho khóa và kho tin cậy chính xác. Sau đó, nó sẽ kết nối với máy chủ và một ClientThread mới sẽ được tạo để xử lý kết nối SSL.
Trong ClientThread, điều đầu tiên là bật các bộ mã hóa mà bạn muốn sử dụng. Và sau đó máy khách bắt đầu bắt đầu trao đổi khóa và gửi dữ liệu ứng dụng sau khi trao đổi khóa hoàn tất.
Một máy khách HTTPS khác
Đây là một máy khách HTTPS khác chỉ sử dụng HttpsURLConnection đơn giản để đóng gói tất cả các chi tiết như trao đổi khóa.
import java.net.URL; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; public class HTTPSClient { // Tắt xác minh tên máy chủ cho mục đích trình diễn static { HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } }); } public static void main(String[] args){ // Khởi tạo cấu hình System.setProperty("javax.net.ssl.trustStore", "test.jks"); System.setProperty("javax.net.ssl.trustStoreType", "jks"); try{ URL url = new URL("https://127.0.0.1:9999"); HttpsURLConnection client = (HttpsURLConnection) url.openConnection(); System.out.println("KẾT QUẢ : "+client.getResponseCode()); } catch (Exception ex){ ex.printStackTrace(); } } }
Ở đây, vì mục đích trình diễn, chúng tôi đã tắt thủ công việc xác minh tên máy chủ. Trong ứng dụng thực tế, điều này cần được xử lý cẩn thận vì điều này gây ra nguy cơ vi phạm bảo mật.
Ngoài ra, chúng ta sử dụng các thuộc tính hệ thống để cấu hình kho tin cậy được máy khách sử dụng để xác minh chứng chỉ máy chủ.
Phần trên trình bày một ứng dụng máy chủ và máy khách HTTPS đơn giản nhưng đầy đủ. Bạn có thể tìm hiểu thêm về mô hình kết nối SSL trong Java từ Oracle.
Thanks for the info, It helped me .