Изградете защитени мрежови приложения с SSL и JSSE API

Интернет е опасно място. Просто е прекалено лесно да се подслушва, да се фалшифицира и да се краде незащитена информация, докато тя се движи по жиците. Миналия месец написах последната статия от поредица за сертификати X.509 и инфраструктура с публичен ключ (PKI), технологиите, които осигуряват повечето дейности за електронна търговия в Интернет. В края на статията предложих да разгледам протокола SSL (Secure Socket Layer), за да науча как X.509 сертификатите се използват на практика. SSL е приложението за убийство X.509 - почти всеки браузър и най-популярните сървъри за уеб и приложения го поддържат.

Този месец ще изследвам SSL, както е внедрен от JSSE (Java Secure Socket Extension), и ще ви покажа как да изградите защитени мрежови приложения в Java с помощта на SSL и JSSE.

Нека започнем с проста демонстрация. JSSE предоставя SSL набор от инструменти за Java приложения. В допълнение към необходимите класове и интерфейси, JSSE предоставя удобен превключвател за отстраняване на грешки в командния ред, който можете да използвате, за да гледате SSL протокола в действие. В допълнение към предоставянето на полезна информация за отстраняване на грешки в непокорното приложение, играта с инструментариума е чудесен начин да намокрите краката си със SSL и JSSE.

За да стартирате демонстрацията, първо трябва да компилирате следния клас:

публичен клас Тест {public static void main (String [] arstring) {try {new java.net.URL ("//" + arstring [0] + "/"). getContent (); } catch (изключение по изключение) {изключение.printStackTrace (); }}}

След това трябва да включите SSL отстраняване на грешки и да стартирате горното приложение. Приложението се свързва със защитения уебсайт, който посочвате в командния ред, използвайки протокола SSL чрез HTTPS. Първата опция зарежда манипулатора на протокол HTTPS. Втората опция, опцията за отстраняване на грешки, кара програмата да отпечатва своето поведение. Ето командата (заменете с името на защитен уеб сървър):

 java -Djava.protocol.handler.pkgs = com.sun.net.ssl.internal.www.protocol -Djavax.net.debug = ssl Тест  

Трябва да инсталирате JSSE; обърнете се към ресурси, ако не сте сигурни как.

Сега нека се заемем с бизнеса и да поговорим за SSL и JSSE.

Кратък поглед към SSL

Кодът във въведението демонстрира най-лесния начин за добавяне на SSL към вашите приложения - чрез java.net.URLкласа. Този подход е полезен, но не е достатъчно гъвкав, за да ви позволи да създадете сигурно приложение, което използва общи сокети.

Преди да ви покажа как да добавите тази гъвкавост, нека да разгледаме набързо характеристиките на SSL.

Както подсказва името му, SSL има за цел да предостави на приложения със сигурен сокет подобен на инструментариум. В идеалния случай трябва да е лесно да конвертирате приложение, което използва обикновени сокети, в приложение, което използва SSL.

SSL разглежда три важни проблема със сигурността:

  1. Той осигурява удостоверяване, което помага да се гарантира легитимността на обектите, участващи в диалогов прозорец.
  2. Той осигурява поверителност. SSL помага да се гарантира, че трета страна не може да дешифрира диалога между две обекти.
  3. Той поддържа целостта. Използването на MAC (код за удостоверяване на съобщение), който е подобен на контролна сума, помага да се гарантира, че диалогът между две обекти не е модифициран от трета страна.

SSL разчита силно както на криптографията с публичен ключ, така и на секретен ключ. Той използва криптография с таен ключ, за да шифрова масово данните, обменени между две приложения. SSL предоставя идеалното решение, тъй като алгоритмите с тайни ключове са едновременно сигурни и бързи. Криптографията с публичен ключ, която е по-бавна от криптографията със секретен ключ, е по-добър избор за удостоверяване и обмен на ключове.

Референтното внедряване на JSSE на Sun идва с цялата технология, необходима за добавяне на SSL към вашите приложения. Включва поддръжка на RSA (Rivest-Shamir-Adleman) криптография - де факто стандартът за сигурност в Интернет. Той включва внедряване на SSL 3.0 - текущият SSL стандарт - и TLS (Transport Layer Security) 1.0, следващото поколение SSL. JSSE също така предоставя набор от API за създаване и използване на защитени сокети.

API на JSSE

Архитектурата на Java за защита използва фабрично модела на проектиране. За непосветените шаблонът за фабричен дизайн използва специални фабрични обекти за конструиране на екземпляри, вместо директно да извиква техните конструктори. (Вижте Ресурси за плюсовете и минусите на фабричния клас.)

В JSSE всичко започва от фабриката; има фабрика за SSL сокети и фабрика за SSL сокети. Тъй като общите сокети и сървърните сокети вече са от съществено значение за мрежовото програмиране на Java, предполагам, че сте запознати с двете и разбирате техните роли и разлики. Ако не сте, препоръчвам да вземете добра книга за мрежовото програмиране на Java.

SSLSocketFactory

Методите в javax.net.ssl.SSLSocketFactoryкласа се разделят на три категории. Първият се състои от един-единствен метод статично, която извлича подразбиране фабрика SSL контакт: static SocketFactory getDefault().

Втората категория се състои от четири метода, наследени от javax.net.SocketFactoryтова огледало на четирите конструктора на ключове, намерени в java.net.Socketкласа, и един метод, който обгръща съществуващ сокет със SSL сокет. Всеки от тях връща 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)

Двата метода в третата категория връщат списъка с набори от SSL шифри, които са разрешени по подразбиране, и пълния списък на поддържаните набори за шифроване на SSL:

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

Шифров пакет е комбинация от криптографски алгоритми, които определят определено ниво на сигурност за SSL връзка. Набор от шифри определя дали връзката е шифрована, дали целостта на съдържанието е проверена и как се извършва удостоверяване.

SSLServerSocketFactory

Методите за javax.net.ssl.SSLServerSocketFactoryкласа попадат в същите три категории като SSLSocketFactory. Първо, това е метода с общ статичен, която извлича SSL сървър фабрика контакт по подразбиране: static ServerSocketFactory getDefault().

Методите, които връщат сокетите на SSL сървъра, отразяват конструкторите, намерени в java.net.ServerSocketкласа:

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

Finally, the SSLServerSocketFactory features the two methods that return the list of ciphers enabled by default and the list of supported ciphers, respectively:

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

So far, the API is pretty straightforward.

SSLSocket

Things get interesting in the javax.net.ssl.SSLSocket class. I assume you are already familiar with the methods provided by its parent, the Socket class, so I will concentrate on the methods that provide SSL-related functionality.

Like the two SSL factory classes, the first two methods listed below retrieve the enabled and supported SSL cipher suites, respectively. The third method sets the enabled cipher suites. An application can use the third operation to upgrade or downgrade the range of acceptable security that the application will allow:

  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(); } } } 

Използвайте следната команда, за да стартирате клиента ( foobarедновременно е името на файла на truststore и неговата парола):

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