Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Как URLConnection использовать с HTTPS и SSL


Автор: LSD 15.4.2006, 12:18
Использование защищенного соединения на основе SSL сокетов.


Протокол SSL предназначен для организации защищенного сетевого соединения. Протокол SSL может быть использован как промежуточный протокол между HTTP и TCP/IP, поэтому его применение HTTP клиентами будет "прозрачно". Чтобы установить связь по протоколу SSL средствами JAVA требуется создать SSL сокеты, которые в последствии используются как обыкновенные сокеты.

Для этого требуется выполнить след. шаги.

1) Создание защищенных сертификатов для клиента и сервера.
2) Создание сервера (имеет серверный SSL сокет).
3) Создание клиента (имеет клиентский SSL сокет).

Создание защищенных сертификатов для клиента и сервера.

Создание защищенных сертификатов можно произвести с помощью утилиты KeyTool входящей в состав JDK. Нам потребуется создать два хранилища ключей: для клиента и для сервера. В каждых из них должны находиться по сертификату: серверному и клиентскому, что бы оде стороны, обменивающиеся информацией могли друг друга опознать.

Создадим хранилище ключей для сервера, сгенерируем ключ, подпишем его, и экспортируем клиенту.
Для клиента выполним аналогичные действия.

/// Создаем ключ для сервера
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -genkey -alias serverKey -keystore ServerKeyStore
Enter keystore password:  serverpassword
What is your first and last name?
  [Unknown]:  myFirstName
What is the name of your organizational unit?
  [Unknown]:  myOrg
What is the name of your organization?
  [Unknown]:  myOrg
What is the name of your City or Locality?
  [Unknown]:  myCity
What is the name of your State or Province?
  [Unknown]:  myProvince
What is the two-letter country code for this unit?
  [Unknown]:  myCountryCode
Is CN=myFirstName, OU=myOrg, O=myOrg, L=myCity, ST=myProvince, C=myCountryCode correct?
  [no]:  y

Enter key password for <serverKey>
        (RETURN if same as keystore password):  serverkeypassword


/// Создаем ключ для клиента
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -genkey -alias clientKey -keystore ClientKeyStore
Enter keystore password:  clientpassword
What is your first and last name?
  [Unknown]:  ClientName
What is the name of your organizational unit?
  [Unknown]:  ClientOrgUnit
What is the name of your organization?
  [Unknown]:  ClientOrg
What is the name of your City or Locality?
  [Unknown]:  ClientCity
What is the name of your State or Province?
  [Unknown]:  ClientProvince
What is the two-letter country code for this unit?
  [Unknown]:  ClientCountryCode
Is CN=ClientName, OU=ClientOrgUnit, O=ClientOrg, L=ClientCity, ST=ClientProvince, C=ClientCountryCod
e correct?
  [no]:  y

Enter key password for <clientKey>
        (RETURN if same as keystore password):  clientkeypassword 


/// Подписываем ключ клиента.
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -selfcert -alias clientKey -keystore ClientKeyStore
Enter keystore password:  clientpassword
Enter key password for <clientKey>clientkeypassword


/// Подписываем ключ сервера.
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -selfcert -alias serverKey -keystore ServerKeyStore
Enter keystore password:  serverpassword
Enter key password for <serverKey>serverkeypassword


/// Экспортируем сертификат сервера в хранилище клиента.
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -export -file ServerCert.txt -alias serverKey -keystore ServerKeyStore
Enter keystore password:  serverpassword
Certificate stored in file <ServerCert.txt>

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -import -file ServerCert.txt -alias serverKey -keystore ClientKeyStore
Enter keystore password:  clientpassword
Owner: CN=myFirstName, OU=myOrg, O=myOrg, L=myCity, ST=myProvince, C=myCountryCode
Issuer: CN=myFirstName, OU=myOrg, O=myOrg, L=myCity, ST=myProvince, C=myCountryCode
Serial number: 443ff9b9
Valid from: Fri Apr 14 23:36:25 MSD 2006 until: Thu Jul 13 23:36:25 MSD 2006
Certificate fingerprints:
         MD5:  0D:6D:EC:1A:FD:06:BE:DA:C3:BC:F5:DF:72:29:89:5F
         SHA1: 87:4F:4E:F2:DD:55:05:39:84:66:F9:98:7B:D6:C0:64:C0:3E:90:8E
Trust this certificate? [no]:  y
Certificate was added to keystore


/// Экспортируем сертификат клиента в хранилище сервера.
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -export -file ClientCert.txt -alias clientKey -keystore ClientKeyStore
Enter keystore password:  clientpassword
Certificate stored in file <ClientCert.txt>

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -import -file ClientCert.txt -alias clientKey -keystore ServerKeyStore
Enter keystore password:  serverpassword
Owner: CN=ClientName, OU=ClientOrgUnit, O=ClientOrg, L=ClientCity, ST=ClientProvince, C=ClientCountryCode
Issuer: CN=ClientName, OU=ClientOrgUnit, O=ClientOrg, L=ClientCity, ST=ClientProvince, C=ClientCountryCode
Serial number: 443ff966
Valid from: Fri Apr 14 23:35:02 MSD 2006 until: Thu Jul 13 23:35:02 MSD 2006
Certificate fingerprints:
         MD5:  CB:74:08:EB:EE:D0:B2:C2:AE:F6:73:E3:BE:39:9E:8A
         SHA1: CC:A3:86:AE:96:31:61:0C:12:CA:0A:A5:57:8F:7D:A2:EE:FD:37:72
Trust this certificate? [no]:  y
Certificate was added to keystore



Далее просмотрим содержимое хранилищ, для уверенности.

/// Для серверного хранилища.
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -list -keystore ServerKeyStore
Enter keystore password:  serverpassword

Keystore type: jks
Keystore provider: SUN

Your keystore contains 2 entries

serverkey, 14.04.2006, keyEntry,
Certificate fingerprint (MD5): 0D:6D:EC:1A:FD:06:BE:DA:C3:BC:F5:DF:72:29:89:5F
clientkey, 14.04.2006, trustedCertEntry,
Certificate fingerprint (MD5): CB:74:08:EB:EE:D0:B2:C2:AE:F6:73:E3:BE:39:9E:8A


/// Для клиентского хранилища.
Код

C:\Program Files\Java\jdk1.5.0_06\bin>keytool -list -keystore ClientKeyStore
Enter keystore password:  clientpassword

Keystore type: jks
Keystore provider: SUN

Your keystore contains 2 entries

serverkey, 14.04.2006, trustedCertEntry,
Certificate fingerprint (MD5): 0D:6D:EC:1A:FD:06:BE:DA:C3:BC:F5:DF:72:29:89:5F
clientkey, 14.04.2006, keyEntry,
Certificate fingerprint (MD5): CB:74:08:EB:EE:D0:B2:C2:AE:F6:73:E3:BE:39:9E:8A



Очевидно, что каждое из хранилищ содержит по собственному подписанному ключу и доверенному сертификату будущего собеседника.
Осталось раздать хранилища клиенту и серверу, т.е. чтобы во время выполнения программы они могли найти свои хранилища ключей.
Поместите их, к примеру, в одну папку с клиентом и сервером соответственно.


Создание Сервера

Код
package ssltest;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

/**
 *
 * @author MoonCat
 */
public class SSLServer {
    
    /** Creates a new instance of Main */
    public SSLServer() {
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        try {
            // Получить экземпляр хранилища ключей.
            KeyStore keyStore = KeyStore.getInstance("JKS");
            FileInputStream fis = new FileInputStream("ServerKeyStore");
            keyStore.load(fis, "serverpassword".toCharArray());
            
            // Получить диспетчеры ключей базовой реализации для заданного хранилища ключей.
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(keyStore, "serverkeypassword".toCharArray());
            KeyManager [] keyManagers = keyManagerFactory.getKeyManagers();
            
            // Получить доверенные диспетчеры базовой реализации.
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
            trustManagerFactory.init(keyStore);
            TrustManager [] trustManagers = trustManagerFactory.getTrustManagers();
            
            // Получить защищенное случайное число.
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
            
            // Создание SSL контекста
            SSLContext sslContext = SSLContext.getInstance("SSLv3");
            sslContext.init(keyManagers, trustManagers, secureRandom);
            
            // Создание фабрики SSL сокетов.
            javax.net.ssl.SSLServerSocketFactory sslSocketFactory = 
                    sslContext.getServerSocketFactory();
            
            System.out.println("Creating Server Socket : 1234");
            
            SSLServerSocket sslServerSocket = (SSLServerSocket) 
                    sslSocketFactory.createServerSocket(1234);
            sslServerSocket.setNeedClientAuth(true);
            
            // Далее работаем как с обычным сокетом.
            System.out.println("Start Listenning Server Socket...");
            SSLSocket sslClientSocket = (SSLSocket) sslServerSocket.accept();
            System.out.println("Client connetion detected.");
            System.out.println("Sending callback message...");
            DataOutputStream os = new DataOutputStream(sslClientSocket.getOutputStream());
            os.write("Sending simple string to socket".getBytes());
            
            System.out.println("Test connection complite successfully");
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}



Создание Клиента

Код
package ssltest;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

/**
 *
 * @author MoonCat
 */
public class SSLClient {
    
    /** Creates a new instance of SSLClient */
    public SSLClient() {
    }
    public static void main(String[] args) {
        try {
            // Получить экземпляр хранилища ключей.
            KeyStore keyStore = KeyStore.getInstance("JKS");
            FileInputStream fis = new FileInputStream("ClientKeyStore");
            keyStore.load(fis, "clientpassword".toCharArray());
            
            // Получить диспетчеры ключей базовой реализации для заданного хранилища ключей.
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(keyStore, "clientkeypassword".toCharArray());
            KeyManager [] keyManagers = keyManagerFactory.getKeyManagers();
            
            // Получить доверенные диспетчеры базовой реализации.
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
            trustManagerFactory.init(keyStore);
            TrustManager [] trustManagers = trustManagerFactory.getTrustManagers();
            
            // Получить защищенное случайное число.
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
            
            // Создание SSL контекста
            SSLContext sslContext = SSLContext.getInstance("SSLv3");
            sslContext.init(keyManagers, trustManagers, secureRandom);
            
            // Создание фабрики SSL сокетов.
            javax.net.ssl.SSLSocketFactory sslSocketFactory =
                    sslContext.getSocketFactory();
            
            // Создаем сокет.
            System.out.println("Creating Server Socket : 1234");
            SSLSocket sslClientSocket = (SSLSocket) sslSocketFactory.createSocket("localhost", 1234);
       
            BufferedReader br = new BufferedReader( 
                    new InputStreamReader(sslClientSocket.getInputStream()));
            
            while (true) {
                String s = br.readLine();
                if (s.length() > 0) {
                    System.out.println( s );
                    break;
                }
            }
            br.close();           
            System.out.println("Test connection complite successfully");
        } catch (KeyManagementException ex) {
            ex.printStackTrace();
        } catch (UnrecoverableKeyException ex) {
            ex.printStackTrace();
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        } catch (NoSuchProviderException ex) {
            ex.printStackTrace();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (KeyStoreException ex) {
            ex.printStackTrace();
        } catch (CertificateException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}



Код подробно прокомментирован, но суть в следующем: сначала происходит настройка SSLContext необходимыми для аутентификации  сертификатами, а потом создаются  клиентский и серверный SSL сокеты. После создания с ними можно работать как с простыми  сокетами, передавать в них информацию, но она будет шифроваться не заметно для нас. Только если скорость передачи данных  несколько упадет.

Запустите сервер а потом клиент. Клиент должен получить ответ от сервера в виде строки: Sending simple string to socket.

Желаю успеха!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)