Sécurité et vérification

Vous devez respecter les règles de sécurité décrites par OAuth et OpenID Connect.

 

Faille dans l'autorisation par code

Il existe une faille dans la cinématique Authorization code flow qui permet à une personne malveillante de récupérer les identifiants d'un utilisateur. Cette faille a affecté des sites web connus (Pinterest, SoundCloud, Digg...) qui n'ont pas correctement implémenté cette cinématique.

Il existe un moyen d'empêcher cela grâce aux paramètres state dans OAuth 2.0 et nonce dans OpenID Connect. Si votre application envoie ces paramètres lors de la demande d'authentification de l'utilisateur, ils seront retournés par Pôle Emploi Access Management et vous pourrez les comparer.

Vous devez obligatoirement utiliser ces deux paramètres :

Paramètre Description
State Retourné en réponse à la demande d'authentification de l'utilisateur
Nonce

Retourné en réponse à la demande de génération d'un access token
Il est également contenu dans l'id token et doit être vérifié en même temps que la vérification de l'id token

 

Vérification des tokens

Définition de l'id token

Un id token est un jeton au format JWT (JSON Web Token) qui contient des informations sur l'authentification d'un utilisateur final. Un jeton JWT est une façon de représenter des claims pour les transférer entre deux parties dans un format compact et compatible URI. Un claim est simplement une paire clé/valeur contenant des informations sur un utilisateur ou sur le contexte d'authentification.

 

L'id token est composé de trois parties (entête, claims et signature) séparées par des . (point) et encodées en base64url :

<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>

 

  1. L'entête est un objet JSON doté des propriétés définies par les normes JWS et JWE suivant l'encryptage ou la signature du jeton. Il contient des métadonnées ainsi que le nom des algorithmes et clés nécessaires à ces algorithmes.
     
  2. Les claims sont un ensemble de clés/valeurs dont les noms sont normalisés dans la norme OpenID Connect. Ils sont sérialisés en JSON.
     
  3. La signature correspond à la concaténation de l'entête et des claims chiffrée avec la clé privée. Elle est utilisée pour vérifier que l’expéditeur du jeton JWT est bien celui qu’il prétend être et de veiller à ce que le message n’ait pas été modifié en cours de route.

 

Exemple d'id token :

"id_token":"eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAidG9rZW5OY
    W1lIjogImlkX3Rva2VuIiwgImF6cCI6ICJlbXBsb2lzdG9yZS1lbXBsb3lldXItYWdlbnQ
    iLCAic3ViIjogIjIxMjM3Nzc1MjEiLCAiYXRfaGFzaCI6ICJIOVFyVnYwcTl5QjRsdzV3Z
    i1IUDdnIiwgImlzcyI6ICJodHRwczovL3NvMDE3LXBvYW0tYWphczc0My5zaWkyNC5wb2x
    lLWVtcGxvaS5pbnRyYToxNzQzMC9jb25uZXhpb24vb2F1dGgyL2luZGl2aWR1IiwgIm9yZ
    y5mb3JnZXJvY2sub3BlbmlkY29ubmVjdC5vcHMiOiAiZTA2MDQ2M2YtYzEzNi00N2M3LTg
    1MmUtYmM0MDIxMTc0ZGRmIiwgImlhdCI6IDE0ODU4NjA5OTQsICJhdXRoX3RpbWUiOiAxN
    Dg1ODU5MjI0LCAiZXhwIjogMTQ4NTg2NDU5NCwgInRva2VuVHlwZSI6ICJKV1RUb2tlbiI
    sICJhdWRpdFRyYWNraW5nSWQiOiAiZWE5MTQ3NWQtZDRhZS00MDQxLWE4NjUtMjI1YjZiY
    TEzYTdiLTc2NTgiLCAibm9uY2UiOiAiZDFjN2M5OWM2ZTJlN2IzMTFmNTFkZDlkMTkxNjF
    hNTgzMjYyNWZiMjFmMzUxMzFmYmE2ZGE2MjUxM2YwYzA5OSIsICJyZWFsbSI6ICIvaW5ka
    XZpZHUiLCAiYXVkIjogImVtcGxvaXN0b3JlLWVtcGxveWV1ci1hZ2VudCIsICJjX2hhc2g
    iOiAidmlqdnZVLXJQcHpXUkdtMVRZbm1GZyIgfQ._a2BNpM7dLXlWZUe9oJnbvalpvrUjo
    VFnznV2OvgoZc"

 

Exemple d'id token décodé :

Partie Valeur brute Valeur base64 décodée
Entête (1) eyAidHlwIjogIkpXVCIsICJhb
GciOiAiSFMyNTYiIH0
{
  "typ": "JWT",
  "alg": "HS256"
}
Claims (2) eyAidG9rZW5OYW1lIjogImlkX
3Rva2VuIiwgImF6cCI6ICJlbX
Bsb2lzdG9yZS1lbXBsb3lldXI
tYWdlbnQiLCAic3ViIjogIjIx
MjM3Nzc1MjEiLCAiYXRfaGFza
CI6ICJIOVFyVnYwcTl5QjRsdz
V3Zi1IUDdnIiwgImlzcyI6ICJ
odHRwczovL3NvMDE3LXBvYW0t
YWphczc0My5zaWkyNC5wb2xlL
WVtcGxvaS5pbnRyYToxNzQzMC
9jb25uZXhpb24vb2F1dGgyL2l
uZGl2aWR1IiwgIm9yZy5mb3Jn
ZXJvY2sub3BlbmlkY29ubmVjd
C5vcHMiOiAiZTA2MDQ2M2YtYz
EzNi00N2M3LTg1MmUtYmM0MDI
xMTc0ZGRmIiwgImlhdCI6IDE0
ODU4NjA5OTQsICJhdXRoX3Rpb
WUiOiAxNDg1ODU5MjI0LCAiZX
hwIjogMTQ4NTg2NDU5NCwgInR
va2VuVHlwZSI6ICJKV1RUb2tl
biIsICJhdWRpdFRyYWNraW5nS
WQiOiAiZWE5MTQ3NWQtZDRhZS
00MDQxLWE4NjUtMjI1YjZiYTE
zYTdiLTc2NTgiLCAibm9uY2Ui
OiAiZDFjN2M5OWM2ZTJlN2IzM
TFmNTFkZDlkMTkxNjFhNTgzMj
YyNWZiMjFmMzUxMzFmYmE2ZGE
2MjUxM2YwYzA5OSIsICJyZWFs
bSI6ICIvaW5kaXZpZHUiLCAiY
XVkIjogImVtcGxvaXN0b3JlLW
VtcGxveWV1ci1hZ2VudCIsICJ
jX2hhc2giOiAidmlqdnZVLXJQ
cHpXUkdtMVRZbm1GZyIgfQ
{
  "tokenName": "id_token",
  "tokenType": "JWTToken",
  "azp": "[identifiant client]",
  "aud": "[identifiant client]",
  "iss": "https://authentification-candidat.pole-emploi.fr/connexion/oauth2/",
  "realm": "/individu",
  "nonce": "d1c7c99c6e2e7b311
f51dd9d19161a5832625fb21f3
5131fba6da62513f0c099",
  "iat": 1485860994,
  "exp": 1485864594,
  "auth_time": 1485859224,
  "c_hash": "vijvvU-rPpzWRGm1TYnmFg",
  "at_hash": "H9QrVv0q9yB4lw5wf-HP7g",
  "sub": "2123777521",
  "auditTrackingId": "ea91475d-d4ae-4041-a865-225b6ba13a7b-7658",
  "org.forgerock.openidconnect.ops": "e060463f-c136-47c7-852e-bc4021174ddf"
}
Signature (3) _a2BNpM7dLXlWZUe9oJnbvalp
vrUjoVFnznV2OvgoZc
Sans objet

 

Exemple de claims :

Clé Valeur
tokenName Nom du token
tokenType Type du token
azp Votre identifiant client
aud Votre identifiant client
iss URL de Pôle Emploi Access Management
realm Royaume de la population d'utilisateurs
nonce Identique à celui fourni lors de l'appel du endpoint d'authentification
iat Date de génération de l’id token
exp Date d’expiration de l’id token
auth_time Date d'authentification de l'individu
c_hash Sans objet
at_hash Permet la vérification de l'access token
sub Identifiant unique de l'individu
auditTrackingId Sans objet
org.forgerock.openidconnect.ops Sans objet

 

Vérification de l'id token

La vérification se fait en suivant ces étapes :

  1. Si l'id token est chiffré, le déchiffrer
  2. Vérifier que l'issuer présent dans le claim iss est bien l'URL de Pôle Emploi Access Management
  3. Vérifier que votre identifiant client est bien présent dans le claim aud
  4. Si un claim azp est présent, vérifier que sa valeur correspond bien à votre identifiant client
  5. (Facultatif) Vérifier la validité de la signature électronique de l'id token en vérifiant que la date courante est :
    • antérieure à la date d'expiration de l'id token présent dans le claim exp
    • proche (≤ 25 secondes) de la date de génération de l'id token présent dans le claim iat et de la date d'authentification de l'utilisateur présent dans le claim auth_time (ceci implique une synchronisation de l'horloge de votre application sur l'horloge atomique)
  6. Vérifier que le claim realm est identique à celui positionné par votre application lors de la requête de demande d'authentification de l'utilisateur
  7. Vérifier que le claim nonce est identique à celui généré par votre application lors de la requête de demande d'authentification de l'utilisateur (paramètre permettant de s'assurer de la provenance des échanges : anti-faille CSRF)

 
Afin de vérifier que l'id token a bien été délivré pour votre application (et qu'il n'y a pas eu d'attaque Man in the middle), celle-ci peut vérifier la signature du jeton ayant pour format :

signature = sign('<base64-encoded header>.<base64-encoded claims>')

 

La vérification de la signature dépend de l'algorithme utilisé. Si votre application souhaite vérifier et valider l'id token qu'elle reçoit de Pôle Emploi Access Management, elle doit récupérer la clé publique de signature dans le détail du endpoint jwk_uri.

 

Vérification de l'access token

La vérification se fait en suivant ces étapes :

  1. Faire un hash SHA256 de l'access token et ne garder que les 128 bits de gauche sur la valeur obtenue (32 octets)
  2. Convertir la valeur hexadécimale des 128 bits de gauche en base64
  3. Supprimer les éventuels = (égal) ou == obtenus en fin de chaine
  4. Remplacer les + (plus) par des – (moins) et les / (slash) par des _ (underline)
  5. Comparer la valeur obtenue au claim at_hash, les valeurs devant être identiques

 

Exemple :

  1. Avec l'acces token 8eb5020b-0b84-41f3-8174-6f7523805bf3, le hash obtenu est 1fd42b56fd2af72078970e707fe1cfee
  2. En base64, on obtient H9QrVv0q9yB4lw5wf+HP7g==
  3. Après suppression des caractères indiqués, on obtient H9QrVv0q9yB4lw5wf+HP7g
  4. Après remplacement des caractères indiqués, on obtient H9QrVv0q9yB4lw5wf-HP7g

 

Vous pouvez aussi remplacer les étapes 2 à 4 en convertissant directement la valeur hexadécimale des 128 bits de gauche en base64url.

La RFC 4648 prévoit une alternative pour un encodage compatible avec les noms de fichiers et les URI. En effet, les caractères 62 (plus) et 63 (slash) peuvent poser problème avec certains systèmes de fichiers et dans les URI. La solution consiste alors à remplacer ces caractères respectivement par un - (moins) et un _ (underline). Le caractère de complément reste le = (égal) mais il peut être ignoré.

Ce système est par exemple utilisé pour la réduction d'URL :

Valeur Codage         Valeur Codage         Valeur Codage         Valeur Codage
 0 000000 A           17 010001 R           34 100010 i           51 110011 z
 1 000001 B           18 010010 S           35 100011 j           52 110100 0
 2 000010 C           19 010011 T           36 100100 k           53 110101 1
 3 000011 D           20 010100 U           37 100101 l           54 110110 2
 4 000100 E           21 010101 V           38 100110 m           55 110111 3
 5 000101 F           22 010110 W           39 100111 n           56 111000 4
 6 000110 G           23 010111 X           40 101000 o           57 111001 5
 7 000111 H           24 011000 Y           41 101001 p           58 111010 6
 8 001000 I           25 011001 Z           42 101010 q           59 111011 7
 9 001001 J           26 011010 a           43 101011 r           60 111100 8
10 001010 K           27 011011 b           44 101100 s           61 111101 9
11 001011 L           28 011100 c           45 101101 t           62 111110 - (moins)
12 001100 M           29 011101 d           46 101110 u           63 111111 _ (souligné)
13 001101 N           30 011110 e           47 101111 v
14 001110 O           31 011111 f           48 110000 w        (complément) =
15 001111 P           32 100000 g           49 110001 x
16 010000 Q           33 100001 h           50 110010 y

 

Dans cette version d'encodage, les / (slash) sont remplacés par des _ (underline) et les + (plus) par des - (moins).