background image

 

 

Java, bazy danych i SSL

1

1. HSQLDB i SSL.

2. MySQL

 własności połączenia,

 transmija z wykorzystaniem SSL.

3. Własne programy wykorzystujące SSL.

background image

 

 

HSQLDB – SSL

2

HSQLDB umożliwia szyfrowanie transmisji. Aby taka transmisja była możliwa 

zarówno serwer jak i klient muszą być odpowiednio skonfigurowane. Konfiguracja 

serwera:

1. Generowanie certyfikatu serwera:

>keytool -genkey -alias hsqldb -keyalg RSA -validity 30 -keystore 
hsqlserver.store

Enter keystore password:  

hsqldb

What is your first and last name?

  [Unknown]:  

localhost

...

Is CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, 
C=Unknown correct?

  [no]:  

yes

Enter key password for <hsqldb>

        (RETURN if same as keystore password):

background image

 

 

HSQLDB – SSL

3

Inny sposób generowania klucza – gdy posiadamy certyfikat podpisany  przez 

zewnętrzne Centrum Autoryzacji”

openssl pkcs8 -topk8 -outform DER -in Xpvk.pem -inform PEM

-out Xpvk.pk8 -nocrypt

openssl x509 -in Xcert.pem -out Xcert.der -outform DER

java DERImport server.store NEWALIAS Xpvk.pk8 Xcert.der

UWAGA: hasło dla klucza musi być takie samo jak hasło dla 

server.store

background image

 

 

HSQLDB – SSL

4

2. Uruchomienie serwera:

>java 

-Djavax.net.ssl.keyStorePassword=hsqldb 
-Djavax.net.ssl.keyStore=hsqlserver.store
-cp hsqldb.jar
org.hsqldb.Server

[Server@13c5982]: [Thread[main,5,main]]: checkRunning(false) 
entered

...

[Server@13c5982]: Using TLS/SSL-encrypted JDBC

...

[Server@13c5982]: Startup sequence completed in 978 ms.

[Server@13c5982]: 2006-03-19 10:16:28.100 HSQLDB server 1.8.0 
is online

background image

 

 

HSQLDB – SSL

5

Po stronie klienta należy:

1. Uzyskać certyfikat serwera np:

>keytool -export -keystore server.store -alias hsqldb 

-file server.cer

Enter keystore password:  hsqldb

Certificate stored in file <server.cer>

Jeśli nie mamy dostępu do 

server.store

 możemy użyć dowolnego narzędzia do 

połączenia się z serwerem i odebrania certyfikatu np:

openssl s_client -connect host:port

 - zakodowany w Base64 certyfikat 

pojawi sie na ekranie pomiędzy liniami 

-----BEGIN CERTIFICATE-----
...
----END CERTIFICATE-----

Ten fragment zapisujemy do pliku 

server.cer

.

background image

 

 

HSQLDB – SSL

6

2. Dodać certyfikat serwera jako zaufany:

>keytool -import -trustcacerts -keystore hsqlclient.store -alias hsql 

-file hsqlserver.cer

Enter keystore password:  

hsqldb

Owner: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, 
C=Unknown

Issuer: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, 
C=Unknown

Serial number: 441d1f43

Valid from: Sun Mar 19 10:07:15 CET 2006 until: Tue Apr 18 11:07:15 
CEST 2006

Certificate fingerprints:

         MD5:  68:A2:33:BA:FA:4B:08:4A:E2:21:DD:E5:F6:7B:E3:8A

         SHA1: 
59:6A:4D:66:03:C8:D6:B0:D1:4C:0B:1B:30:E2:90:0F:88:66:EC:40

Trust this certificate? [no]:  

yes

Certificate was added to keystore

background image

 

 

HSQLDB – SSL

7

JVM musi zostać poinformowana, ze w pliku 

hsqlclient.store 

znajdują się 

zaufane certyfikaty. Można to zrobić na trzy sposoby:

a) plik 

hsqlclient.store

 należy dodać do katalogu z zaufanymi certyfikatami (w 

JDK zwykle: 

JAVA_HOME/jre/lib/security/cacerts

), 

b) wywołać program kliencki z opcją:

-Djavax.net.ssl.trustStore=/sciezka/do/hsqlclient.store

c) w kodzie programu klienckiego użyć instrukcji:

 

System.getProperties().put("javax.net.ssl.trustStore", 

"/sciezka/do/hsqlclient.store");

background image

 

 

HSQLDB – SSL

8

Przykładowy program klienta:

import java.sql.*;

public class HSQLDb {

public static void main(String[] args){

System.getProperties().put("javax.net.ssl.trustStore",

"/sciezka/do/hsqlclient.store");

System.getProperties().put("javax.net.debug","all");

try {

Class.forName("org.hsqldb.jdbcDriver").newInstance();

} catch (Exception e) { e.printStackTrace(); return; }

background image

 

 

HSQLDB – SSL

9

try {

Connection con = DriverManager.getConnection(

"jdbc:hsqldb:

hsqls

://localhost/test", "sa", "");

Statement stmt = con.createStatement();

ResultSet rs = stmt.executeQuery("SELECT NOW()");

rs.next();

System.out.println(rs.getString(1));

con.close();

} catch (SQLException ex) { ex.printStackTrace(); }

}

}

}

background image

 

 

MySQL i JDBC

Driver JDBC do bazy MySQL: 

http://www.mysql.com/products/connector/j/

. 

Dokumentacja: 

http://dev.mysql.com/doc/refman/5.0/en/java-connector.html

Nawiązanie połączenia:

Connection con = DriverManager.getConnection(

"jdbc:mysql://localhost/test?user=monty&password=");

Ogólnie "connectString" ma postać:

jdbc:mysql://[host][,failoverhost...][:port]/[database]
[?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...

Domyślny adres host'a to '127.0.0.1'. Domyślny port to '3306'.

jdbc:mysql://[host:port],[host:port].../[database]
[?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...

Jeśli nie zostanie podana nazwa bazy danych, w przyszłości należy ją ustawić 

metodą 

setCatalog()

 na rzecz obiektu 

Connection

 lub w zapytaniach przesyłać 

pełne nazwy tabel: (np. 

SELECT dbname.tablename.colname FROM 

dbname.tablename

).

10

background image

 

 

Wybrane własności połączenia

 

user

 – nazwa użytkownika (domyślnie 

''

),

 

password

- hasło (

''

),

 

useCompression

 – czy używać kompresji podczas komunikacji z serwerem 

(

false

),

 

autoReconnect

 – czy odtwarzać nieaktywne połączenia (

false

),

 

useSSL

 – czy używać SSL'a podczas komunikacji (

false

),

 

requireSSL

 – wymagać SSL'a gdy 

useSSL=true

? (

false

),

 

logger

 – nazwa klasy logującej implementującej 

com.mysql.jdbc.log.Log

używanej do logowania zdarzeń (

com.mysql.jdbc.log.StandardLogger

),

 

zeroDateTimeBehavior

 – jak obsługiwać daty wypełnione zerami, opcje: 

exception

round

 oraz 

convertToNull

 (

exception

).

11

background image

 

 

Kodowanie znaków

Wszystkie teksty wysyłane przez sterownik do bazy danych są automatycznie 

konwertowane z Unikodu (natywne kodowanie w Javie) do kodowania używanego 

przez komputer klienta. 

Kodowanie znaków między klientem i serwerem jest wykrywane automatycznie 

podczas nawiązania połączenia. Kodowanie używane przez sterownik jest ustawiane 

po stronie serwera poprzez  

character_set

 (przed 4.1.0) lub  

character_set_server

 (od 4.1.0). Aby zmienić automatyczne kodowanie należy 

ustawić własność 

characterEncoding

 w 

connectString'u

.

Najczęstsze kodowania nazwa MySQL (nazwa Java):

usa7 (US-ASCII), latin1 (ISO8859_1), latin2 (ISO8859_2), win1250ch (Cp1250),

utf8 (UTF-8), ucs2 (UnicodeBig).

12

background image

 

 

Używanie SSL'a

SSL szyfruje wszystkie przesyłane dane. Wydajność komunikacji spada o 35-50%.

Konfiguracja serwera: 

http://dev.mysql.com/doc/refman/5.0/en/secure-connections.html.

W skrócie:

 konfiguracja kompilacji: 

SHOW VARIABLES LIKE 'have_openssl';

 wygenerowanie certyfikatów SSL:

http://dev.mysql.com/doc/refman/5.0/en/secure-create-certs.html?ff=nopfpls

 zmiany w pliku 

my.cnf

,

 uruchomienie serwera.

13

background image

 

 

Używanie SSL'a

14

1. Import certyfikatu serwera MySQL:

>cp /etc/mysql/openssl/cacert.pem cacert.pem

>keytool -import -alias mysql -file cacert.pem -keystore mysql.store

Enter keystore password:  

mysqljava

Owner: CN=Michal Ciesla, O=Internet Widgits Pty Ltd, ST=Some-State, C=pl

Issuer: CN=Michal Ciesla, O=Internet Widgits Pty Ltd, ST=Some-State, C=pl

Serial number: c55bf7ad0557670b

Valid from: Sun Mar 19 20:54:21 CET 2006 until: Tue Apr 18 21:54:21 CEST 2006

Certificate fingerprints:

         MD5:  FA:3C:B9:34:9E:11:FB:0E:D9:1C:C9:40:A5:3E:CB:E8

         SHA1: 4F:9F:A8:C9:B1:3B:8F:CE:0F:7D:B0:CC:C6:E6:5A:53:EA:4B:B7:FC

Trust this certificate? [no]:  

yes

Certificate was added to keystore

>

background image

 

 

Używanie SSL'a

15

2. Ewentualne wygenerowanie certyfikatu klienta:

>keytool -genkey -keyalg rsa -alias client -keystore 
client.store

 

3. Ustawienie właściwości JVM:

-Djavax.net.ssl.keyStore=/sciezka/do/mysql.store

-Djavax.net.ssl.keyStorePassword=*********

-Djavax.net.ssl.trustStore=/sciezka/do/client.store

-Djavax.net.ssl.trustStorePassword=********* 

4. Dodanie do przy połączeniu opcji: 

useSSL=true

5. Sprawdzenie – uruchomienie JVM z opcją 

-Djavax.net.debug=all

background image

 

 

Używanie SSL'a

16

import java.sql.*;

public class MySQLDb {

public static void main(String[] args){

String sString =

"jdbc:mysql://localhost/test?" +
"user=root&password=haslo&useSSL=true";

System.getProperties().put("javax.net.ssl.trustStore",

"/path/to/mysql.store");

System.getProperties().put("javax.net.debug","all");

try {

Class.forName(com.mysql.jdbc.Driver).newInstance();

} catch (Exception e) { e.printStackTrace(); return; }

background image

 

 

Używanie SSL'a

17

try {

Connection con =

DriverManager.getConnection(sString);

Statement stmt =con.createStatement();

ResultSet rs = stmt.executeQuery("SELECT NOW()");

rs.next();

System.out.println(rs.getString(1));

con.close();

} catch (SQLException ex) { // ex.printStackTrace(); }

}

}

background image

 

 

SSL i Java

18

Protokół SSL umożliwia bezpieczną (szyfrowaną) transmisję danych poprzez 

niezabezpieczoną sieć. Dodatkowo SSL umożliwia autoryzację stron komunikacji. 

W tym celu wykorzystywany jest mechanizm certyfikatów. Za transmisję z użyciem 

protokołu SSL odpowiedzialnesą klasy zgrupowane w pakiecie javax.net.SSL.

Implementacja SSH jest dostępna poprzez zewnętrzne biblioteki. Jedną z nich jest 

jsch (http://www.jcraft.com/jsch/).

background image

 

 

Przykład: serwer echo

19

Przykład ze strony: http://tvilda.stilius.net/java/java_ssl.php

Piersza czynność to wygenerowanie klucza:

keytool -genkey -keystore mySrvKeystore -keyalg RSA

Kod programu serwera:

import javax.net.ssl.*;

import java.io.*;

public class EchoServer {

public static void main(String[] args) {

t

ry {

SSLServerSocketFactory factory = 

(SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();

SSLServerSocket ss = (SSLServerSocket)

factory.createServerSocket(9999);

background image

 

 

Przykład: serwer echo

20

   SSLSocket s = (SSLSocket) ss.accept();

InputStreamReader isr = 

new InputStreamReader(s.getInputStream());

BufferedReader br = new BufferedReader(isr);

String sTmp = null;

while ((sTmp = bufferedreader.readLine()) != null) {

System.out.println(sTmp);

System.out.flush();

}

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

background image

 

 

Przykład: klient echo

21

import javax.net.ssl.*;

import java.io.*;

public class EchoClient {

public static void main(String[] args) {

try {

SSLSocketFactory factory = 

(SSLSocketFactory) SSLSocketFactory.getDefault();

SSLSocket s = (SSLSocket)

factory.createSocket("localhost", 9999);

InputStream inputstream = 

InputStreamReader isr = 

new InputStreamReader(System.in);

BufferedReader br = new BufferedReader(isr);

background image

 

 

Przykład: klient echo

22

OutputStreamWriter osw = 

new OutputStreamWriter(s.getOutputStream());

BufferedWriter bw = new BufferedWriter(osw);

String sTmp = null;

while ((sTmp = br.readLine()) != null) {

bw.write(sTmp + '\n');

bw.flush();

}

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

background image

 

 

Przykład: uruchomienie programów

23

Uruchomienie serwera:

java -Djavax.net.ssl.keyStore=mySrvKeystore -Djavax
.net.ssl.keyStorePassword=123456 EchoServer

Uruchomienie klienta:

java -Djavax.net.ssl.trustStore=mySrvKeystore -Djavax
.net.ssl.trustStorePassword=123456 EchoClient

Dodatkowe parametry wywołania pozwolą zobaczyć informacje związane z 
połączeniem SSL:

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

background image

 

 

SSL i autoryzacja

24

Domyślnie tylko jedna strona komunikacji (serwer) musi potwierdzać swoją 

tożsamość.  Jeśli konieczne jest potwierdzenie toższności klienta należy użyć 

medod: 

setNeedClientAuth(true)

 lub 

setWantClientAuth(true)

 

wywołanych na rzecz obiektu 

SSLServerSocket

Jeśli chcemy aby żadna ze stron nie musiała potwierdzać swojej tożsamości musimy 

zmienić domyślne algorytmy kodowania. Najłatwiej zrobić to tworząc własne 

rozszerzenie klasy 

SSLSocketFactory

.

Listę obsługiwanych i domyślnych algorytmów uzyskamy za pomocą metod:

getSuppotredCipherSuites()

 oraz 

getDefaultCipherSuites()

.

background image

 

 

SSL i autoryzacja – listy algorytmów

25

Domyślne:

SSL_RSA_WITH_RC4_128_MD5

SSL_RSA_WITH_RC4_128_SHA

TLS_RSA_WITH_AES_128_CBC_SHA

TLS_DHE_RSA_WITH_AES_128_CBC_SHA

TLS_DHE_DSS_WITH_AES_128_CBC_SHA

SSL_RSA_WITH_3DES_EDE_CBC_SHA

SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA

SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA

SSL_RSA_WITH_DES_CBC_SHA

SSL_DHE_RSA_WITH_DES_CBC_SHA

SSL_DHE_DSS_WITH_DES_CBC_SHA

SSL_RSA_EXPORT_WITH_RC4_40_MD5

SSL_RSA_EXPORT_WITH_DES40_CBC_SHA

SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA

SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA

Wspierane: wszystkie domyślne oraz:

SSL_DHE_RSA_WITH_DES_CBC_SHA

SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA

SSL_RSA_WITH_NULL_MD5

SSL_RSA_WITH_NULL_SHA

SSL_DH_anon_WITH_RC4_128_MD5

TLS_DH_anon_WITH_AES_128_CBC_SHA

SSL_DH_anon_WITH_3DES_EDE_CBC_SHA

SSL_DH_anon_WITH_DES_CBC_SHA

SSL_DH_anon_EXPORT_WITH_RC4_40_MD5

SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA

background image

 

 

Pdsumowanie

26

Bezpieczeństwo jest się jednym z priorytetów przy tworzeniu oprogramowania. 

Częściowo może być ono zapewnione poprzez szyfrowanie przesyłanych informacji. 

Java standardowo wspiera protokół TLS-SSL jak również jest przygotowana do 

łatwej implementacji nowych rozwiązań w tej dziedzinie.