☁️Entra IDApplicationsPermissionsIdentity

Permessi Graph API Delegati Versus Applicazione Entra Minimo Privilegio: il Modello di Consenso che la Maggior Parte dei Tenant Interpreta al Contrario

I permessi Graph delegati non sono quelli sicuri. Una concessione AllPrincipals a livello di tenant pre-autorizza un'applicazione contro ogni utente della directory — e vive in una collezione che le revisioni dei ruoli applicativi non leggono mai.

Younes AZABARDi Younes AZABAR13 min di lettura
Permessi Graph API Delegati Versus Applicazione Entra Minimo Privilegio: il Modello di Consenso che la Maggior Parte dei Tenant Interpreta al Contrario

Ogni tenant finisce per dover rispondere alla domanda sui permessi Graph API delegati versus applicazione Entra minimo privilegio: quale dei due modelli di consenso è davvero più sicuro, e come si concede a un'applicazione il minimo di cui ha bisogno senza romperla? La maggior parte dei team risponde per istinto — i permessi delegati «vengono eseguiti come un utente», quindi sembrano limitati; i permessi applicativi «vengono eseguiti come l'applicazione», quindi sembrano pericolosi. Quell'istinto ha ragione a metà, e la metà in cui sbaglia è quella che nessuno audita.

Il permesso che dà discretamente a un'applicazione un punto d'appoggio in ogni casella di posta del tenant non è necessariamente un permesso applicativo. Può essere un permesso delegato che un amministratore ha concesso a nome dell'intera organizzazione — e quella concessione vive in una collezione di oggetti diversa da quella degli app role, quindi una revisione dei permessi applicativi non la rileva mai.

Permessi Graph API Delegati Versus Applicazione Entra Minimo Privilegio, Definizione

La piattaforma di identità di Microsoft documenta due scenari di accesso, e la distinzione riguarda chi agisce come l'applicazione, non quanto danno può causare.

L'accesso delegato significa che un utente ha eseguito l'accesso e l'applicazione client accede alla risorsa per suo conto. Microsoft è esplicita sul limite: «The application isn't able to access anything the signed in user couldn't access.» Un'applicazione con il permesso delegato Files.Read.All «is only able to read files that the user can personally access.» I permessi delegati sono chiamati anche scope, e l'oggetto di concessione risultante è un oAuth2PermissionGrant.

L'accesso applicativo (app-only) significa che l'applicazione agisce da sola, senza alcun utente collegato — daemon, backup, automazione. Qui il limite è la risorsa stessa: un'applicazione con il permesso applicativo Microsoft Graph Files.Read.All «is able to read any file in the tenant using Microsoft Graph.» I permessi applicativi sono app role, l'oggetto di concessione è un appRoleAssignment, e secondo la stessa tabella comparativa di Microsoft, solo un admin può concederli.

Permessi delegatiPermessi applicativi
Contesto di accessoPer conto di un utente collegatoSenza utente
Chi può concedereGli utenti per i propri dati; gli admin per tutti gli utentiSolo un admin
Metodi di consensoStatico (app registration) oppure dinamico (richiesto all'accesso)Solo statico
Altri nomiScope, OAuth2 permission scopeApp role, permessi app-only
Oggetto di concessioneoAuth2PermissionGrantappRoleAssignment

Quest'ultima riga riassume tutto il problema. I due tipi di permessi vivono in due collezioni di oggetti distinte. Un audit che enumera gli appRoleAssignments non vede nulla del lato delegato, e viceversa: le due query restituiscono insiemi disgiunti, quindi una revisione che ne esegue solo una resta muta su metà della superficie.

I Due Modi in cui i Tenant Leggono il Modello di Consenso al Contrario

«Il delegato è quello sicuro»

La frase «l'applicazione non può fare più di quanto possa fare l'utente» è vera, e porta un peso per cui non è mai stata progettata.

Una concessione delegata ha un campo consentType con due valori possibili. Il riferimento di Microsoft è inequivocabile: «AllPrincipals indicates authorization to impersonate all users. Principal indicates authorization to impersonate a specific user.» Quando consentType è AllPrincipals, principalId è nullo — la concessione non è collegata a nessuno, perché si applica a tutti.

Un consenso admin a livello di tenant per il permesso delegato Mail.ReadWrite non significa quindi che l'applicazione possa leggere tutta la posta. Significa che l'applicazione è pre-autorizzata ad agire sulla casella di posta di qualsiasi utente che vi effettui l'accesso, senza schermata di consenso, finché la concessione esiste. Il limite resta i privilegi propri dell'utente collegato — ma la popolazione è l'intera directory, e l'attrito che normalmente costringerebbe un utente a fermarsi e leggere una schermata di consenso è scomparso.

Consideri ora chi accede agli strumenti interni. Se un Global Administrator o un Exchange Administrator si autentica su un'applicazione che detiene un Directory.ReadWrite.All delegato a livello di tenant, l'applicazione eredita la portata di quella sessione. Il delegato non è un limite sul privilegio; è un limite che si sposta con chi è collegato.

«I permessi applicativi sono quelli potenti, quindi chiediamo quelli»

L'errore speculare. Il percorso stesso del portale Microsoft presenta prima i permessi delegati e descrive i permessi applicativi come l'opzione per «service- or daemon-type applications that need to access a web API as themselves, without user interaction for sign-in or consent» — e questa descrizione è esattamente il motivo per cui gli sviluppatori li scelgono. Un servizio che deve solo leggere una casella condivisa finisce per detenere Mail.Read contro l'intera organizzazione, perché quella è l'unica granularità che Entra ID offre sul permesso Graph stesso.

La guida di Microsoft sull'accesso delegato è diretta su quale scenario è quale: l'accesso delegato è «usually a poor choice for scenarios that must run without a signed-in user, like automation», mentre bisogna «use delegated access whenever you want to let a signed-in user work with their own resources or resources they can access.» La modalità di fallimento nei tenant reali è scegliere per comodità — quello che si autentica senza una finestra del browser — piuttosto che in base a quale principal ha davvero bisogno del dato.

⚠️

⚠️ Attenzione: i due errori si sommano. Un tenant che concede eccessivamente sia scope delegati a livello di tenant sia permessi applicativi non delimitati ha due percorsi indipendenti e additivi verso lo stesso dato, tracciati in due posti diversi.

Cosa Offre a un Attaccante una Concessione Delegata a Livello di Tenant

L'accesso delegato richiede due autorizzazioni indipendenti per avere successo, e Microsoft le documenta separatamente: l'autorizzazione dell'applicazione client (l'applicazione ha ricevuto lo scope, che finisce nella claim scp del token) e l'autorizzazione dell'utente (la risorsa verifica i diritti propri dell'utente collegato). L'esempio OneDrive di Microsoft rende la matrice esplicita — una richiesta fallisce se uno dei due lo scope manca o l'utente non ha diritti sull'oggetto.

Un attaccante non deve rompere quel modello. Deve soddisfare entrambe le metà contemporaneamente, e una concessione a livello di tenant gli offre la prima metà gratis:

  1. Lo scope è già concesso. Con consentType = AllPrincipals, non c'è alcuna schermata di consenso da phishare né alcuna concessione per utente da creare. Qualsiasi token che l'applicazione ottiene per qualsiasi utente porta lo scope.
  2. La metà utente arriva con la vittima. Tutto ciò che l'utente compromesso o phishato può raggiungere, l'applicazione ora può raggiungerlo tramite l'API, che è esattamente la differenza tra «leggere questa singola casella in Outlook» ed «enumerarla programmaticamente a velocità macchina». E quella portata è spesso più ampia di quanto suggerisca l'organigramma — vedi ruoli admin di service principal sovraprivilegiati.
  3. La revoca non è dove te la aspetteresti. La stessa guida Microsoft nota che nell'admin center di Entra, «You can't revoke permissions in the User consent tab using the portal.» Le concessioni delegate per utente devono essere rimosse tramite Graph o PowerShell.

Questa è la stessa superficie di consenso sfruttata dal phishing di consenso OAuth, tranne che qui non serve alcun phishing — la concessione è già in essere, fatta da un amministratore, di solito anni prima, di solito per uno strumento ancora installato.

Due proprietà correlate dell'app registration ampliano il raggio d'impatto. signInAudience impostato su AzureADMultipleOrgs rende l'app registration multi-tenant — «users with a Microsoft work or school account in any organization's Microsoft Entra tenant» possono accedere. E le applicazioni che nessuno usa più mantengono le proprie concessioni indefinitamente: l'oggetto oAuth2PermissionGrant non ha alcuna proprietà di scadenza, quindi nulla fa invecchiare una concessione da sola, e un'integrazione dismessa con un secret ancora valido e una concessione a livello di tenant ancora valida è una credenziale in attesa di essere trovata. Vedi anche rotazione dei segreti app registration di Entra.

Rilevamento

Eseguite questo sul vostro stesso tenant. Leggere l'attività di accesso richiede AuditLog.Read.All (il meno privilegiato) e uno dei ruoli Reports Reader, Security Reader o Security Administrator; leggere e revocare concessioni richiede almeno Cloud Application Administrator.

Cosa cercareDoveSegnale
Concessioni delegate a livello di tenantoauth2PermissionGrantsconsentType eq 'AllPrincipals' — si applica a tutti gli utenti
Concessioni delegate per utenteoauth2PermissionGrantsconsentType eq 'Principal', non revocabile dal portale
Permessi applicativiservicePrincipals/{id}/appRoleAssignmentsNon delimitati, a livello di tenant per costruzione
Registrazioni multi-tenantapplicationssignInAudience eq 'AzureADMultipleOrgs'
App inattive/beta/reports/servicePrincipalSignInActivitieslastSignInActivity più vecchio di 90 giorni

Iniziate dalle concessioni che si applicano a tutti. consentType supporta $filter con eq:

GET https://graph.microsoft.com/v1.0/oauth2PermissionGrants?$filter=consentType eq 'AllPrincipals'

Ogni risultato fornisce clientId (l'object id del service principal client — non il suo appId), resourceId (l'API chiamata), e scope, un elenco separato da spazi come openid User.Read GroupMember.Read.All. L'equivalente in Microsoft Graph PowerShell:

Connect-MgGraph -Scopes "Directory.Read.All"
Get-MgOauth2PermissionGrant -All | Where-Object { $_.ConsentType -eq 'AllPrincipals' } |
    Select-Object ClientId, ResourceId, Scope

Recuperate poi l'altra collezione per lo stesso service principal, perché la query delegata sopra non la mostrerà mai:

GET https://graph.microsoft.com/v1.0/servicePrincipals/{id}/oauth2PermissionGrants
GET https://graph.microsoft.com/v1.0/servicePrincipals/{id}/appRoleAssignments

Registrazioni multi-tenant — signInAudience supporta $filter con eq, ne e not:

GET https://graph.microsoft.com/v1.0/applications?$filter=signInAudience eq 'AzureADMultipleOrgs'

Per le app inattive, l'attività di accesso dei service principal è un'API beta — Microsoft precisa che le API sotto /beta sono soggette a modifiche e non sono supportate in produzione, quindi trattatela come un input di audit, non come un controllo su cui costruire. Supporta $top, $filter e $orderby:

GET https://graph.microsoft.com/beta/reports/servicePrincipalSignInActivities
Import-Module Microsoft.Graph.Beta.Reports
Get-MgBetaReportServicePrincipalSignInActivity

Ogni record espone lastSignInActivity oltre a una ripartizione che indica come viene usata l'applicazione: delegatedClientSignInActivity (agisce per un utente collegato) versus applicationAuthenticationClientSignInActivity (app-only, senza utente). Questa ripartizione è il modo più rapido per individuare un'applicazione che detiene entrambi i tipi di permesso pur esercitandone sempre e solo uno, e alimenta direttamente il rilevamento di anomalie di accesso del service principal.

Rimedio

💡

💡 Quick Win: enumerate prima consentType eq 'AllPrincipals' e revocate le concessioni collegate ad applicazioni per cui nessuno sa indicare un owner. È il percorso più breve dall'audit a un raggio d'impatto ridotto.

1. Bloccare il sovra-consenso alla porta. Nell'admin center di Microsoft Entra, andate su Identity > Applications > Enterprise apps > Consent and permissions > User consent settings (Global Administrator per il portale; Privileged Role Administrator altrimenti). Per impostazione predefinita, «all users are allowed to consent to applications for permissions that don't require administrator consent.» Le due policy integrate sono microsoft-user-default-legacy (consente il consenso utente per le app — qualsiasi permesso che non richieda consenso admin, qualsiasi app) e microsoft-user-default-low (consente il consenso utente solo per app di publisher verificati o registrate nel vostro tenant, e solo per permessi che avete classificato a basso impatto). Programmaticamente:

PATCH https://graph.microsoft.com/v1.0/policies/authorizationPolicy

{
    "defaultUserRolePermissions": {
        "permissionGrantPoliciesAssigned": [
            "managePermissionGrantsForSelf.microsoft-user-default-low",
            "managePermissionGrantsForOwnedResource.{other-current-policies}"
        ]
    }
}

Leggete prima la authorizationPolicy attuale e preservate ogni voce ManagePermissionGrantsForOwnedResource.* esistente, altrimenti rimuoverete silenziosamente l'autoconsenso self-service degli sviluppatori. Abbinate questo al workflow di consenso admin in modo che gli utenti possano richiedere una revisione invece di restare bloccati, e rivedetelo insieme alle altre impostazioni utente predefinite del tenant che governano cosa i non-admin possono creare.

⚠️

⚠️ Attenzione: modificare questa impostazione corregge solo il futuro. Microsoft è esplicita: «Any updates to user consent settings only affect future consent operations for applications. Existing consent grants remain unchanged.» Inasprire la policy non revoca nemmeno una concessione esistente.

2. Revocare ciò che esiste già. I permessi delegati e applicativi si rimuovono tramite endpoint diversi:

DELETE https://graph.microsoft.com/v1.0/oAuth2PermissionGrants/{id}
DELETE https://graph.microsoft.com/v1.0/servicePrincipals/{resource-servicePrincipal-id}/appRoleAssignedTo/{appRoleAssignment-id}

Ricordate la particolarità del portale: la scheda Admin consent supporta la revoca dall'UI, la scheda User consent no. E la sola revoca non è duratura — Microsoft nota che «Revoking the current granted permission doesn't stop users from re-consenting to the application's requested permissions.» Occorre anche rimuovere il permesso da ciò che l'applicazione richiede, oppure bloccare del tutto il consenso utente.

3. Delimitare i permessi applicativi invece di accettare il livello tenant. Per i workload Exchange, RBAC for Applications permette di abbinare un app role a uno scope di risorsa, così che Mail.Read copra un insieme filtrato di caselle invece di tutte. Assegnare questi ruoli richiede l'appartenenza al gruppo di ruoli Organization Management in Exchange Online, e al ruolo Exchange Administrator in Microsoft Entra ID:

New-ServicePrincipal -AppId <appId> -ObjectId <servicePrincipalObjectId> -DisplayName "reporting-app"
New-ManagementScope -Name "Canadian users" -RecipientRestrictionFilter "CustomAttribute1 -eq '012332'"
New-ManagementRoleAssignment -App <servicePrincipalObjectId> -Role "Application Mail.Read" -CustomResourceScope "Canadian users"
Test-ServicePrincipalAuthorization -Identity "reporting-app" -Resource <targetMailbox> | Format-Table

C'è una trappola qui che coglie quasi tutti. Le FAQ di Microsoft lo dicono chiaramente: i permessi delle due autorità formano un'unione, non un'intersezione. «If your Service Principal has Mail.Read granted in Microsoft Entra ID and you configure a resource-scoped Mail.Read permission in Application RBAC, it's important that you remove the assignment of Mail.Read from Microsoft Entra ID. Otherwise, the union ... results in no effective resource scoping.» Delimitare in Exchange lasciando intatta la concessione Entra non cambia nulla. Notate anche che le modifiche ai permessi vengono messe in cache tra 30 minuti e 2 ore (il cmdlet di test bypassa la cache), e che gli scope di gestione esclusivi non limitano l'accesso applicativo.

4. Ritirare le registrazioni inattive. Qualsiasi app senza lastSignInActivity da 90 giorni è candidata a disattivazione-e-poi-eliminazione. Fatelo in quest'ordine così potete ripristinare rapidamente se un job trimestrale si rivela dipenderne. Eliminare il service principal in Entra rimuove automaticamente anche le sue assegnazioni RBAC di Exchange.

5. Rendere la revisione ricorrente, e coprire entrambe le collezioni. Una revisione che legge solo appRoleAssignments lascerà passare un tenant la cui esposizione reale è una concessione AllPrincipals vecchia di cinque anni. Integrate questo nel più ampio audit di sicurezza di Entra ID invece di trattarlo come una pulizia una tantum — le concessioni di consenso non hanno scadenza, quindi qui la deriva è permanente finché qualcuno non guarda.

Come EtcSec Rileva Questo

Il catalogo Azure di EtcSec copre entrambe le metà del modello di consenso. APP_EXCESSIVE_DELEGATED segnala le applicazioni che detengono più scope delegati di quanto la loro funzione giustifichi, e APP_CONSENT_GRANTED_TENANT_WIDE fa emergere le concessioni AllPrincipals che una revisione dei permessi basata sugli app role si lascerà sfuggire. APP_USER_CONSENT_UNRESTRICTED e APP_ADMIN_CONSENT_NOT_REQUIRED verificano le impostazioni a livello di tenant che permettono a quelle concessioni di accumularsi in primo luogo, mentre APP_MULTI_TENANT identifica le registrazioni con signInAudience esteso oltre la vostra directory, e APP_UNUSED_90_DAYS elenca le registrazioni che detengono ancora concessioni valide molto tempo dopo che qualcuno ha smesso di usarle.

Per il lato permessi applicativi dello stesso problema — nello specifico gli app role Directory, Mail, Files e RoleManagement — vedi Permessi Graph API pericolosi di app registration di Entra e App registration Azure: app con privilegi eccessivi nel tenant.

ℹ️

ℹ️ Nota: EtcSec verifica queste configurazioni errate a ogni audit di Entra ID. Eseguite un audit gratuito per vedere quali delle vostre app registration detengono oggi concessioni a livello di tenant.

Fonti

Esplora le pagine di identity security collegate a questo tema