Firma e autenticazione delle richieste REST
Argomenti
- Utilizzo di credenziali di sicurezza temporanee
- Intestazione di autenticazione
- Standardizzazione della richiesta per la firma
- Costruzione dell'elemento CanonicalizedResource
- Costruzione dell'elemento CanonicalizedAmzHeaders
- Elementi StringToSign posizionali e denominati dell'intestazione HTTP
- Necessità del time stamp
- Esempi di autenticazione
- Problemi con la firma delle richieste REST
- Alternativa per l'autenticazione di una richiesta tramite stringa di query
In questo argomento viene illustrato come autenticare le richieste tramite Signature Version 2. Amazon S3 supporta ora il più recente Signature Version 4. L'ultima versione è ora supportata in tutte le regioni e le regioni create dopo il 30 gennaio 2014 supporteranno solo Signature Version 4. Per ulteriori informazioni, consulta la sezione Autenticazione delle richieste (AWS Signature Version 4) nella Documentazione di riferimento delle API di Amazon Simple Storage Service.
Per autenticazione si intende il processo di attestazione dell'identità in un sistema. L'identità è un importante fattore per le decisioni di controllo degli accessi in Amazon S3. Le richieste vengono accettate o rifiutate in parte anche in base all'identità del richiedente. Ad esempio, il diritto di creare bucket è riservato agli sviluppatori registrati e, di default, è solo il proprietario del bucket in questione ad avere il diritto di creare oggetti al suo interno. Poiché gli sviluppatori inviano richieste che invocano questi privilegi, dovranno provare la propria identità al sistema autenticando le richieste: in questa sezione viene illustrato come procedere.
I contenuti di questa sezione non si applicano alle richieste HTTP POST. Per ulteriori informazioni, consulta Caricamenti basati sul browser tramite POST (AWS Signature Version 2).
Per l'autenticazione, l'API REST di Amazon S3 utilizza uno schema HTTP personalizzato basato su un codice HMAC (Hash Message Authentication Code) con chiave. Per autenticare una richiesta, è necessario in primo luogo concatenare alcuni elementi della richiesta per formare una stringa, Per calcolare il codice HMAC di quella stringa si utilizza la chiave di accesso segreta AWS. Questo processo viene definito in modo informale "firma della richiesta", mentre il risultato dell'algoritmo HMAC viene definito firma perché simula le proprietà di sicurezza di una firma vera e propria. Infine, la firma viene aggiunta come parametro della richiesta tramite la sintassi descritta in questa sezione.
Quando il sistema riceve una richiesta autenticata, recupera la chiave di accesso segreta AWS dichiarata e la utilizza nello stesso modo per calcolare una firma per il messaggio ricevuto, quindi confronta la firma calcolata con quella presentata dal richiedente. Se le due firme coincidono, il sistema conclude che il richiedente ha accesso alla chiave di accesso segreta AWS e agisce quindi con l'autorità dell'entità principale a cui è stata assegnata la chiave. Se le due firme non coincidono, la richiesta viene scartata e il sistema risponde con un messaggio di errore.
Esempio Richiesta REST Amazon S3 autenticata
GET /photos/puppy.jpg HTTP/1.1 Host: awsexamplebucket1.us-west-1.s3.amazonaws.com Date: Tue, 27 Mar 2007 19:36:42 +0000
Authorization: AWS AKIAIOSFODNN7EXAMPLE: qgk2+6Sv9/oM7G3qLEjTH1a1l1g=
Utilizzo di credenziali di sicurezza temporanee
Se la richiesta viene firmata tramite credenziali di sicurezza temporanee (consulta Esecuzione di richieste), è necessario includere nella richiesta il corrispondente token di sicurezza aggiungendo l'intestazione x-amz-security-token
.
Quando si ottengono credenziali di sicurezza temporanee utilizzando l'API AWS Security Token Service, la risposta include le credenziali di sicurezza temporanee e un token di sessione. Il valore del token di sessione deve essere fornito nell'intestazione x-amz-security-token
durante l'invio di richieste ad Amazon S3. Per informazioni sull'API AWS Security Token Service fornita da IAM, consulta la sezione Operazioni nella Guida di riferimento alle API AWS Security Token Service.
Intestazione di autenticazione
L'API REST di Amazon S3 utilizza l'intestazione standard HTTP Authorization
per passare le informazioni di autenticazione (il nome dell'intestazione standard è poco felice perché in realtà comunica informazioni sull'autenticazione, non sull'autorizzazione). Nell'ambito dello schema di autenticazione Amazon S3, l'intestazione Authorization ha il formato seguente:
Authorization: AWS
AWSAccessKeyId
:Signature
Al momento della registrazione, gli sviluppatori ricevono un ID chiave di accesso AWS e una chiave di accesso segreta AWS. Per l'autenticazione delle richieste, l'elemento AWSAccessKeyId
identifica l'ID chiave di accesso utilizzata per calcolare la firma e, indirettamente, lo sviluppatore che invia la richiesta.
L'elemento Signature
corrisponde al codice HMAC-SHA1 RFC 2104 di alcuni elementi della richiesta, quindi la parte Signature
dell'intestazione Authorization varierà da richiesta a richiesta. Se la firma calcolata dal sistema corrisponde all'elemento Signature
incluso nella richiesta, il richiedente avrà dimostrato di possedere la chiave di accesso segreta AWS. La richiesta verrà quindi elaborata con l'identità e l'autorità dello sviluppatore titolare della chiave.
Di seguito è riportato un esempio di grammatica che illustra la costruzione dell'intestazione Authorization
per la richiesta. (Nell'esempio, l'elemento \n
rappresenta il punto di codice Unicode U+000A
, comunemente chiamato newline).
Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature; Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of(YourSecretAccessKey), UTF-8-Encoding-Of( StringToSign ) ) ); StringToSign = HTTP-Verb + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedAmzHeaders + CanonicalizedResource; CanonicalizedResource = [ "/" + Bucket ] + <HTTP-Request-URI, from the protocol name up to the query string> + [ subresource, if present. For example "?acl", "?location", or "?logging"]; CanonicalizedAmzHeaders = <described below>
HMAC-SHA1 è un algoritmo definito in base allo standard RFC 2104 - Keyed-Hashing for Message AuthenticationYourSecretAccessKey
) come chiave e la codifica UTF-8 di StringToSign
come messaggio. L'algoritmo HMAC-SHA1 restituirà sempre una stringa in byte, detta digest. Il parametro di richiesta Signature
viene costruito da Base64 codificando il digest.
Standardizzazione della richiesta per la firma
È importante ricordare che, quando il sistema riceve una richiesta di autenticazione, confronta la firma calcolata con la firma fornita nella richiesta in StringToSign
. Per questo motivo, devi calcolare la firma con lo stesso metodo utilizzato da Amazon S3. Il processo di stesura di una richiesta in una forma concordata per la firma viene definito standardizzazione.
Costruzione dell'elemento CanonicalizedResource
CanonicalizedResource
rappresenta la risorsa Amazon S3 cui è destinata la richiesta. È possibile costruire l'elemento per una richiesta REST nel modo seguente:
1 |
Iniziare con una stringa vuota ( |
2 |
Se la richiesta specifica un bucket tramite l'intestazione Host HTTP (in stile hosting virtuale), aggiungere il nome del bucket preceduto da Per una richiesta in stile hosting virtuale "https://awsexamplebucket1.s3.us-west-1.amazonaws.com/photos/puppy.jpg", l'elemento Per la richiesta in stile percorso, "https://s3.us-west-1.amazonaws.com/awsexamplebucket1/photos/puppy.jpg", l'elemento |
3 |
Aggiungere la parte di percorso relativa all'URI della richiesta HTTP non decodificato, fino alla stringa di query (senza includerla). Per una richiesta in stile hosting virtuale "https://awsexamplebucket1.s3.us-west-1.amazonaws.com/photos/puppy.jpg", l'elemento Per una richiesta di stile percorso, "https://s3.us-west-1.amazonaws.com/awsexamplebucket1/photos/puppy.jpg", Per una richiesta non indirizzata a un bucket, come GET Service, aggiungere "/". |
4 |
Se la richiesta è indirizzata a una risorsa secondaria, come Le risorse secondarie da includere nella costruzione dell'elemento CanonicalizedResource sono acl, lifecycle, location, logging, notification, partNumber, policy, requestPayment, torrent, uploadId, uploads, versionId, versioning, versions e website. Se la richiesta specifica parametri della stringa di query che sostituiscono i valori dell'intestazione della risposta (consultare Get Object), aggiungere i parametri della stringa di query e i rispettivi valori. Al momento della firma questi valori non vanno codificati, ma i valori dei parametri devono essere codificati quando si invia la richiesta. I parametri della stringa di query in una richiesta GET includono Quando si crea l'elemento CanonicalizedResource per una richiesta di eliminazione di più oggetti, è necessario includere il parametro della stringa di query |
Gli elementi della CanonicalizedResource provenienti dall'URI della richiesta HTTP devono essere firmati esattamente come appaiono nella richiesta HTTP, compresi i metacaratteri della codifica URL.
L'elemento CanonicalizedResource
può variare rispetto all'URI della richiesta HTTP. Nello specifico, se nella richiesta è utilizzata l'intestazione HTTP Host
per la specifica di un bucket, quest'ultimo non compare nell'URI della richiesta HTTP. Tuttavia, nella CanonicalizedResource
è sempre incluso il bucket. Nell'URI della richiesta possono comparire anche i parametri della stringa di query, che non sono comunque inclusi nella CanonicalizedResource
. Per ulteriori informazioni, consulta Hosting virtuale dei bucket.
Costruzione dell'elemento CanonicalizedAmzHeaders
Per costruire la parte CanonicalizedAmzHeaders dell'elemento StringToSign
, selezionare tutte le richieste HTTP che iniziano con "x-amz-" (tramite un confronto senza distinzione tra maiuscole e minuscole) e utilizzare il processo illustrato di seguito.
1 | Convertire ciascun nome dell'intestazione HTTP in lettere minuscole. Ad esempio "X-Amz-Date " diventa "x-amz-date ". |
2 | Disporre la raccolta delle intestazioni in ordine lessicografico in base al nome dell'intestazione. |
3 | Combinare i campi di intestazione con lo stesso nome in una coppia "nome-valore:elenco-valori-separati-da-virgole", come stabilito dallo standard RFC 2616, sezione 4.2, senza spazi tra i valori. Ad esempio, le due intestazioni con metadata "x-amz-meta-username: fred " e "x-amz-meta-username: barney " verrebbero combinate nell'intestazione singola "x-amz-meta-username:
fred,barney ". |
4 | "Aprire" le intestazioni più lunghe che occupano più righe (come consentito dallo standard RFC 2616, sezione 4.2) sostituendo gli spazi di folding (newline compreso) con un singolo spazio. |
5 | Rimuovere gli spazi attorno ai due punti nell'intestazione. Ad esempio, l'intestazione "x-amz-meta-username: fred,barney " diventerebbe "x-amz-meta-username:fred,barney " |
6 | Infine, aggiungere un carattere newline (U+000A ) a ogni intestazione standardizzata nell'elenco risultante. Costruire l'elemento CanonicalizedResource concatenando tutte le intestazioni dell'elenco in un'unica stringa. |
Elementi StringToSign posizionali e denominati dell'intestazione HTTP
I primi elementi dell'intestazione di StringToSign
(Content-Type, Date e Content-MD5) sono posizionali per natura. StringToSign
non include i nomi delle intestazioni, ma solo i valori tratti dalla richiesta. Al contrario, gli elementi "x-amz-
" sono denominati. In sono inclusi sia i nomi, sia i valori dell'intestazion StringToSign
.
Se un'intestazione posizionale richiamata per la definizione di StringToSign
non è presente nella richiesta (ad esempio, Content-Type
o Content-MD5
sono facoltative per le richieste PUT e prive di senso per le richieste GET), la stringa vuota ("") per tale posizione va sostituita.
Necessità del time stamp
Per le richieste autenticate, è obbligatorio un time stamp valido (tramite intestazione Date
HTTP o un'alternativa x-amz-date
). Inoltre, alla ricezione di una richiesta autenticata, il timestamp del client incluso nella richiesta non deve differire di oltre 15 minuti rispetto all'orario di sistema in Amazon S3. In caso contrario, la richiesta avrà esito negativo con il codice di errore RequestTimeTooSkewed
. Tali restrizioni hanno lo scopo di limitare le possibilità che una richiesta intercettata possa essere riproposta da un sistema avversario. Per una maggiore protezione contro le intercettazioni, utilizzare il protocollo di trasferimento HTTPS per le richieste autenticate.
Il vincolo relativo alla convalida della data della richiesta è valido solo per le richieste autenticate che non utilizzano l'autenticazione stringa di query. Per ulteriori informazioni, consulta Alternativa per l'autenticazione di una richiesta tramite stringa di query.
Alcune librerie client HTTP non danno la possibilità di impostare l'intestazione Date
per una richiesta. Se includere il valore dell'intestazione "Date" nelle intestazioni standardizzate crea difficoltà, è possibile impostare il time stamp per la richiesta utilizzando l'intestazione "x-amz-date
". Il valore dell'intestazione x-amz-date
deve essere in uno dei formati RFC 2616 (http://www.ietf.org/rfc/rfc2616.txtx-amz-date
, durante il calcolo della firma della richiesta il sistema ignorerà qualsiasi intestazione di tipo Date
. Di conseguenza, se si include l'intestazione x-amz-date
, va utilizzata la stringa vuota per il valore Date
durante la costruzione della stringa StringToSign
. Nella prossima sezione sarà riportato un esempio.
Esempi di autenticazione
Gli esempi in questa sezione utilizzano le credenziali (non funzionanti) incluse nella seguente tabella.
Parametro | Valore |
---|---|
AWSAccessKeyId | AKIAIOSFODNN7EXAMPLE |
AWSSecretAccessKey | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
Negli elementi StringToSign
di esempio, la formattazione non è significativa, mentre l'elemento \n
rappresenta il punto di codice Unicode U+000A
, comunemente chiamato newline. Inoltre, negli esempi viene utilizzato "+0000" per identificare il fuso orario. Allo stesso scopo è anche possibile utilizzare "GMT", ma le firme mostrate nell'esempio saranno diverse.
Richiesta GET di un oggetto
Nell'esempio viene richiesto un oggetto dal bucket awsexamplebucket1.
Richiesta | StringToSign |
---|---|
|
|
Si noti che il nome del bucket è presente in CanonicalizedResource, ma non nell'URI della richiesta HTTP. (Il bucket è specificato dall'intestazione Host).
Il seguente script Python calcola la firma precedente utilizzando i parametri forniti. È possibile utilizzare questo script per creare le proprie firme, sostituendo le chiavi e StringToSign in base alle esigenze.
import base64 import hmac from hashlib import sha1 access_key = '
AKIAIOSFODNN7EXAMPLE
'.encode("UTF-8") secret_key = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
'.encode("UTF-8") string_to_sign = 'GET\n\n\nTue, 27 Mar 2007 19:36:42 +0000\n/awsexamplebucket1/photos/puppy.jpg
'.encode("UTF-8") signature = base64.encodestring( hmac.new( secret_key, string_to_sign, sha1 ).digest() ).strip() print(f"AWS {access_key.decode()}:{signature.decode()}")
Richiesta PUT di un oggetto
Nell'esempio viene inserito un oggetto nel bucket awsexamplebucket1.
Richiesta | StringToSign |
---|---|
|
|
Si noti l'intestazione Content-Type nella richiesta e in StringToSign. Si noti inoltre che l'intestazione Content-MD5 è lasciata vuota in StringToSign perché non è presente nella richiesta.
Elenco
Nell'esempio viene recuperato l'elenco dei contenuti del bucket awsexamplebucket1.
Richiesta | StringToSign |
---|---|
|
|
Si noti la barra finale in CanonicalizedResource e l'assenza di parametri della stringa di query.
Recupero
Nell'esempio viene recuperata la risorsa secondaria relativa alla policy di controllo degli accessi per il bucket "awsexamplebucket1".
Richiesta | StringToSign |
---|---|
|
|
Si noti il modo in cui il parametro della stringa di query della risorsa secondaria è incluso in CanonicalizedResource.
Delete
In questo esempio viene eliminato un oggetto dal bucket "awsexamplebucket1" utilizzando lo stile percorso e l'alternativa Date.
Richiesta | StringToSign |
---|---|
|
|
Si noti come è stato utilizzato il metodo alternativo "x-amz-date" per la specifica della data (ad esempio perché la libreria del client impedisce di impostare la data). In questo caso, il metodo x-amz-date
prevale sull'intestazione Date
. Di conseguenza, la voce relativa alla data nella firma deve contenere il valore dell'intestazione x-amz-date
.
Caricamento
In questo esempio viene caricato un oggetto in un bucket CNAME in stile hosting virtuale con metadata.
Richiesta | StringToSign |
---|---|
|
|
Osserva il modo in cui le intestazioni "x-amz-" vengono ordinate, private degli spazi aggiuntivi e convertite in caratteri minuscoli. Inoltre, più intestazioni con lo stesso nome sono state unite, con i valori separati da virgole.
Si noti come solo le intestazioni delle entità HTTP Content-Type
e Content-MD5
siano presenti in StringToSign
, mentre le intestazioni dell'altra entità Content-*
non lo sono.
Si noti nuovamente che il nome del bucket è presente in CanonicalizedResource
, ma non nell'URI della richiesta HTTP. (Il bucket è specificato dall'intestazione Host).
Elenco di tutti i bucket personali
Richiesta | StringToSign |
---|---|
|
|
Chiavi Unicode
Richiesta | StringToSign |
---|---|
|
|
Gli elementi inclusi in StringToSign
derivanti dall'URI della richiesta sono stati presi letteralmente, comprensivi di codifica dell'URL e uso delle maiuscole.
Problemi con la firma delle richieste REST
In caso di errore nell'autenticazione delle richieste REST, il sistema risponde alla richiesta con un documento di errore XML, che contiene informazioni concepite per aiutare gli sviluppatori a individuare il problema. In particolare, l'elemento StringToSign
del documento di errore SignatureDoesNotMatch
indica esplicitamente il tipo di standardizzazione della richiesta usata dal sistema.
Alcuni kit di strumenti inseriscono tacitamente intestazioni non note in precedenza, ad esempio nel caso dell'aggiunta dell'intestazione Content-Type
durante un'operazione PUT. In gran parte dei casi, il valore dell'intestazione inserita rimane costante: questo consente di scoprire le intestazioni mancanti utilizzando strumenti come Ethereal o tcpmon.
Alternativa per l'autenticazione di una richiesta tramite stringa di query
È possibile autenticare alcuni tipi di richieste passando le informazioni necessarie come parametri di una stringa di query, invece di utilizzare l'intestazione HTTP Authorization
. Questa soluzione è utile per abilitare l'accesso diretto da parte di browser di terze parti ai dati Amazon S3 privati senza proxy della richiesta. L'idea è costruire di una richiesta "prefirmata" e codificarla come URL recuperabile da parte del browser di un utente finale. È inoltre possibile limitare una richiesta prefirmata specificando un periodo di scadenza.
Per ulteriori informazioni sull'utilizzo di parametri di query per autenticare le richieste, consulta la sezione Autenticazione delle richieste: Uso dei parametri di query (AWS Signature Version 4) nella Documentazione di riferimento delle API di Amazon Simple Storage Service. Per alcuni esempi di utilizzo degli SDK AWS per la generazione di URL prefirmati, consulta Condivisione di oggetti mediante URL prefirmati.
Creazione di una firma
Di seguito è riportato un esempio di richiesta REST Amazon S3 autenticata tramite stringa di query.
GET /photos/puppy.jpg ?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Expires=1141889120&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv4%3D HTTP/1.1 Host: awsexamplebucket1.s3.us-west-1.amazonaws.com Date: Mon, 26 Mar 2007 19:37:58 +0000
Il metodo di autenticazione delle richieste tramite stringa di query non richiede particolari intestazioni HTTP. Gli elementi necessari all'autenticazione sono invece specificati come parametri della stringa di query:
Nome parametro stringa di query | Valore di esempio | Descrizione |
---|---|---|
AWSAccessKeyId |
AKIAIOSFODNN7EXAMPLE |
L'ID chiave di accesso AWS. Specifica la chiave di accesso segreta AWS utilizzata per firmare la richiesta e, indirettamente, l'identità dello sviluppatore che invia la richiesta. |
Expires |
1141889120 |
L'ora di scadenza della firma, specificata come numero di secondi dal valore epoca (Unix epoch, ovvero 00:00:00 UTC del 1° gennaio 1970). Se ricevuta dopo l'ora indicata (secondo il server), la richiesta verrà rifiutata. |
Signature |
vjbyPxybdZaNmGa%2ByT272YEAiv4%3D |
La codifica URL della codifica Base64 relativa all'algoritmo HMAC-SHA1 dell'elemento StringToSign. |
Il metodo di autenticazione delle richieste tramite stringa di query varia leggermente rispetto al metodo tradizionale, ma solo nel formato del parametro di richiesta Signature
e nell'elemento StringToSign
. Di seguito è riportato un esempio di grammatica che illustra il metodo di autenticazione delle richieste tramite stringa di query.
Signature = URL-Encode( Base64( HMAC-SHA1( YourSecretAccessKey, UTF-8-Encoding-Of( StringToSign ) ) ) ); StringToSign = HTTP-VERB + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Expires + "\n" + CanonicalizedAmzHeaders + CanonicalizedResource;
YourSecretAccessKey
è l'ID chiave di accesso segreta AWS assegnata da Amazon al momento della registrazione come sviluppatore Amazon Web Service. Si noti come il parametro Signature
sia codificato come URL per renderlo adatto all'inserimento nella stringa di query. Inoltre, in StringToSign
, l'elemento posizionale HTTP Date
è stato sostituito con l'elemento Expires
, mentre CanonicalizedAmzHeaders
e CanonicalizedResource
restano invariati.
Nel metodo di autenticazione stringa di query, non si utilizzano né l'elemento Date
né l'intestazione x-amz-date request
per il calcolo della stringa da firmare.
Autenticazione di una richiesta tramite stringa di query
Richiesta | StringToSign |
---|---|
|
|
Si presuppone che, al momento di inviare la richiesta GET, il browser non fornisca le intestazioni Content-MD5 o Content-Type e non imposti intestazioni x-amz-, quindi queste parti sono lasciate vuote nel'elemento StringToSign
.
Utilizzo della codifica Base64
Le firme di richiesta HMAC devono essere codificate in formato Base64. La codifica Base64 converte la firma in una stringa ASCII semplice che è possibile allegare alla richiesta. Se utilizzati in un URI, i caratteri che possono essere presenti in una firma, ad esempio il più (+), la barra (/) e l'uguale (=), devono essere codificati. Ad esempio, se il codice di autenticazione include un simbolo più (+), nella richiesta va codificato come %2B. La codifica per la barra è %2F, mentre per l'uguale è %3D.
Per esempi di codifica Base64, consulta di Amazon 3 Esempi di autenticazione.