Bangun aplikasi jaringan yang aman dengan SSL dan JSSE API

Internet adalah tempat yang berbahaya. Terlalu mudah untuk mengintip, memalsukan, dan mencuri informasi yang tidak terlindungi saat menyebar melalui kabel. Bulan lalu, saya menulis artikel terakhir dalam seri sertifikat X.509 dan infrastruktur kunci publik (PKI), teknologi yang mengamankan sebagian besar aktivitas e-niaga di Internet. Menjelang akhir artikel, saya menyarankan untuk melihat protokol SSL (Secure Socket Layer) untuk mempelajari bagaimana sertifikat X.509 digunakan dalam praktiknya. SSL adalah aplikasi X.509 killer - hampir setiap browser dan server Web dan aplikasi terpopuler mendukungnya.

Bulan ini, saya akan menjelajahi SSL seperti yang diterapkan oleh JSSE (Java Secure Socket Extension), dan menunjukkan kepada Anda bagaimana membangun aplikasi jaringan yang aman di Java menggunakan SSL dan JSSE.

Mari kita mulai dengan demonstrasi sederhana. JSSE menyediakan toolkit SSL untuk aplikasi Java. Selain kelas dan antarmuka yang diperlukan, JSSE menyediakan sakelar debugging baris perintah praktis yang dapat Anda gunakan untuk melihat protokol SSL beraksi. Selain memberikan informasi yang berguna untuk men-debug aplikasi bandel, bermain dengan toolkit adalah cara yang bagus untuk membuat kaki Anda basah dengan SSL dan JSSE.

Untuk menjalankan demonstrasi, Anda harus terlebih dahulu mengkompilasi kelas berikut:

Uji kelas publik {public static void main (String [] arstring) {coba {java.net.URL baru ("//" + arstring [0] + "/"). getContent (); } catch (Exception exception) {exception.printStackTrace (); }}}

Selanjutnya, Anda perlu mengaktifkan debugging SSL dan menjalankan aplikasi di atas. Aplikasi ini terhubung ke Situs Web aman yang Anda tentukan di baris perintah menggunakan protokol SSL melalui HTTPS. Opsi pertama memuat penangan protokol HTTPS. Opsi kedua, opsi debug, menyebabkan program mencetak perilakunya. Berikut perintahnya (ganti dengan nama server Web aman):

 java -Djava.protocol.handler.pkgs = com.sun.net.ssl.internal.www.protocol -Djavax.net.debug = Tes ssl  

Anda perlu menginstal JSSE; lihat Sumber Daya jika Anda tidak yakin caranya.

Sekarang mari kita mulai berbisnis dan berbicara tentang SSL dan JSSE.

Sekilas tentang SSL

Kode dalam pendahuluan menunjukkan cara termudah untuk menambahkan SSL ke aplikasi Anda - melalui java.net.URLkelas. Pendekatan ini berguna, tetapi tidak cukup fleksibel untuk memungkinkan Anda membuat aplikasi aman yang menggunakan soket generik.

Sebelum saya menunjukkan cara menambahkan fleksibilitas itu, mari kita lihat sekilas fitur SSL.

Seperti namanya, SSL bertujuan untuk menyediakan aplikasi dengan toolkit seperti soket yang aman. Idealnya, harus mudah untuk mengubah aplikasi yang menggunakan soket biasa menjadi aplikasi yang menggunakan SSL.

SSL mengatasi tiga masalah keamanan penting:

  1. Ini menyediakan otentikasi, yang membantu memastikan keabsahan entitas yang terlibat dalam dialog.
  2. Ini memberikan privasi. SSL membantu menjamin bahwa pihak ketiga tidak dapat menguraikan dialog antara dua entitas.
  3. Itu menjaga integritas. Penggunaan MAC (kode otentikasi pesan), yang mirip dengan checksum, membantu menjamin bahwa dialog antara dua entitas tidak diubah oleh pihak ketiga.

SSL sangat bergantung pada kriptografi kunci publik dan kunci rahasia. Ia menggunakan kriptografi kunci rahasia untuk mengenkripsi data secara massal yang dipertukarkan antara dua aplikasi. SSL memberikan solusi yang ideal karena algoritme kunci rahasia aman dan cepat. Kriptografi kunci publik, yang lebih lambat dari kriptografi kunci rahasia, adalah pilihan yang lebih baik untuk otentikasi dan pertukaran kunci.

Implementasi referensi JSSE Sun dilengkapi dengan semua teknologi yang diperlukan untuk menambahkan SSL ke aplikasi Anda. Ini mencakup dukungan kriptografi RSA (Rivest-Shamir-Adleman) - standar de facto untuk keamanan di Internet. Ini mencakup implementasi SSL 3.0 - standar SSL saat ini - dan TLS (Transport Layer Security) 1.0, generasi SSL berikutnya. JSSE juga menyediakan rangkaian API untuk membuat dan menggunakan soket yang aman.

API JSSE

Arsitektur keamanan Java banyak menggunakan pola desain Pabrik . Untuk yang belum tahu, pola desain Pabrik menggunakan objek pabrik khusus untuk membuat instance, daripada memanggil konstruktornya secara langsung. (Lihat Sumberdaya untuk pro dan kontra dari kelas pabrik.)

Di JSSE, semuanya dimulai dari pabrik; ada pabrik untuk soket SSL dan pabrik untuk soket server SSL. Karena soket generik dan soket server sudah cukup mendasar untuk pemrograman jaringan Java, saya akan berasumsi bahwa Anda sudah familiar dengan keduanya dan Anda memahami peran dan perbedaannya. Jika tidak, saya sarankan untuk mengambil buku yang bagus tentang pemrograman jaringan Java.

SSLSocketFactory

Metode di javax.net.ssl.SSLSocketFactorykelas terbagi dalam tiga kategori. Yang pertama terdiri dari metode statis tunggal yang mengambil default pabrik SSL socket: static SocketFactory getDefault().

Kategori kedua terdiri dari empat metode yang diwarisi dari javax.net.SocketFactorycermin itu empat konstruktor kunci yang ditemukan di java.net.Socketkelas, dan satu metode yang membungkus soket yang ada dengan soket SSL. Mereka masing-masing mengembalikan soket SSL:

  1. Socket createSocket(String host, int port)
  2. Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
  3. Socket createSocket(InetAddress host, int port)
  4. Socket createSocket(InetAddress host, int port, InetAddress clientHost, int clientPort)
  5. Socket createSocket(Socket socket, String host, int port, boolean autoClose)

Dua metode dalam kategori ketiga mengembalikan daftar paket penyandian SSL yang diaktifkan secara default, dan daftar lengkap rangkaian penyandian SSL yang didukung:

  1. String [] getDefaultCipherSuites()
  2. String [] getSupportedCipherSuites()

Cipher suite adalah kombinasi algoritma kriptografi yang menentukan tingkat keamanan tertentu untuk koneksi SSL. Cipher suite menentukan apakah koneksi dienkripsi, apakah integritas konten diverifikasi, dan bagaimana autentikasi terjadi.

SSLServerSocketFactory

Metode di javax.net.ssl.SSLServerSocketFactorykelas termasuk dalam tiga kategori yang sama seperti SSLSocketFactory. Pertama, ada metode statis tunggal yang mengambil server default SSL pabrik socket: static ServerSocketFactory getDefault().

Metode yang mengembalikan soket server SSL mencerminkan konstruktor yang ditemukan di java.net.ServerSocketkelas:

  1. ServerSocket createServerSocket(int port)
  2. ServerSocket createServerSocket(int port, int backlog)
  3. ServerSocket createServerSocket(int port, int backlog, InetAddress address)

Terakhir, SSLServerSocketFactoryfitur kedua metode yang mengembalikan daftar cipher yang diaktifkan secara default dan daftar cipher yang didukung, masing-masing:

  1. String [] getDefaultCipherSuites()
  2. String [] getSupportedCipherSuites()

Sejauh ini, API cukup mudah.

SSLSocket

Hal-hal menjadi menarik di javax.net.ssl.SSLSocketkelas. Saya berasumsi Anda sudah terbiasa dengan metode yang disediakan oleh induknya, Socketkelas, jadi saya akan berkonsentrasi pada metode yang menyediakan fungsionalitas terkait SSL.

Seperti dua kelas pabrik SSL, dua metode pertama yang tercantum di bawah ini mengambil cipher suite SSL yang diaktifkan dan didukung. Metode ketiga mengatur cipher suite yang diaktifkan. Aplikasi dapat menggunakan operasi ketiga untuk meningkatkan atau menurunkan kisaran keamanan yang dapat diterima yang diizinkan oleh aplikasi:

  1. String [] getEnabledCipherSuites()
  2. String [] getSupportedCipherSuites()
  3. void setEnabledCipherSuites(String [] suites)

These two methods determine whether the socket can establish new SSL sessions, which maintain connection details -- like the shared secret key -- between connections:

  1. boolean getEnableSessionCreation()
  2. void setEnableSessionCreation(boolean flag)

The next two methods determine whether the socket will require client authentication. The methods only make sense when invoked on server mode sockets. Remember, according to the SSL specification, client authentication is optional. For example, most Web applications don't require it:

  1. boolean getNeedClientAuth()
  2. void setNeedClientAuth(boolean need)

The methods below change the socket from client mode to server mode. This affects who initiates the SSL handshake and who authenticates first:

  1. boolean getUseClientMode()
  2. void setUseClientMode(boolean mode)

Method void startHandshake() forces an SSL handshake. It's possible, but not common, to force a new handshake operation in an existing connection.

Method SSLSession getSession() retrieves the SSL session. You will seldom need to access the SSL session directly.

The two methods listed below add and remove an SSL handshake listener object. The handshake listener object is notified whenever an SSL handshake operation completes on the socket.

  1. void addHandshakeCompletedListener(HandshakeCompletedListener listener)
  2. void removeHandshakeCompletedListener(HandshakeCompletedListener listener)

SSLServerSocket

The javax.net.ssl.SSLServerSocket class is similar to the javax.net.ssl.SSLSocket class; it doesn't require much individual attention. In fact, the set of methods on javax.net.ssl.SSLServerSocket class is a subset of the methods on the javax.net.ssl.SSLSocket class.

The first two methods listed below retrieve the enabled and supported SSL cipher suites. The third method sets the enabled cipher suite:

  1. String [] getEnabledCipherSuites()
  2. String [] getSupportedCipherSuites()
  3. void setEnabledCipherSuites(String [] suites)

These two methods control whether or not the server socket can establish new SSL sessions:

  1. boolean getEnableSessionCreation()
  2. void setEnableSessionCreation(boolean flag)

The following methods determine whether the accepted sockets will require client authentication:

  1. boolean getNeedClientAuth()
  2. void setNeedClientAuth(boolean flag)

The methods below change the accepted socket from client mode to server mode:

  1. boolean getUseClientMode()
  2. void setUseClientMode(boolean flag)

A simple example

To make this toolkit tutorial clearer, I've included the source code for a simple server and a compatible client below. It's a secure variation on the typical echo application that many introductory networking texts provide.

The server, shown below, uses JSSE to create a secure server socket. It listens on the server socket for connections from secure clients. When running the server, you must specify the keystore to use. The keystore contains the server's certificate. I have created a simple keystore that contains a single certificate. (See Resources to download the certificate.)

import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.IOException; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; public class EchoServer { public static void main(String [] arstring) { try { SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); SSLServerSocket sslserversocket = (SSLServerSocket)sslserversocketfactory.createServerSocket(9999); SSLSocket sslsocket = (SSLSocket)sslserversocket.accept(); InputStream inputstream = sslsocket.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); String string = null; while ((string = bufferedreader.readLine()) != null) { System.out.println(string); System.out.flush(); } } catch (Exception exception) { exception.printStackTrace(); } } } 

Use the following command to start the server (foobar is both the name of the keystore file and its password):

 java -Djavax.net.ssl.keyStore=foobar -Djavax.net.ssl.keyStorePassword=foobar EchoServer 

The client, shown below, uses JSSE to securely connect to the server. When running the client, you must specify the truststore to use, which contains the list of trusted certificates. I have created a simple truststore that contains a single certificate. (See Resources to download the certificate.)

import java.io.InputStream; import java.io.OutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; public class EchoClient { public static void main(String [] arstring) { try { SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault(); SSLSocket sslsocket = (SSLSocket)sslsocketfactory.createSocket("localhost", 9999); InputStream inputstream = System.in; InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); OutputStream outputstream = sslsocket.getOutputStream(); OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream); BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter); String string = null; while ((string = bufferedreader.readLine()) != null) { bufferedwriter.write(string + '\n'); bufferedwriter.flush(); } } catch (Exception exception) { exception.printStackTrace(); } } } 

Gunakan perintah berikut untuk memulai klien ( foobarmerupakan nama file truststore dan sandinya):

 java -Djavax.net.ssl.trustStore = foobar -Djavax.net.ssl.trustStorePassword = foobar EchoClient