IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Boot Java Discussion :

J'ai pu modifier un jeton entre deux requêtes ! Comment cela est-il possible ?


Sujet :

Spring Boot Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Points : 65
    Points
    65
    Par défaut J'ai pu modifier un jeton entre deux requêtes ! Comment cela est-il possible ?
    Bonjour,
    Pour un support de cours j'ai voulu montrer que la gestion de la sécurité via un token était très sûre et pour en donner la preuve, j'ai proposé de vérifier que l'on ne pouvait pas modifier un jeton.
    Sauf que si j'ai pu modifier un jeton entre deux appels ! Comment cela est-il possible ?
    D'abord un exemple :
    Le token après un login :
    Code JSON : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
    "id": 4,
    "email": "jean.bon@monserveur.fr",
    "password": "",
    "username": "jean.bon",
    "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqZWFuLmJvbiIsImlhdCI6MTY0MzM4MDE1NSwiZXhwIjoxNjQzNDY2NTU1fQ.JUSTGCfWS9MrbBzkyEboaxHyZcBVwzC_TAH8LRx76wJmKZ9drF1cz51EWfKs9rd4GfxqwpE33-_5e0soylfA6w",
    "roles": [
        "USER"
    ]
    }
    Résultat de la requête employee/employee avec ce token :
    [{"id":1,"name":"KING","job":{"id":1,"jobname":"President"},"managerId":null,"hiredate":"1981-11-17","salary":5000.00,"department":{"id":1,"dname":"Accounting","location":"NEW YORK"}},{"id":2,"name":"JONES","job":{"id":2,"jobname":"Manager"},"managerId":1,"hiredate":"1981-04-02","salary":3000.00,"department":{"id":1,"dname":"Accounting","location":"NEW YORK"}},...

    Token modifié : le dernier caractère (w) replacé par un x :

    "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqZWFuLmJvbiIsImlhdCI6MTY0MzM4MDE1NSwiZXhwIjoxNjQzNDY2NTU1fQ.JUSTGCfWS9MrbBzkyEboaxHyZcBVwzC_TAH8LRx76wJmKZ9drF1cz51EWfKs9rd4GfxqwpE33-_5e0soylfA6x",

    Résultat de la requête employee/employee :

    [{"id":1,"name":"KING","job":{"id":1,"jobname":"President"},"managerId":null,"hiredate":"1981-11-17","salary":5000.00,"department":{"id":1,"dname":"Accounting","location":"NEW YORK"}},{"id":2,"name":"JONES","job":{"id":2,"jobname":"Manager"},"managerId":1,"hiredate":"1981-04-02","salary":3000.00,"department":{"id":1,"dname":"Accounting","location":"NEW YORK"}},...

    A noter que si je remplace le w par un caractère avant le w, par exemple un a ou b, cela ne fonctionne pas !
    Maintenant le contexte technique :

    La clé : key= AzertyuiopQsdfgjklmWxcvbn1234567890!=
    Expiration : expiration= 86400000

    Générateur de jeton :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public String generateToken(Authentication authentication) {
        UserDetailsImpl userDetailsImpl = (UserDetailsImpl) authentication.getPrincipal();
        JwtBuilder jwtBuilder = Jwts.builder();
        jwtBuilder.setSubject((userDetailsImpl.getUsername()));
        jwtBuilder.setIssuedAt(new Date());
        jwtBuilder.setExpiration(new Date((new Date()).getTime() + expiration));
        jwtBuilder.signWith(SignatureAlgorithm.HS512, key);
        String token = jwtBuilder.compact();
        return token;
    }
    Validateur de jeton :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public boolean validateToken(String token) {
        Boolean ret = false;
        try {
            JwtParser jwtParser = Jwts.parser();
            jwtParser.setSigningKey(key);
            jwtParser.parseClaimsJws(token);
            ret= true;
        } catch (Exception e) {
            ret = false;
        }
        return ret;
    }
    Extraction du username :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public String getUserNameFromToken(String token) {
        JwtParser jwtParser = Jwts.parser();
        jwtParser.setSigningKey(key);
        Jws<Claims> jws = jwtParser.parseClaimsJws(token);
        Claims claims = jws.getBody();
        String userName = claims.getSubject();
        return userName;
    }

  2. #2
    Membre averti
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2020
    Messages
    326
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mai 2020
    Messages : 326
    Points : 439
    Points
    439
    Par défaut
    Bonjour,

    Modifier le token en soit n'est pas impossible. Par contre il ne devrait plus être valide.

    Ce qui est étonnant c'est que sur https://jwt.io/ la signature n'est pas correcte. Je vois aussi que le token (partie signature) est raccourcie pour être valide.

    Malheureusement je ne connais pas la librairie que vous utilisez mais il y à peut-être une erreur dans son utilisation ?

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Points : 65
    Points
    65
    Par défaut
    Citation Envoyé par gervais.b Voir le message
    Bonjour,

    Modifier le token en soit n'est pas impossible. Par contre il ne devrait plus être valide.

    Ce qui est étonnant c'est que sur https://jwt.io/ la signature n'est pas correcte. Je vois aussi que le token (partie signature) est raccourcie pour être valide.

    Malheureusement je ne connais pas la librairie que vous utilisez mais il y à peut-être une erreur dans son utilisation ?
    Bonsoir,
    Merci d'avoir répondu, je commençais à désespérer de trouver une solution :-(
    Ceci dit ce n'est pas fait !
    J'utilise cette bibliothèque :
    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.9.1</version>
            </dependency>
    Tout le code est dans ma question et je ne vois pas où pourrait se situer l'erreur.
    Merci d'avance pour votre aide.

  4. #4
    Membre averti
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2020
    Messages
    326
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mai 2020
    Messages : 326
    Points : 439
    Points
    439
    Par défaut
    Attention : Je ne suis pas expert en crypto, je peux raconter des bêtises sur le fonctionnement.


    Dans le signatures, il y à des caractères de padding qui servent simplement à remplir la chaine jusqu'a à un taille définie. Par exemple:
    La signature doit faire 10 caractères mais le contenu à signer est tellement petit que 7 caratères suffisent à la signer. Alors on complète par des choses insignifiantes:
    On à 10 caractères à remplir : [_ _ _ _ _ _ _ _ _ _]
    La signature n'en fait que 7 : [1 2 3 4 5 6 7 _ _ _]
    On complète avec du bruit : [1 2 3 4 5 6 7 a a a]

    Les caractères que vous modifiez font certainement partie de ce padding. Ce n'est pas un problème car le payload de votre token est inchangé. Si vous vouliez vous faire passer pour quelqu'un d'autre alors la signature serait incorrecte avec ou sans ce caractère qui est en quelque sorte ignoré lors de la vérification.

    (Pour être complet, nous avons eu quelques échanges privés avec Alain. Mais il n'ont pas de véritable intérêt pour cette réponse)

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    169
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 169
    Points : 65
    Points
    65
    Par défaut
    Citation Envoyé par gervais.b Voir le message
    Attention : Je ne suis pas expert en crypto, je peux raconter des bêtises sur le fonctionnement.


    Dans le signatures, il y à des caractères de padding qui servent simplement à remplir la chaine jusqu'a à un taille définie. Par exemple:
    La signature doit faire 10 caractères mais le contenu à signer est tellement petit que 7 caratères suffisent à la signer. Alors on complète par des choses insignifiantes:
    On à 10 caractères à remplir : [_ _ _ _ _ _ _ _ _ _]
    La signature n'en fait que 7 : [1 2 3 4 5 6 7 _ _ _]
    On complète avec du bruit : [1 2 3 4 5 6 7 a a a]

    Les caractères que vous modifiez font certainement partie de ce padding. Ce n'est pas un problème car le payload de votre token est inchangé. Si vous vouliez vous faire passer pour quelqu'un d'autre alors la signature serait incorrecte avec ou sans ce caractère qui est en quelque sorte ignoré lors de la vérification.

    (Pour être complet, nous avons eu quelques échanges privés avec Alain. Mais il n'ont pas de véritable intérêt pour cette réponse)
    Bonjour,
    Certes, mais cela n'explique pas pourquoi si la signature se termine par exemple par un H, je peux substituer ce H par une lettre postérieure I J K... mais pas par une lettre antérieure E F G !
    Dans un message privé avec gervais.b, je disais que j'avais posté une demande auprès de plusieurs commiters de la bibliothèque io.jsonwebtoken, mais que j'avais des doutes quant à une potentielle réponse à un "petit frenchie" ! Et bien j'ai été mauvaise langue, voici la réponse qui m'a été faite par Brian Demers :
    My guess is it's related to base64 encoding scheme. For example, if you take the "modified" Base64 encoded string, and then decode and re-encode it, you end up with the expected value.
    Slightly ugly test code to follow:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
            String stringKey = "JUSTGCfWS9MrbBzkyEboaxHyZcBVwzC_TAH8LRx76wJmKZ9drF1cz51EWfKs9rd4GfxqwpE33-_5e0soylfA6x";
            byte[] bytes = Base64.getUrlDecoder().decode(stringKey);
            System.out.println("Original Key: " + stringKey);
            String stringKey2 = Base64.getUrlEncoder().encodeToString(bytes);
            byte[] bytes2 = Base64.getUrlDecoder().decode(stringKey2);
            System.out.println("Re-encoded:   " + stringKey2);
            assertThat(bytes, is(bytes2));
    This test passes and outputs the following (the '=' are just padding):

    Original Key: JUSTGCfWS9MrbBzkyEboaxHyZcBVwzC_TAH8LRx76wJmKZ9drF1cz51EWfKs9rd4GfxqwpE33-_5e0soylfA6x
    Re-encoded: JUSTGCfWS9MrbBzkyEboaxHyZcBVwzC_TAH8LRx76wJmKZ9drF1cz51EWfKs9rd4GfxqwpE33-_5e0soylfA6w==

    You can get similar results in this test if you change the last letter to `h`:

    Original Key: JUSTGCfWS9MrbBzkyEboaxHyZcBVwzC_TAH8LRx76wJmKZ9drF1cz51EWfKs9rd4GfxqwpE33-_5e0soylfA6h
    Re-encoded: JUSTGCfWS9MrbBzkyEboaxHyZcBVwzC_TAH8LRx76wJmKZ9drF1cz51EWfKs9rd4GfxqwpE33-_5e0soylfA6g==

    TL;DR The string decodes to the same original bytes.

    Je ne suis pas certain que cela réponde vraiment à ma question, mais au moins j'ai peut-être un début de piste ;-)
    Tout ça n'est pas très grave car il semblerait que ça n'empêche pas les token de circuler sur le web, mais quand même j'aurais bien aimé comprendre ! Sans doute une déformation professionnelle de la part d'un enseignant (à la retraite, mais encore actif) qui cherche un peu trop à comprendre avant que de faire :-)
    Alain

Discussions similaires

  1. Différence entre deux "requêtes"
    Par zaventem dans le forum Développement
    Réponses: 3
    Dernier message: 16/03/2009, 12h01
  2. [Requête]Problèmes de nombre d'enregistrements entre deux requêtes
    Par Paul Gasser dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 23/03/2007, 12h20
  3. Addition entre deux requêtes
    Par tazmania dans le forum Langage SQL
    Réponses: 4
    Dernier message: 17/10/2006, 17h17
  4. Différence entre deux requêtes
    Par viny dans le forum Langage SQL
    Réponses: 7
    Dernier message: 03/10/2006, 16h28
  5. Test d'égalité entre deux algorithmes, ça existe, est-ce faisable ?
    Par davcha dans le forum Algorithmes et structures de données
    Réponses: 16
    Dernier message: 25/04/2006, 18h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo