Fork me on GitHub

Bibliothèque SignRequest

Introduction

L'objet de cette bibliothèque est d'offrir un certain nombre d'outils et d'interfaces pour transmettre avec les requêtes HTTP des signatures numériques afin de garantir un certain niveau de sécurité.

Sécurité apportée par une signature

La sécurité apportée par une signature associée àune requete HTTP est très utile notamment dans le cadre de webservice REST où il n'y a pas de notion de session ( Mode stateless - sans état).

Le principe de la signature est de réaliser coté client un condensat (hash) d'un certain d'éléments variables de la requête (paramètres), d'un timestamp (pour limiter la validité de la signature dans le temps) et d'une clé secrète (connue que du client et du serveur). Ce condensat est obtenu à l'aide d'un algorithme de hashage (SHA-1, SHA-256, ...) et constitue la signature proprement dite de la requête. Elle se présente sous la forme d'une chaîne de caractères représentant un nombre sous forme héxadécimale.

La signature est transmise au serveur, qui devra reconstituer un condensat de son coté avec sa clé secrète. Si la signature est correctement reconstituée, la requête est valide, sinon elle refusée avec un code retour HTTP 401.

Voici ce que la signature apporte en terme de sécurité :

  • Une requête HTTP ou un appel de WebService ne peut être exécuté par un client qui ne possède pas la clé secrète
  • Si l'option de contrôle du Timestamp est activée, la requête aura une durée de vie limitée dans le temps. Il ne sera pas possible de rejouer la requête dans ce délai.
  • Valider l'intégrité des paramètres transmis (si ils font partie de la signature).

Voici ce que la signature n'apporte pas en terme de sécurité :

  • La confidentialité des données transmises. Celle-ci peut être obtenue par cryptage de la transmission par HTTPS
  • La possibilité de rejouer exactementla même requête dans un temps limité.
  • La signature simple n'est pas liée à un utilisateur donc ne permet pas la gestion de droits d'accès. Pour valider une signature par utilisateur, il est nécessaire de s'appuyer sur un serveur d'identités (Identity Provider) faisant appel à des protocoles tels que OAuth.

En résumé, la sécurité offerte par ce mécanisme de signature correspond bien à un besoin de fonctionnement sans session typiquement les Webservices REST. Il convient bien à la sécurisation de requêtes entre deux serveurs où provenant d'une population très faible d'utilisateurs (confidentialité du secret partagé) ou n'ayant pas accès à la clé secrète.

Afin d'assurer la confidentialité des données, le transfert des données doit être réalisé en HTTPS.

Outils apportés par SignRequest

API RequestAuthenticator

L'API RequestAuthenticator : définit un authentificateur de requete HTTP.

Le même composant peut être utilisé coté client pour signer une requête et coté serveur pour valider l'authentification. Voici l'interface et ses deux méthodes à implémenter :

    /**
     * Check the Authentication of a request
     * @param request The HTTP request
     * @return true if authenticated, otherwise false
     */
    boolean isRequestAuthenticated( HttpServletRequest request );

    /**
     * Authenticate a request
     * @param method The HTTP method to authenticate
     * @param elements List of elements to include in the signature
     */
    void authenticateRequest( HttpMethodBase method, List<String> elements );
                        
                    

Cette interface offre de nombreuses possibilités d'implémentations. Une bonne pratique consiste à injecter via un contexte Spring l'implémentation souhaitée.
La bibliothèque SignRequest propose plusieurs implémentations :

  • NoSecurityAuthenticator : pas de contrôle de l'authentification
  • HeaderHashAuthenticator : Signature passée dans un header de la requête HTTP
  • RequestHashAuthenticator : Signature passée dans un header de la requête HTTP

RequestHashAuthenticator et HeaderHashAuthenticator

Ces authenticators doivent être configurés à l'aide de plusieurs paramètres :

  • le service de hachage. La librairie SignRequest fournit une API de HashService et une implémentation utilisant l'algorithme SHA-1.
  • la clé privée correspondant au secret partagé entre le client et le serveur
  • la liste des paramètres de la requête qui sont utilisés pour composer la signature
  • la durée de validité de la signature en secondes. La valeur 0 indique que la durée n'est pas contrôlée.

Configuration d'un RequestAuthenticator dans le plugin REST

La sécurisation de l'ensemble des requêtes peut se faire au niveau du plugin REST en injectant via le context Spring un authenticator.

Par défaut, le plugin REST utilise l'implémentation NoSecurityRequestAuthenticator qui autorise l'ensemble des requêtes. L'exemple ci-dessous montre une configuration utilisant le HeaderHashRequestAuthenticator et son paramètrage spécifique.

<bean id="rest.hashService" class="fr.paris.lutece.util.signrequest.security.Sha1HashService" /> <bean id="rest.requestAuthenticator" class="fr.paris.lutece.util.signrequest.HeaderHashAuthenticator" > <property name="hashService" ref="rest.hashService" /> <property name="signatureElements" > <list> <value>key</value> </list> </property> <property name="privateKey"> <value>change me</value> </property> <property name="validityTimePeriod"> <value>0</value> </property> </bean>

API HashService

Cette API propose une fonction de hachage dont voici l'interface :

    /**
     * Create a Hash string from a given source
     * @param strSource The source
     * @return The Hash
     */
    String getHash( String strSource );
        
        

La bibliothèque SignRequest propose l'implémentation SHA-1.

Filtres de servlet

La bibliothèque SignRequest propose également des filtres de Servlet qui peuvent être utilisés par les plugins de manière à valider les requêtes coté serveur.
Ils sont basés sur les authenticator fournis avec la bibliothèque.
Voici un exemple de filtre ajouté dans le fichier XML d'un plugin :

<filters>
       <filter>
           <filter-name>myresourcesecurity</filter-name>
           <url-pattern>/rest/myresource/*</url-pattern>
           <filter-class>fr.paris.lutece.util.signrequest.servlet.HeaderHashRequestFilter</filter-class>

           <init-param>
               <param-name>elementsSignature</param-name>
               <param-value>id-resource,name,description</param-value>
           </init-param>

           <init-param>
               <param-name>validityTimePeriod</param-name>
               <param-value>0</param-value>
           </init-param>

           <init-param>
               <param-name>privateKey</param-name>
               <param-value>change me</param-value>
           </init-param>
       </filter>
   </filters>