"JDBC thin" sans mot de passe ou Comment intégrer Oracle dans une PKI via SSL

Un truc que je n’ai jamais bien compris avec Oracle, c’est l’intérêt de créer des mots de passe qui se retrouvent finalement:

  • connus par tous, y compris de personnes qui ont quitté les projets 5 ans auparavant
  • stockés dans des fichiers de configurations sous des formes réversibles ou pire, en clair
  • dans des comptes génériques, donc anonymes, intraçables et en dehors de toute stratégie d’audit

D’un autre côté, les équipes de sécurité réclament de valider la complexité des mots de passe, de les faire expirer, de chiffrer les données, de les rendre invisibles, de chiffrer les sauvegardes, de limiter et d’auditer les accès, d’appliquer les « Critical Patch Updates », de ne pas installer Oracle JServer. A la fin, la réalité est toute autre que celle visée. Une fois que quelqu’un a accès à une zone serveur, il a beau jeu de disparaitre de tous les écrans radar grâce à un mot de passe « anonyme ».

Cet article présente comment intégrer les accès JDBC thin de vos bases de données dans une infrastructure à clés publiques et oublier à tout jamais vos mots de passe.
Vous me direz : « cette zone du SI est sécurisée ; les données sont bien gardées. Elles le sont par des multinationales de 10000 personnes elles-mêmes faisant appel à d’autres sociétés ou individus. Elles privilegient la souplesses au détriment de vos données. Combien de personnes peuvent franchir vos grilles ? 5, 20, 100, 1000 ? En fait, ceux qui devraient pouvoir franchir les grilles de vos bases de données sont probablement 5 à 100 fois moins. Et ce n’est pas parce que vous avez confiance dans votre mur d’enceinte qu’il ne faut pas créer d’autres remparts. Je ne vais pas vous prendre la tête, il n’y a pas de secret. Ca existe depuis que les loups ont faim. A moins que vous n’utilisiez une PKI, vos systèmes sont une aubaine pour tous les hacker en herbe qui travaillent sur vos infrastructures. Heureusement, vos administrateurs sont dans leur immense majorité bien intentionnés, trop occupés pour avoir des pensées négatives, incapables de revendre des informations. Enfin, à défaut de mieux, ils font l’objet d’enquêtes de moralité.

Cet article est aussi la preuve, s’il en fallait une, qu’on peut faire des trucs horribles, même avec une PKI. Enfin, je laisse aux gens dont c’est le métier le soin de mettre en place une infrastructure de sécurité ; l’idée ici est simplement de créer les certificats et les comptes pour utiliser une authentification forte en JDBC thin.

Etape 1. Créer une autorité de certification (CA)

Pour avoir un environnement représentatif d’une PKI, il vous faut une autorité de certification ; bien sur vous pouvez utiliser des certificats sans CA comme décrit dans la note 1190873.1(*). Dans ce cas, la gestion des clés est laissée aux seuls DBA.

Pour cet exemple, j’utilise le package openssl qui fournit un script CA.pl pour créer et gérer une autorité de certification. Dans la vie réelle, si vous voulez assurer une vrai sécurité, vous utiliserez des supports spécifiques pour vos clés. Le wallet Oracle sait accéder des équipements de sécurité via le standard PKCS11.

Sur Linux, installez donc openssl et créez votre CA comme ci-dessous :

locate CA.pl |grep -v gz
/usr/lib/ssl/misc/CA.pl

mkdir ~/CA
cd ~/CA

/usr/lib/ssl/misc/CA.pl -newca
CA certificate filename (or enter to create)

Making CA certificate ...
Generating a 1024 bit RSA private key
.................................++++++
.................................++++++
writing new private key to './demoCA/private/cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:FR
State or Province Name (full name) [Some-State]:Paris
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ArKZoYd
Organizational Unit Name (eg, section) []:.
Common Name (eg, YOUR name) []:CA
Email Address []:.

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number:
85:a4:e9:bb:41:06:53:ba
Validity
Not Before: Sep 18 08:51:37 2010 GMT
Not After : Sep 17 08:51:37 2013 GMT
Subject:
countryName = FR
stateOrProvinceName = Paris
organizationName = ArKZoYd
commonName = CA
X509v3 extensions:
X509v3 Subject Key Identifier:
1F:0C:C7:04:76:85:D2:13:A4:86:C6:00:C9:DA:18:F3:E6:2C:4C:2F
X509v3 Authority Key Identifier:
keyid:1F:0C:C7:04:76:85:D2:13:A4:86:C6:00:C9:DA:18:F3:E6:2C:4C:2F
DirName:/C=FR/ST=Paris/O=ArKZoYd/CN=CA
serial:85:A4:E9:BB:41:06:53:BA

X509v3 Basic Constraints:
CA:TRUE
Certificate is to be certified until Sep 17 08:51:37 2013 GMT (1095 days)

Write out database with 1 new entries
Data Base Updated

Notez bien le mot de passe utilisé pour sécuriser votre CA; vous pouvez ensuite changer la durée de validité du certificat de la CA avec openssl :

cd demoCA 
openssl x509 -in cacert.pem
-days 1095 -out cacert.pem
-signkey ./private/cakey.pem
Getting Private key
Enter pass phrase for ./private/cakey.pem:

Etape 2. Créer des wallets et faire des demandes de certificat avec OWM

Créez ensuite 2 wallets, le premier pour le serveur de base de données et le second pour le client JDBC thin ; commencez par créer les répertoires correspondants :

mkdir -p /u01/app/oracle/SSL/wallet/server/BLACK
mkdir -p /u01/app/oracle/SSL/wallet/client/demo

Vous pouvez utiliser Oracle Wallet Manager (lancez owm) puis sélectionnez le menu « Wallet > New » comme ci-dessous ; mettez un mot de passe pour protéger la demande de certificat

OWM vous demande si vous voulez demander un nouveau certificat, répondez « Yes » puis définissez le DN de votre choix comme ci-dessous :

OWM vous indique que la demande de certificat a été réalisée et vous conseille de l’exporter s
ous la forme d’un fichier .pem pour la soumettre a une autorité de certification:

  • Enregistrez votre wallet avec le menu « Walletr > Save » dans /u01/app/oracle/SSL/server/BLACK
  • Exportez la demande de certificat à partir du menu « Operations > Export Certificate Request… ». Enregistrez la sous le nom DBReq.pem :
Enfin vous pouvez permettre aux produits Oracle de se connecter au Wallet sans mot de passe en sélectionnant le menu « Wallet > Auto Login » puis en enregistrant de nouveau votre wallet :

Vous en aurez vite assez de Oracle Wallet Manager et vous pourrez aussi facilement réaliser les mêmes opérations à l’aide de la commande orapki comme ci-dessous :

  • Créez un wallet vide avec les fichiers .sso et .pkcs12
cd /u01/app/oracle/SSL/wallet/client/demo
orapki wallet create
   -wallet /u01/app/oracle/SSL/wallet/client/demo
   -auto_login -pwd manager1
  • Ajoutez une demande de certificat pour le DN (Distinguished Name) de votre client
orapki wallet add 
   -wallet /u01/app/oracle/SSL/wallet/client/demo
   -dn 'CN=demo, ST=ArKZoYd, C=FR'
   -keysize 1024 -validity 1095 -pwd manager1
  • Exportez la demande sous forme d’un fichier .pem à envoyer à la CA
orapki wallet export 
-wallet /u01/app/oracle/SSL/wallet/client/demo
-dn 'CN=demo, ST=ArKZoYd, C=FR'
-request CLReq.pem -pwd manager1

Etape 3. Créer les certificats en tant qu’autorité de certification

C’est l’autorité de certification qui va créer les certificats. Envoyez les fichiers de demande de certificats CLReq.pem et DBReq.pem sur le serveur de la CA dans le répertoire ~/CA puis générer les certificats comme ci-dessous :

cp DBReq.pem newreq.pem
/usr/lib/ssl/misc/CA.pl -sign
mv newcert.pem DBCert.pem
cp CLReq.pem newreq.pem
/usr/lib/ssl/misc/CA.pl -sign
mv newcert.pem CLCert.pem
rm newreq.pem

Renvoyez ensuite les certificats créés sur leur serveur respectif ainsi que le certificat de l’autorité de certification nommé .~/CA/demoCA/cacert.pem

Etape 4. Enregistrer le certificat dans les wallets avec OWM

Ouvrez de nouveau les wallets avec OWM puis commencez par enregistrer le certificat de la CA en sélectionnant le menu « Operations > Import Trusted Certificate » puis le fichier cacert.pem :

Le certificat de l’autorité de certification apparaît alors dans les certificats de confiance stockés dans le wallet :

Ensuite enregistrez le certificat correspondant à la demande effectuée précédemment « Operations > Import User Certificate » et en selectionnant le fichier DBCert.pem :

Le wallet de la base de données contient désormais les informations nécessaires aux connexions.

Vous pouvez opérer de la même façon avec le wallet du client ou simplement avec orapki comme ci-dessous :

cd /u01/app/oracle/SSL/wallet/client/demo
orapki wallet add -wallet /u01/app/oracle/SSL/wallet/client/demo
-trusted_cert -cert cacert.pem -pwd manager1

orapki wallet add -wallet /u01/app/oracle/SSL/wallet/client/demo
-user_cert -cert CLCert.pem -pwd manager1

Vous pourrez vérifier avec OWM que les différents certificats sont correctement enregistrés :

Etape 5. Configurer la base de données

Pour que l’utilisateur puisse se connecter et ait des droits dans la base de données vous pouvez bein sur utiliser les Enterprise Users; j’en ai parlé il y a quelques années avec iPlanet et OID puis Oracle Virtual Directory. Dans notre cas, nous allons faire beaucoup plus simple et simplement créer un utilisateur que l’on fera correspondre au DN du client :

sqlplus / as sysdba
create user demo identified externally as 'CN=demo, ST=ArKZoYd, C=FR';
grant connect to demo;
exit

Pour que l’authentification fonctionne, vous devez également vérifier que :

  • remote_os_authent=FALSE
  • os_authent_prefix= »

Si ce n’est pas le cas, vous devrez redémarrer votre base de données :

sqlplus / as sysdba
alter system set remote_os_authent=FALSE scope=spfile;
alter system set os_authent_prefix='' scope=spfile;
startup force;

Etape 6. Configurer le listener

Il faut modifier les fichiers sqlnet.ora et listener.ora pour que le listener écoute sur un port en SSL (e.g. 2484) et que le listener accède au wallet du serveur. Voici un exemple de fichiers de configuration du réseau du serveur :

cat $ORACLE_HOME/network/admin/sqlnet.ora 
SQLNET.AUTHENTICATION_SERVICES= (BEQ, TCPS)

SSL_VERSION = 0

SSL_CLIENT_AUTHENTICATION = TRUE

WALLET_LOCATION =
(SOURCE =
(METHOD = FILE)
(METHOD_DATA =
(DIRECTORY = /u01/app/oracle/SSL/wallet/server/BLACK)
)
)

SSL_CIPHER_SUITES= (SSL_RSA_EXPORT_WITH_DES40_CBC_SHA)

ADR_BASE = /u01/app/oracle

Le fichier de configuration du listener est quant à lui le suivant :

cat $ORACLE_HOME/network/admin/listener.oraWALLET_LOCATION =
(SOURCE =
(METHOD = FILE)
(METHOD_DATA =
(DIRECTORY = /u01/app/oracle/SSL/wallet/server/BLACK)
)
)

LISTENER =
(DESCRIPTION_LIST =
(DESCRI PTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = hello-laptop)(PORT = 1521))
)
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCPS)(HOST = hello-laptop)(PORT = 2484))
)
)

Une fois la configuration effectuée, redémarrez le listener :

lsnrctl stop 
lsnrctl start

Etape 7. Configurer votre environnement Java

Pour ce test, j’utilise une machine virtuelle Java 1.6; vous devez positionner l’environnement de manière à utiliser cette VM :

export JAVA_HOME=/opt/jdk1.6.0_18
export PATH=$JAVA_HOME/bin:$PATH

D’autre part, il faut, non seulement ajouter le driver JDBC mais également tous les fichiers jar qui permettent de se connecter au fournisseur de sécurité Oracle

export CLASSPATH=.
export CLASSPATH=$CLASSPATH:$ORACLE_HOME/jdbc/lib/ojdbc6.jar
export CLASSPATH=$CLASSPATH:$ORACLE_HOME/jlib/oraclepki.jar
export CLASSPATH=$CLASSPATH:$ORACLE_HOME/jlib/osdt_cert.jar
export CLASSPATH=$CLASSPATH:$ORACLE_HOME/jlib/osdt_core.jar
export CLASSPATH=$CLASSPATH:$ORACLE_HOME/jlib/ojpse.jar

Enfin, il faut ajouter le fournisseur Oracle dans la configuration de sécurité de la JVM (le fichier $JAVA_HOME/jre/lib/security/java.security), en ajoutant la ligne suivante (décaler d’autant les providers de 3 déjà 8) :

security.provider.3=oracle.security.pki.OraclePKIProvider

Etape 8. Modifier vos programmes Java

Les programmes java ne doivent pas être modifiés, les seules différences résident dans :

  • l’URL de connexion qui utilise TCPS au lien de TCP 
  • le fait que les paramètres utilisateurs et mots de passe de votre connexion sont laissés vides

A moins que votre serveur d’applications vérifie que ces champs de sont pas vides, l’utilisation de SSL pour s’authentifier sera donc complètement transparente pour l’application. Voici un exemple de programme que vous pouvez utiliser pour faire vos tests; modifiez simplement l’url jdbc pour correspondre à votre configuration :

cat OracleAuthSSL.java
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class OracleAuthSSL {
public static void main(String[] args)
throws SQLException {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
String url = "jdbc:oracle:thin:@"
+ "(DESCRIPTION = "
+ "(ADDRESS_LIST = "
+ "(ADDRESS=(PROTOCOL = TCPS)(HOST = hello-laptop)(PORT = 2484))"
+ ") "
+ "(CONNECT_DATA = (SERVICE_NAME = BLACK))"
+ ")";

Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("select user from dual");

while (rset.next())
System.out.println(rset.getString(1));

rset.close();
stmt.close();
conn.close();
}
}

Etape 8. Exécuter le programme

Compilez le programme :

javac OracleAuthSSL.java

Pour exécuter le programme, positionnez simplement les informations qui permettront au provider de sécurité d’utiliser la bonne méthode d’authentification et de trouver les fichiers qui contiennent les certificats clients et de la CA; voici comment lancer la ligne de commande correspondante :

java -Doracle.net.authentication_services="(TCPS)" 
 -Djavax.net.ssl.trustStore=/u01/app/oracle/SSL/wallet/client/demo/cwallet.sso
 -Djavax.net.ssl.trustStoreType=SSO
 -Djavax.net.ssl.keyStore=/u01/app/oracle/SSL/wallet/client/demo/cwallet.sso
 -Djavax.net.ssl.keyStoreType=SSO OracleAuthSSL

DEMO

Quelques remarques complémentaires :

  • (*) Pour un exemple plus simple sans autorité de certification, utilisez des certificats « self-signed » et reportez-vous à la note suivante : « How To Setup The Database And The Client To Have SSL Mutual Authentication With An Oracle Jdbc Thin Client And The Database? [ID 1190873.1] »
  • Ne négligez pas l’impact de SSL sur les temps de connexions, sur le dialogue client/serveur ni sur l’utilisation des processeurs
  • Si vous cherchez plus d’information sur l’utilisation du script CA.pl, il y a une bonne introduction dans le howto IPSec.
  • Pour tracer le fonctionnement du programme, ajoutez le paramètre -Djavax.net.debug=ssl
  • Il est possible d’enregistrer le provider dynamiquement sans utiliser le fichier java.policy pour cela, utilisez Security.addProvider(new oracle.security.pki.OraclePKIProvider());
  • Comme indiqué dans le licensing guide, pour utiliser l’authentification forte ou les communication SSL entre vos clients et vos serveurs, vous devez avoir des licences Advanced Security Options
  • L’authentification forte avec les drivers JDBC thin est une nouvelle fonctionnalité d’Oracle 11g. En 10g, vous ne pouviez utiliser SSL que pour chiffrer les connections JDBC entre le client et le serveur. Pour gérer les connexions, vous deviez utiliser les drivers JDBC/OCI.