Accueil Nos publications Blog Connexions sécurisées aux bases de données Oracle via les wallets

Connexions sécurisées aux bases de données Oracle via les wallets

 

Dans la famille So@t, nous sommes quelques irréductibles à ne pas savoir ce que veut dire le “j” dans jsp mais qui savons polémiquer sur un clustering factor de 1… Nous sommes les DBA Oracle.

Nous allons vous présenter un outil d’Oracle qui pourrait faciliter la vie des développeurs et surtout sécuriser les connexions à la base. Cet outil s’appelle les wallets.

Les wallets Oracle sont 2 fichiers cryptés en Triple-DES qui ne sont manipulables qu’avec des binaires Oracle, contenant l’association nom de service à (compte oracle ; mot de passe).

Ainsi, pour vous connecter au service vous n’aurez qu’à indiquer le nom du service et  Oracle détermine alors via les wallets le compte oracle à utiliser et le mot de passe de celui-ci.

Dans la suite de ce document nous allons donc vous présenter dans un premier temps les notions sur Oracle à connaître, suivi de la présentation des wallets et d’un exemple simple d’utilisation des wallets avec du Java.

Notions Oracle à connaître

Afin de mieux appréhender le sujet de cet article nous allons vous présenter sans entrer trop amplement dans les détails quelques notions Oracle à connaître.

Une base de données Oracle stockée dans plusieurs fichiers sur le disque d’un serveur est utilisée par une ou plusieurs instance(s). Une instance est composée d’une zone de mémoire appelée zone globale système ou SGA (System Global Area) et de plusieurs processus Oracle en arrière-plan permettant de faire le lien entre la zone mémoire et les fichiers de base de données sur le disque.

Lorsque l’on parle d’une base de données c’est généralement par le biais du nom d’une des instances s’y connectant : l’Oracle SID (System ID). L’Oracle SID est unique pour une base de données sur un système.

Sa variable d’environnement est :

  • %ORACLE_SID% pour le système Microsoft Windows et sa valeur est définie dans le registre.

  • $ORACLE_SID pour les systèmes Unix et sa valeur est définie dans le fichier .profile.

Le répertoire où est installé le soft Oracle est indiqué par la variable d’environnement :

  • %ORACLE_HOME% pour le système Microsoft Windows et sa valeur est définie dans le registre.

  • $ORACLE_HOME pour les systèmes Unix et sa valeur est définie dans le fichier .profile.

L’outil de communication en réseau d’Oracle s’appelle Oracle Net et peut servir à se connecter à des bases de données.

Les fichiers utiles à la configuration d’un client SQL*Net se trouvent dans le répertoire ORACLE_HOME/network (net80 pour versions antérieures à la 9i).

Un fichier sqlnet.ora précise, s’il existe, l’ordre (les priorités) des méthodes de résolution de nom utilisées par le client à l’aide du paramètre NAMES.DIRECTORY_PATH.

Dans le sous répertoire ADMIN se trouve le fichier tnsnames.ora dans lequel est listé la ou les chaines de connexion aux bases de données souhaitées, que l’on appelle descripteur de connexion. Ce fichier est en général fourni par l’administrateur de bases de données.

Voici un exemple de tnsnames.ora

ORCL1 = (DESCRIPTION =

(ADDRESS=

(PROTOCOL=TCP)

(HOST=HQ)

(PORT=1521))

(CONNECT_DATA=

(SID=TEST)))

Ce fichier permet de se connecter  via le protocole TCP/IP à la base de données ORCL1 sur le serveur HQ via l’instance TEST.

Ainsi une connexion à la base ORCL1 peut se faire de la manière suivante :

sqlplus christophe/toto@TEST

Une autre façon de nous connecter à la base ORCL1 (celle préconisée par Oracle à partir de la 8i) est la connexion par un nom de services de cette base. L’administrateur peut en effet définir un nom de services qui se réfèrent au descripteur de connexion. Et contrairement à l’instance qui est unique par serveur pour une base de données, les services eux peuvent être multiple sur un serveur pour une même base de données.

Ces noms de services sont également stockés dans le tnsnames.ora.

La notion de nom de services étant assez abstraite, pour comprendre ce charabia prenons l’exemple suivant :

Supposons que la base ORCL1, contiennent des informations pouvant être utiles aux vendeurs d’une entreprise, ainsi qu’au personnel des ressources humaines de cette même entreprise.

Les  membres de ces deux entités ne faisant pas le même travail peuvent se connecter à la base de données ORCL1 selon le service de la base de données qui leur est dédié.

Le fichier tnsnames.ora correspondant pourrait ressembler ainsi à cela :

ORCL1 = (DESCRIPTION =

(ADDRESS=

(PROTOCOL=TCP)

(HOST=HQ)

(PORT=1521))

(CONNECT_DATA=

(SERVICE_NAME=VENDEURS)))

ORCL1 = (DESCRIPTION =

(ADDRESS=

(PROTOCOL=TCP)

(HOST=HQ)

(PORT=1521))

(CONNECT_DATA=

(SERVICE_NAME=RH)))

Les connexions pour un vendeur à la base ORCL se ferait donc de la manière suivante

sqlplus christophe/toto@VENDEURS

 Et pour un membre des ressources humaines ainsi

sqlplus christophe/toto@RH

Les noms de services ont encore d’autres utilités mais avec ces notions vous en savez assez maintenant pour aborder le sujet de cet article, nos fameuses wallets.

Le répertoire où se situe le fichier tnsnames.ora  est indiqué par la variable d’environnement :

  • %TNS_ADMIN% pour le système Microsoft Windows et sa valeur est définie dans le registre.

  • $TNS_ADMIN pour les systèmes Unix et sa valeur est définie dans le fichier .profile

L’objectif

L’objectif est de sécuriser l’accès aux bases de données en évitant de laisser les mots de passe écrits en clair dans les scripts ou fichiers de configuration. Même sur les productions, il reste trop de connexions avec les mots de passe mis en clair…

Le second objectif est de pouvoir déléguer la gestion des habilitations à une équipe différente des DBA ou des développeurs/utilisateurs. En effet, une fois la wallet créée, on peut l’utiliser sans pouvoir lire les mots de passe enregistrés dedans.

Manipulation

Dans notre exemple, toute la manipulation des wallets se fera avec le binaire mkstore qui est installé avec les clients Oracle (et les serveurs). Attention, le binaire n’est pas installé avec Instant Client. Il y a toutefois d’autre moyen de manipuler les wallets comme par exemple avec l’outil graphique Wallet Manager.

Initialisation

Ainsi après avoir configuré l’ORACLE_HOME et le chemin des binaires Oracle dans la variable d’environnement PATH, on peut créer, modifier ou supprimer une wallet avec msktore

Pour notre exemple nous allons nous placer sur un système Unix sur lequel est installé un client Oracle 10GR2.

Les binaires Oracle sont installés à l’arborescence suivante : /products/oracle/10.2.0.4

Nous cherchons à nous connecter au service ORCL1 de la base ORCL1.

Voici les commandes pour configurer notre environnement afin de pouvoir utiliser msktore

$ export ORACLE_HOME=/products/oracle/10.2.0.4

$ export PATH=$ORACLE_HOME/bin:$PATH

Création

La commande pour créer une wallet est la suivante :

mkstore –wrl [EMPLACEMENT] – create

Exemple :

$ mkstore -wrl . -create

Enter password:

Enter password again:

On se retrouve avec 2 fichiers tout neufs :
$ ll
total 24
-rw——-  1 oberthom dba 7940 Oct 24 17:13 cwallet.sso
-rw——-  1 oberthom dba 7912 Oct 24 17:13 ewallet.p12

La wallet peut être protégée par un mot de passe d’où les 2 lignes suivant la création.  Ce mot de passe ne sera pas demandé pour utiliser la wallet mais pour ajouter/supprimer une association  service -> (compte, mot de passe). En 11G, ce mot de passe est obligatoire et doit faire plus de 7 caractères

Ajouter une association

La commande pour ajouter une association service -> (compte ; mot de passe) est la suivante :

mkstore –wrl [EMPLACEMENT] –createCredential [SERVICE_NAME] [COMPTE][MDP]

Exemple :

Le compte : olivier

Le mot de passe : 12345#

Le service : ORCL1

$ mkstore -wrl . -createCredential ORCL1 olivier 12345#

Enter wallet password:
Create credential oracle.security.client.connect_string1

mkstore demande le mot de passe utilisé pour l’administration de la wallet.

On pourrait rajouter d’autres services dans la wallet comme par exemple le service RH ou VENDEUR tant que sur les postes de chaque vendeur et chaque membre des ressources humaines le tnsnames.ora contient le descripteur de connexion associé.

Lister les associations enregistrées

La commande pour lister les associations est la suivante :

mkstore –wrl [EMPLACEMENT] -listCredential

Exemple :

$ mkstore -wrl . -listCredential

Enter wallet password:

List credential (index: connect_string username)
1: ORCL1 olivier

Il est impossible de lire le mot de passe pour le service ORCL1 mais on voit que le compte associé est olivier.

Modifier ou supprimer une association

Les commandes pour modifier ou supprimer une association sont les suivantes :

–          Modification

mkstore –wrl [EMPLACEMENT] –modifyCredential [SERVICE_NAME] [COMPTE] [MDP]

–          Suppression

mkstore –wrl [EMPLACEMENT] –deleteCredential [SERVICE_NAME]

Exemples d’utilisation

 Dans nos deux exemples nous allons chercher à nous connecter à la base ORCL1 via le service ORCL1 avec le compte d’Olivier.  Notre administrateur de bases de données préféré nous a donné le tnsnames.ora nécessaire à la connexion que nous avons placé dans l’ORACLE_HOME/network/admin de notre client oracle. Et nous avons créé la wallet permettant de nous connecter.

Utilisation avec SQL*PLUS

Dans notre exemple nous nous plaçons sur un système unix.

Dans un dossier, copier les fichiers wallets.  Le répertoire pour l’exemple sera /home/oberthom/oracle

Créer un lien vers le tnsnames.ora à utiliser

$ ln –sf  $ORACLE_HOME/network/admin/tnsnames.ora .

Créer un fichier sqlnet.ora dans le répertoire ORACLE_HOME/network contenant l’emplacement du dossier où se trouve notre wallet.

$ cat sqlnet.ora

WALLET_LOCATION = (SOURCE = (METHOD = FILE) (METHOD_DATA = (DIRECTORY = /home/oberthom/oracle )))
SQLNET.WALLET_OVERRIDE = TRUE
SSL_CLIENT_AUTHENTICATION = FALSE

Exporter la variable TNS_ADMIN avec la valeur l’emplacement du nouveau dossier.

$ export TNS_ADMIN=/home/oberthom/oracle

Les connexions se font maintenant en utilisant la wallet :

$ sqlplus /nolog

SQL> conn /@ORCL1
Connecté.
SQL> show user
USER est “OLIVIER”

Dans les scripts, les connexions peuvent se faire directement :

sqlplus /@ORCL1

SQL*Plus: Release 10.2.0.4.0 – Production on Jeu. Nov. 3 16:28:08 2011
Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connecté à :
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 – 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> show user
USER est “OLIVIER”

Utilisation avec driver JDBC Thin

Environnement

Pour cet exemple, nous nous plaçons sur un système windows.

Pour utiliser les connexions en JDBC Thin, il faut ajouter la librairie correcte dans le CLASSPATH.

Pour une exécution avec la JRE5, ajouter la librairie ojdbc5.jar ; pour une exécution avec la JRE6, ajouter ojdbc6.jar. Pour l’utilisation des wallets, il faut aussi la librairie oraclepki.jar.

Création de la wallet

Le driver JDBC Thin utilise une chaine de connexion de la forme : “//machine:port/Service”. Il faut indiquer l’ensemble de la chaine de connexion dans la wallet.

Exemple :

mkstore -wrl . -createCredential //psu455:1625/ORCL1 OLIVIER 12345#

Code de connexion sans wallet


import java.sql.*;
import oracle.jdbc.pool.OracleDataSource;

public class TestNoWallet {
   public TestNoWallet() {
           super();
           try {
                   // The connect string
                   String connect_string = "jdbc:oracle:thin:/@//psu455:1625/ORCL1";

                   // The query we will execute
                   String query = "select 'Hello JDBC: ' || to_char(sysdate,'DD/MM/YYYY HH24:MI') from dual";

                   // The connection to the database
                   Connection conn;

                   //specify the datasource object
                   OracleDataSource ods = new OracleDataSource();
                   ods.setURL(connect_string);
                   ods.setUser("OLIVIER");
                   ods.setPassword("12345#");

                   // Connect to the database
                   System.out.println("Connecting to " + connect_string);
                   conn = ods.getConnection();
                   System.out.println("Connected");

                   // Create a statement
                   Statement stmt = conn.createStatement();

                   // Execute the query
                   System.out.println("Executing query " + query);
                   ResultSet rset = stmt.executeQuery(query);

                   // Dump the result
                   while (rset.next())
                           System.out.println(rset.getString(1));

                   // We're done
                   System.out.println("Done.");
           } catch (SQLException e) {
                   e.printStackTrace();
           }
   }

   public static void main(String[] args) {
           new TestNoWallet();
   }
}

Code de connexion avec wallet

 

Pour utiliser la wallet, il faut ajouter la librairie oraclepki.jar



import java.sql.*;
import oracle.jdbc.pool.OracleDataSource;

public class TestWallet {
   public TestWallet() {
           super();
           try {
                   // The connect string
                   String connect_string = "jdbc:oracle:thin:/@//psu455:1625/ORCL1";

                   // The query we will execute
                   String query = "select 'Hello JDBC: ' || to_char(sysdate,'DD/MM/YYYY HH24:MI') from dual";

                   String cheminRepertoireWallet="/home/oberthom/howso";

                   // The connection to the database
                   Connection conn;

                   // The wallet properties
                   java.util.Properties info = new java.util.Properties();
                   info.put("oracle.net.wallet_location", "(SOURCE=(METHOD=file)(METHOD_DATA=(DIRECTORY=" + cheminRepertoireWallet + ")))");

                   //specify the datasource object
                   OracleDataSource ods = new OracleDataSource();
                   ods.setURL(connect_string);
                   ods.setConnectionProperties(info);

                   // Connect to the database
                   System.out.println("Connecting to " + connect_string);
                   conn = ods.getConnection();
                   System.out.println("Connected");

                   // Create a statement
                   Statement stmt = conn.createStatement();

                   // Execute the query
                   System.out.println("Executing query " + query);
                   ResultSet rset = stmt.executeQuery(query);

                   // Dump the result
                   while (rset.next())
                           System.out.println(rset.getString(1));

                   // We're done
                   System.out.println("Done.");
           } catch (SQLException e) {
                   e.printStackTrace();
           }
   }

   public static void main(String[] args) {
           new TestWallet();
   }
}

Compilation

Les compilations se font de cette façon :

javac -cp /jdbc/lib/ojdbc5.jar:/jlib/oraclepki.jar:. TestWallet.java

Exécutions

java -cp /jdbc/lib/ojdbc5.jar:/jlib/oraclepki.jar:. TestWallet

Connecting to jdbc:oracle:thin:/@//psu455:1625/ORCL1
Connected

Executing query select 'Hello JDBC: ' || to_char(sysdate,'DD/MM/YYYY HH24:MI') from dual

Hello JDBC: 29/11/2011 09:56
Done.

Utilisation avec un progiciel

Pour les progiciels (WebSphere, Tomcat, Datastage etc...) l'utilisation des wallets devient spécifique. Certains sont prévus pour supporter nativement des Wallets (Tomcat par exemple) d'autres non. Ce n'est pas un problème technique (puisque c'est un changement interne à Oracle) mais un problème de configuration.

Par exemple, WebSphere6 refuse cette utilisation car il ne prend pas en compte une chaine de connexion sans utilisateur ni mot de passe. C'est donc directement la fenêtre de configuration de la datasource qui refuse cette configuration.

Dans le cas de Tomcat, il faut ajouter deux informations :

  • dans le XML de la datasource il faut ajouter le champ suivant : connectionProperties="oracle.net.wallet_location=/home/oberthom/howso"

  •  il faut ajouter aux $JAVA_OPTS Doracle.net.tns_admin=/home/oberthom/howso

Si votre progiciel n'accepte pas las Wallets, il y a une forte probailité qu'il crypte le compte / mot de passe après configuration. De cette façon, la sécurité du compte repose sur le progiciel.

Conclusion

Nous venons de voir qu’il est possible d’utiliser les wallets autant dans des scripts que dans du Java. Ce système permet de ne pas s’occuper de la sécurité pour stocker le compte et le mot de passe utilisé et de reléguer cet aspect au système. Avec les wallets, plus aucun compte n’est à fournir pour se connecter à un service, ce qui implique qu’il faut une wallet par compte pour un service.

En Java, la mise en place est totalement intégrée et devrait permettre de ne plus avoir de fichier properties avec compte et mot de passe en clair. Nous n'avons pas fourni d'exemple avec .Net mais l'utilisation des wallets est également possible avec ce langage.

L’utilisation des wallets est incluse dans la licence Entreprise Edition du moteur de base de données du coup si cette licence est déjà payée il n’y a aucune excuse pour ne pas s’en servir.

Liens

Voici quelques liens pour poursuivre l'étude des wallets.

https://blog.arkzoyd.com/2012/04/oracle-external-secure-password-store.html

https://blog.arkzoyd.com/2010/09/jdbc-thin-sans-mot-de-passe-ou-comment.html

https://laetitia-avrot.blogspot.fr/2011/05/jouer-avec-les-wallet.html

https://sysapp.wordpress.com/2010/08/31/how-to-oracle-wallet-with-jdbc-thin-driver-datasource-tomcat/

https://www.dba-oracle.com/t_wallet_manager.htm

https://docs.oracle.com/cd/B19306_01/network.102/b14268/asowalet.htm 

https://docs.oracle.com/cd/B15904_01/core.1012/b13995/wallets.htm