Controllo di accesso nell'API SQL di Azure Cosmos DB

Azure Cosmos DB è un servizio di database NoSQL completamente gestito per lo sviluppo di app moderne. Questo articolo illustra l'API SQL per Azure Cosmos DB. L'accesso alle risorse nell'API SQL è regolato da un token della chiave master o da un token di risorsa. Per accedere a una risorsa, il token selezionato è incluso nell'intestazione di autorizzazione REST, come parte della stringa di autorizzazione.

Token di chiave master

Il token della chiave master è il token di chiave di accesso che consente agli utenti di avere il controllo completo delle risorse di Cosmos DB in un determinato account. La chiave master viene creata durante la creazione di un account. Esistono due set di chiavi master, la chiave primaria e la chiave secondaria. L'amministratore dell'account può applicare quindi la rotazione delle chiavi usando la chiave secondaria. Inoltre, l'amministratore account può anche rigenerare le chiavi, se necessario. Per istruzioni sulla rigenerazione e la distribuzione delle chiavi, vedere Proteggere l'accesso ai dati in Azure Cosmos DB.

Token delle risorse

I token di risorsa vengono creati quando gli utenti di un database vengono configurati con autorizzazioni di accesso per un controllo di accesso preciso su una risorsa, nota anche come risorsa di autorizzazione. Una risorsa di autorizzazione contiene un token di risorsa hash costruito con le informazioni relative al percorso della risorsa e al tipo di accesso a cui un utente può accedere. Il token della risorsa autorizzazione ha un limite di tempo ed è possibile eseguire l'override del periodo di validità. Quando viene eseguita un'operazione su una risorsa autorizzazione (POST, GET, PUT), viene generato un nuovo token della risorsa. Per informazioni sulle autorizzazioni e sui token delle risorse, vedere Operazioni sulle autorizzazioni di Cosmos DB.

Authorization header (Intestazione dell'autorizzazione)

Tutte le operazioni REST, indipendentemente dal fatto che si usi un token di chiave master o un token di risorsa, devono includere l'intestazione di autorizzazione con la stringa di autorizzazione per interagire con una risorsa. La stringa di autorizzazione è nel seguente formato:

type={typeoftoken}&ver={tokenversion}&sig={hashsignature}  

Una stringa di autorizzazione è simile all'esempio seguente:

type=master&ver=1.0&sig=5mDuQBYA0kb70WDJoTUzSBMTG3owkC0/cEN4fqa18/s=  

Le parti racchiuse tra parentesi sono le seguenti:

  • {typeoftoken} indica il tipo di token: master, resource o aad(se si usa il controllo degli accessi in base al ruolo di Azure Cosmos DB).

  • {tokenversion} indica la versione del token, attualmente 1.0.

  • {hashsignature} indica la firma del token hash o il token oauth se si usa il controllo degli accessi in base al ruolo di Azure Cosmos DB.

La stringa di autorizzazione deve essere codificata prima di essere aggiunta alla richiesta REST per garantire che non contenga caratteri non validi. Assicurarsi che sia codificato in Base64 usando MIME RFC2045. Inoltre, la chiave master usata nell'hashsignature deve essere decodificata usando MIME RFC2045 perché è codificata in Base64. Se vengono visualizzati problemi con l'autorizzazione, vedere Come diagnosticare e risolvere le eccezioni non autorizzate.

Costruzione della firma del token hash per un token master

La firma hash per il token della chiave master può essere creata dai parametri seguenti: Verb, ResourceType, ResourceLink e Date.

  1. Il verbo rappresenta il verbo HTTP della richiesta. I valori possibili sono: get, post, put, patch, delete

Nota: i valori devono essere minuscoli.

  1. La parte ResourceType della stringa identifica il tipo di risorsa per cui la richiesta è destinata. I valori possibili sono:
    • Operazioni di database: dbs
    • Operazioni del contenitore: colls
    • Stored procedure: sprocs
    • Funzioni definite dall'utente: udfs
    • Trigger: triggers
    • Gli utenti: users
    • Autorizzazioni: permissions
    • Operazioni a livello di elemento: docs

Nota: I valori fanno distinzione tra maiuscole e minuscole e devono essere minuscoli.

  1. La parte ResourceLink della stringa è la proprietà identity della risorsa a cui viene indirizzata la richiesta. Il valore ResourceLink dipende dall'operazione che si sta tentando di eseguire. Ogni operazione avrà un proprio ResourceLink corrispondente seguendo questa convenzione:
    • Se l'operazione viene eseguita su una risorsa specifica, il valore è il collegamento a tale risorsa. Esempi:

      • Per Ottenere database usare: dbs/{databaseId}
      • Per l'uso di Recupera documento: dbs/{databaseId}/colls/{containerId}/docs/{docId}
    • Se l'operazione viene eseguita su un set di risorse (Elenco, Crea, Query), il valore è il collegamento della risorsa padre. Esempi:

      • Per l'uso di Crea documento: dbs/{databaseId}/colls/{containerId}
      • Per l'uso della stored procedure di creazione: dbs/{databaseId}/colls/{containerId}
      • Per Creare un contenitore usare: dbs/{databaseId}
      • Per l'uso di Crea database: "" -> stringa vuota perché i database non dispongono di una risorsa padre

Nota: I nomi delle risorse a cui viene fatto riferimento come parte del valore ResourceLink fanno distinzione tra maiuscole e minuscole e devono corrispondere alla combinazione di maiuscole e minuscole della modalità di dichiarazione nel database. Gli altri componenti devono essere minuscoli.

  1. La parte Data della stringa è la data e l'ora UTC in cui il messaggio è stato inviato (in formato "HTTP-date" come definito dai formati data/ora RFC 7231), ad esempio "Mar, 01 Nov 1994 08:12:31 GMT".

    In C# può essere ottenuto usando l'identificatore di formato "R" sul DateTime.UtcNow valore.

    Anche questa stessa data(nello stesso formato) deve essere passata come x-ms-date intestazione nella richiesta.

Nota: Il valore fa distinzione tra maiuscole e minuscole e deve essere tutto minuscolo.

Per calcolare la firma, usare la funzione HMAC (Hash Authentication Code) basata su HASH256 con la chiave CosmosDB come segreto.

Il payload per la funzione di hashing si basa sui 4 componenti presentati in precedenza usando il formato seguente: "{verb}\n{resourceType}\n{resourceLink}\n{date}\n\n" (si noti la nuova riga aggiuntiva alla fine del payload).

Il risultato con codifica Base64 della funzione verrà usato come firma durante la costruzione dell'intestazione Authorization per la chiamata.

Esempio [C#] per un'intestazione di autorizzazione valida:

    httpClient.DefaultRequestHeaders.Clear();
    httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
    httpClient.DefaultRequestHeaders.Add("authorization", auth); //generated using method below
    httpClient.DefaultRequestHeaders.Add("x-ms-date", requestDateString);
    httpClient.DefaultRequestHeaders.Add("x-ms-version", "2018-12-31");

Esempio di metodo [C#] per generare una firma di autorizzazione valida:

Per visualizzare esempi completi per l'API REST di Cosmos DB, visitare il repository di esempi dell'API REST di Cosmos DB in GitHub

  
string GenerateMasterKeyAuthorizationSignature(HttpMethod verb, ResourceType resourceType, string resourceLink, string date, string key)
{
    var keyType = "master";
    var tokenVersion = "1.0";
    var payload = $"{verb.ToString().ToLowerInvariant()}\n{resourceType.ToString().ToLowerInvariant()}\n{resourceLink}\n{date.ToLowerInvariant()}\n\n";

    var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };
    var hashPayload = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payload));
    var signature = Convert.ToBase64String(hashPayload);
    var authSet = WebUtility.UrlEncode($"type={keyType}&ver={tokenVersion}&sig={signature}");

    return authSet;
}
  

Esempio [Node.js]:

  
var crypto = require("crypto");  
  
function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceId, date, masterKey) {  
    var key = new Buffer(masterKey, "base64");  
  
    var text = (verb || "").toLowerCase() + "\n" +   
               (resourceType || "").toLowerCase() + "\n" +   
               (resourceId || "") + "\n" +   
               date.toLowerCase() + "\n" +   
               "" + "\n";  
  
    var body = new Buffer(text, "utf8");  
    var signature = crypto.createHmac("sha256", key).update(body).digest("base64");  
  
    var MasterToken = "master";  
  
    var TokenVersion = "1.0";  
  
    return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);  
}  
  

Codifica di esempio:

Argomento Valore
Verbo GET
Tipo di risorsa "dbs"
Collegamento risorse "dbs/ToDoList"
Data Thu, 27 Apr 2017 00:51:12 GMT
Chiave dsZQi3KtZmCv1ljt3VNWNm7sQUF1y5rJfC6kv5Jiwv
W0EndXdDku/dkKBp8/ufDToSxLzR4y+O/0H/t4bQtVNw==
Tipo chiave master
Versione del token 1,0
Stringa di autorizzazione di output type%3dmaster%26ver%3d1.0%26sig%3dc09PEVJr
gp2uQRkr934kFbTqhByc7TVr3OHyqlu%2bc%2bc%3d

Costruzione della firma hash per un token di risorsa

I token di risorsa devono essere generati da un server intermedio. Il server funge da guardiano della chiave master e genera token con vincoli di tempo per i client non attendibili, ad esempio i Web browser.

Questo server esegue i passaggi seguenti:

  1. Gestisce le richieste client in ingresso per i nuovi token.

  2. Verifica l'identità client in modo specifico dell'applicazione.

  3. Se il client esegue correttamente l'autenticazione, usa le interfacce cosmos DB (SDK o REST) per generare un nuovo token limitato a tempo e lo restituisce al client.

Vedere anche