Sécurisation d’une application Web¶
Une application Web Java EE peut être sécurisée de manière déclarative. Cela signifie qu’il est possible de déclarer que certaines adresses de cette application sont soumises à des restrictions d’accès. Dans ce cas, le serveur doit pouvoir garantir la confidentialité des données grâce à une connexion sécurisée https et/ou l’utilisateur doit, au préalable, s’authentifier auprès du serveur.
Le mécanisme d’authentification relève de la configuration du serveur. Dans le processus de développement, l’équipe de développement configure l’application pour sécuriser l’accès à certaines parties de l’application et les administrateurs du serveur mettent en place la configuration nécessaire pour prendre en charge la sécurisation.
La déclaration des contraintes de sécurité est standardisée par Java EE. La configuration des mécanismes de sécurité est propre à chaque serveur Web Java.
Déclarer des contraintes de sécurité¶
Pour l’équipe de développement, il faut déclarer les contraintes de sécurité
dans le fichier web.xml
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<security-constraint>
<web-resource-collection>
<web-resource-name>Zone privée</web-resource-name>
<url-pattern>/private/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Zone avec accès restreint</realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
</web-app>
|
Pour l’exemple précédent, on déclare une zone privée correspondant à toutes les
adresses de la forme /private/*
(ligne 10). Cette zone n’est accessible que
pour les utilisateurs qui ont le rôle admin
(ligne 13). Les données doivent
être transmises de manière confidentielle, c’est-à-dire que les échanges doivent
se faire en https (ligne 16). On déclare ensuite la configuration pour réaliser
une étape de login. On déclare qu’il faut utiliser une authentification HTTP
en mode BASIC (ligne 21). Enfin, on déclare que l’application utilise le rôle
admin
(ligne 26).
À partir de cette configuration, le serveur doit pouvoir satisfaire l’ensemble de ces contraintes et garantir que les accès sont correctement sécurisés.
Configuration de l’authentification dans Tomcat¶
Tomcat utilise la notion de royaumes (Realms) pour définir des zone sécurisées. Cela permet de configurer différentes stratégies pour valider l’authentification d’un utilisateur. Ainsi Tomcat peut valider une authentification en recherchant le couple login/mot de passe dans une base de données, en interrogeant un serveur LDAP ou tout simplement en consultant un fichier de configuration. Il est également possible de fournir son propre mécanisme d’authentification en fournissant une bibliothèque Java conforme au standard JAAS (Java Authentication and Authorization Service).
Par defaut, un serveur Tomcat est configuré pour consulter un fichier de configuration
appelé tomcat-users.xml
. Ce fichier contient la déclaration des rôles
et des utilisateurs.
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users version="1.0"
xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd">
<role rolename="admin"/>
<user username="user" password="azerty" roles="admin"/>
</tomcat-users>
Configuration https dans Tomcat¶
Pour activer le connecteur https dans Tomcat, il faut disposer d’un certificat serveur. Java fournit un outil appelé keytool qui est dédié à la gestion des certificats et à leur stockage dans un fichier sécurisé appelé un keystore.
Pour disposer d’un certificat, il faut effectuer une demande de validation auprès d’un organisme certificateur. En effet, un certificat numérique doit toujours être signé numériquement par un tiers de confiance. Cependant, il est également possible de créer des certificats dits auto-signés, c’est-à-dire signés par l’émetteur. Attention, ce type de certificat ne doit pas être utilisé dans un environnement de production. Un navigateur Web se connectant en https sur un serveur présentant un certificat auto-signé, produit un message d’avertissement à l’utilisateur car cela constitue une faille de sécurité.
Pour des raisons de simplicité, nous allons utiliser pour ce chapitre une certificat auto-signé.
Vous pouvez récupérer un fichier keystore contenant un certificat auto-signé :
Ce fichier contient un certificat auto-signé nommé tomcat pour le domaine localhost. Le mot de passe qui protège le keystore est azerty.
Note
Il est possible de générer votre propre certificat auto-signé grâce à l’outil
keytool. Il s’agit d’un outil en ligne de commandes qui se trouve dans le
sous-répertoire bin
du répertoire d’installation du JDK. Pour créer
un certificat auto-signé, il faut utiliser la commande :
keytool -genkey -keystore [NOM FICHIER KEYSTORE] -alias tomcat -keyalg RSA -keysize 4096 -validity 365
Il faut maintenant configurer Tomcat en éditant le fichier de configuration
principal du serveur : server.xml
. Ce fichier se trouve dans le *
sous-répertoire conf
du répertoire d’installation de Tomcat.
Important
Dans Eclipse, la configuration de Tomcat se trouve dans le projet nommé Servers.
Recherchez la déclaration du connecteur http dans le fichier qui ressemble à ceci :
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
Ajoutez à la suite la déclaration du connecteur https :
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="selfsigned.keystore"
keyAlias="tomcat"
keystorePass="azerty" />
Avertissement
Faites attention à ce que l’attribut keystoreFile
indique bien le chemin
complet d’accès au fichier keystore contenant le certificat.
Exercice¶
Sécurisation d’une application Web
Sécurisez une application Web de manière à ce que l’application demande une authentification HTTP et soit accessible en https.
Astuce
Une fois connecté, les informations sur l’utilisateur (dont son login)
sont accessibles grâce à la méthode HttpServletRequest.getUserPrincipal.
Il est également possible d’y accéder dans une JSP puisque l’objet implicite
pageContext
permet d’accéder à l’objet HttpServletRequest :
${pageContext.request.userPrincipal.name}
Login à partir d’un formulaire Web¶
Si vous ne désirez pas utiliser l’authentification HTTP, il est possible de créer son propre formulaire de login et de préciser que la configuration de login doit se faire à partir d’un formulaire.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<security-constraint>
<web-resource-collection>
<web-resource-name>Zone privée</web-resource-name>
<url-pattern>/private/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/login-failed.html</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
</web-app>
|
Les balises <form-login-page>
et <form-error-page>
indiquent les ressources
Web à utiliser pour afficher le formulaire de login et la page d’erreur de
connexion. Il peut s’agir de n’importe quelle ressource : page HTML, JSP,
Servlet.
La page de login doit contenir un formulaire qui soumet des données vers j_security_check. Les paramètres soumis doivent être j_username et j_password.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form method="POST" action="j_security_check" accept-charset="latin-1">
<label>login : </label>
<input type="text" name="j_username"><br>
<label>mot de passe : </label>
<input type="password" name="j_password"><br>
<button type="submit">Connexion</button>
</form>
</body>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Échec login</title>
</head>
<body>
<div>Le login ou le mot de passe est invalide !</div>
<form method="POST" action="j_security_check">
<label>login : </label>
<input type="text" name="j_username"><br>
<label>mot de passe : </label>
<input type="text" name="j_password"><br>
<button type="submit">Connexion</button>
</form>
</body>
</html>
|