Usurpation d’identité utilisateur
Imaginez Sarah, une ingénieure support chez TechCorp, qui reçoit un ticket urgent d’Alex, un client qui ne peut pas accéder à une ressource critique. Pour diagnostiquer et résoudre efficacement le problème, Sarah doit voir exactement ce qu’Alex voit dans le système. C’est là que la fonctionnalité d’usurpation d’identité utilisateur de Logto devient précieuse.
L’usurpation d’identité utilisateur permet à des utilisateurs autorisés comme Sarah d’agir temporairement au nom d’autres utilisateurs comme Alex dans le système. Cette fonctionnalité puissante est inestimable pour le dépannage, l’assistance client et l’exécution de tâches administratives.
Comment ça fonctionne ?
Le processus d’usurpation implique trois étapes principales :
- Sarah demande l’usurpation via le serveur backend de TechCorp
- Le serveur de TechCorp obtient un jeton de sujet auprès du Management API de Logto
- L’application de Sarah échange ce jeton de sujet contre un jeton d’accès
Voyons comment Sarah peut utiliser cette fonctionnalité pour aider Alex.
Étape 1 : Demander l’usurpation
Tout d’abord, l’application de support de Sarah doit demander l’usurpation auprès du serveur backend de TechCorp.
Requête (application de Sarah vers le serveur de TechCorp)
POST /api/request-impersonation HTTP/1.1
Host: api.techcorp.com
Authorization: Bearer <Sarah's_access_token>
Content-Type: application/json
{
"userId": "alex123",
"reason": "Investigating resource access issue",
"ticketId": "TECH-1234"
}
Dans cette API, le backend doit effectuer des vérifications d’autorisation appropriées pour s’assurer que Sarah dispose des permissions nécessaires pour usurper Alex.
Étape 2 : Obtenir un jeton de sujet
Après avoir validé la demande de Sarah, le serveur de TechCorp appellera le Management API de Logto pour obtenir un jeton de sujet.
Requête (serveur de TechCorp vers le Management API de Logto)
POST /api/subject-tokens HTTP/1.1
Host: techcorp.logto.app
Authorization: Bearer <TechCorp_m2m_access_token>
Content-Type: application/json
{
"userId": "alex123",
"context": {
"ticketId": "TECH-1234",
"reason": "Resource access issue",
"supportEngineerId": "sarah789"
}
}
Réponse (Logto vers le serveur de TechCorp)
{
"subjectToken": "sub_7h32jf8sK3j2",
"expiresIn": 600
}
Le serveur de TechCorp doit ensuite retourner ce jeton de sujet à l’application de Sarah.
Réponse (serveur de TechCorp vers l’application de Sarah)
{
"subjectToken": "sub_7h32jf8sK3j2",
"expiresIn": 600
}
Étape 3 : Échanger le jeton de sujet contre un jeton d’accès
Avant d'utiliser la délégation d'échange de jeton, vous devez l'activer pour votre application :
- Allez dans Console > Applications et sélectionnez votre application.
- Dans les paramètres de l'application, trouvez la section "Échange de jeton".
- Activez l'option "Autoriser l'échange de jeton".
L'échange de jeton est désactivé par défaut pour des raisons de sécurité. Si vous ne l'activez pas, vous recevrez une erreur "l'échange de jeton n'est pas autorisé pour cette application".
À présent, l’application de Sarah échange ce jeton de sujet contre un jeton d’accès représentant Alex, en spécifiant la ressource où le jeton sera utilisé.
Requête (application de Sarah vers le point de terminaison de jeton Logto)
Pour les applications web traditionnelles ou les applications machine à machine avec secret d’application, incluez les identifiants dans l’en-tête Authorization :
POST /oidc/token HTTP/1.1
Host: techcorp.logto.app
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64(client_id:client_secret)>
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&scope=resource:read
&subject_token=alx_7h32jf8sK3j2
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&resource=https://api.techcorp.com/customer-data
Pour les applications monopage (SPA) ou les applications natives sans secret d’application, incluez client_id dans le corps de la requête :
POST /oidc/token HTTP/1.1
Host: techcorp.logto.app
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&client_id=techcorp_support_app
&scope=resource:read
&subject_token=alx_7h32jf8sK3j2
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&resource=https://api.techcorp.com/customer-data
Réponse (Logto vers l’application de Sarah)
{
"access_token": "eyJhbG...<truncated>",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "resource:read"
}
Le access_token retourné sera lié à la ressource spécifiée, garantissant qu’il ne peut être utilisé qu’avec l’API de données client de TechCorp.
Exemple d’utilisation
Voici comment Sarah pourrait utiliser cela dans une application de support Node.js :
interface ImpersonationResponse {
subjectToken: string;
expiresIn: number;
}
interface TokenExchangeResponse {
access_token: string;
issued_token_type: string;
token_type: string;
expires_in: number;
scope: string;
}
async function impersonateUser(
userId: string,
clientId: string,
ticketId: string,
resource: string,
clientSecret?: string // Requis pour les applications web traditionnelles ou machine à machine
): Promise<string> {
try {
// Étapes 1 & 2 : Demander l’usurpation et obtenir le jeton de sujet
const impersonationResponse = await fetch(
'https://api.techcorp.com/api/request-impersonation',
{
method: 'POST',
headers: {
Authorization: "Bearer <Sarah's_access_token>",
'Content-Type': 'application/json',
},
body: JSON.stringify({
userId,
reason: 'Investigating resource access issue',
ticketId,
}),
}
);
if (!impersonationResponse.ok) {
throw new Error(`Erreur HTTP. Statut : ${impersonationResponse.status}`);
}
const { subjectToken } = (await impersonationResponse.json()) as ImpersonationResponse;
// Étape 3 : Échanger le jeton de sujet contre un jeton d’accès
// Pour les applications web traditionnelles ou M2M, utiliser l’authentification Basic avec le secret client
// Pour les SPA ou applications natives, inclure client_id dans le corps de la requête
const headers: Record<string, string> = {
'Content-Type': 'application/x-www-form-urlencoded',
};
const tokenExchangeBody = new URLSearchParams({
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
scope: 'openid profile resource.read',
subject_token: subjectToken,
subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',
resource: resource,
});
if (clientSecret) {
// Client confidentiel : utiliser l’authentification Basic
headers['Authorization'] =
`Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`;
} else {
// Client public : inclure client_id dans le corps
tokenExchangeBody.append('client_id', clientId);
}
const tokenExchangeResponse = await fetch('https://techcorp.logto.app/oidc/token', {
method: 'POST',
headers,
body: tokenExchangeBody,
});
if (!tokenExchangeResponse.ok) {
throw new Error(`Erreur HTTP ! statut : ${tokenExchangeResponse.status}`);
}
const tokenData = (await tokenExchangeResponse.json()) as TokenExchangeResponse;
return tokenData.access_token;
} catch (error) {
console.error('Échec de l’usurpation :', error);
throw error;
}
}
// Sarah utilise cette fonction pour usurper Alex
async function performImpersonation(): Promise<void> {
try {
// Pour les applications web traditionnelles ou M2M, passer le secret client
const accessToken = await impersonateUser(
'alex123',
'techcorp_support_app',
'TECH-1234',
'https://api.techcorp.com/customer-data',
'your-client-secret' // Omettez ceci pour les SPA ou applications natives
);
console.log('Jeton d’accès d’usurpation pour Alex :', accessToken);
} catch (error) {
console.error('Échec de l’usurpation :', error);
}
}
// Exécuter l’usurpation
void performImpersonation();
- Le jeton de sujet est de courte durée et à usage unique.
- Le jeton d’accès d’usurpation ne s’accompagne pas d’un jeton de rafraîchissement (Refresh token). Sarah devra répéter ce processus si le jeton expire avant qu’elle ne résolve le problème d’Alex.
- Le serveur backend de TechCorp doit mettre en œuvre des vérifications d’autorisation appropriées pour s’assurer que seuls les membres du support autorisés comme Sarah peuvent demander une usurpation.
Revendication act
Lors de l’utilisation du flux d’échange de jetons pour l’usurpation, le jeton d’accès émis peut inclure une revendication supplémentaire act (acteur). Cette revendication représente l’identité de la "partie agissante" — dans notre exemple, Sarah, qui effectue l’usurpation.
Pour inclure la revendication act, l’application de Sarah doit fournir un actor_token dans la requête d’échange de jeton. Ce jeton doit être un jeton d’accès valide pour Sarah avec la portée openid. Voici comment l’inclure dans la requête d’échange de jeton :
Pour les applications web traditionnelles ou les applications machine à machine :
POST /oidc/token HTTP/1.1
Host: techcorp.logto.app
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64(client_id:client_secret)>
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&scope=resource:read
&subject_token=alx_7h32jf8sK3j2
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&actor_token=sarah_access_token
&actor_token_type=urn:ietf:params:oauth:token-type:access_token
&resource=https://api.techcorp.com/customer-data
Pour les SPA ou applications natives, incluez client_id dans le corps de la requête :
POST /oidc/token HTTP/1.1
Host: techcorp.logto.app
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&client_id=techcorp_support_app
&scope=resource:read
&subject_token=alx_7h32jf8sK3j2
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&actor_token=sarah_access_token
&actor_token_type=urn:ietf:params:oauth:token-type:access_token
&resource=https://api.techcorp.com/customer-data
Si un actor_token est fourni, le jeton d’accès résultant contiendra une revendication act comme ceci :
{
"aud": "https://api.techcorp.com",
"iss": "https://techcorp.logto.app",
"exp": 1443904177,
"sub": "alex123",
"act": {
"sub": "sarah789"
}
}
Cette revendication act indique clairement que Sarah (sarah789) agit au nom d’Alex (alex123). La revendication act peut être utile pour l’audit et le suivi des actions d’usurpation.
Personnalisation des revendications de jeton
Logto vous permet de personnaliser les revendications de jeton pour les jetons d’usurpation. Cela peut être utile pour ajouter du contexte ou des métadonnées supplémentaires au processus d’usurpation, comme la raison de l’usurpation ou le ticket de support associé.
Lorsque le serveur de TechCorp demande un jeton de sujet au Management API de Logto, il peut inclure un objet context :
{
"userId": "alex123",
"context": {
"ticketId": "TECH-1234",
"reason": "Resource access issue",
"supportEngineerId": "sarah789"
}
}
Ce contexte peut ensuite être utilisé dans une fonction getCustomJwtClaims() pour ajouter des revendications spécifiques au jeton d’accès final. Voici un exemple d’implémentation :
const getCustomJwtClaims = async ({ token, context, environmentVariables }) => {
if (context.grant?.type === 'urn:ietf:params:oauth:grant-type:token-exchange') {
const { ticketId, reason, supportEngineerId } = context.grant.subjectTokenContext;
return {
impersonation_context: {
ticket_id: ticketId,
reason: reason,
support_engineer: supportEngineerId,
},
};
}
return {};
};
Le jeton d’accès résultant que Sarah reçoit pourrait ressembler à ceci :
{
"sub": "alex123",
"aud": "https://api.techcorp.com/customer-data",
"impersonation_context": {
"ticket_id": "TECH-1234",
"reason": "Resource access issue",
"support_engineer": "sarah789"
}
// ... autres revendications standard
}
En personnalisant ainsi les revendications des jetons d’accès, TechCorp peut inclure des informations précieuses sur le contexte d’usurpation, ce qui facilite l’audit et la compréhension des activités d’usurpation dans leur système.
Soyez prudent lors de l’ajout de revendications personnalisées à vos jetons. Évitez d’inclure des informations sensibles qui pourraient présenter des risques de sécurité si le jeton est intercepté ou divulgué. Les JWT sont signés mais non chiffrés, donc les revendications sont visibles par toute personne ayant accès au jeton.
Ressources associées
Qu’est-ce que l’usurpation d’identité en cybersécurité et gestion des identités ? Comment les agents IA peuvent-ils l’utiliser ?