Passa al contenuto principale

1. Introduction (Introduzione)

1. Introduction (Introduzione)

Integrità e autenticità del messaggio sono proprietà di sicurezza critiche per il funzionamento sicuro di molte applicazioni HTTP. Gli sviluppatori di applicazioni si affidano in genere al livello di trasporto per fornire tali proprietà, operando l'applicazione su TLS [TLS]. Tuttavia, TLS garantisce tali proprietà solo su una singola connessione TLS, e il percorso tra client e applicazione può essere composto da più connessioni TLS indipendenti (ad esempio se l'applicazione è ospitata dietro un gateway che termina TLS o se il client è dietro un appliance di ispezione TLS). In tali casi, TLS non può garantire integrità e autenticità end-to-end del messaggio tra client e applicazione. Inoltre, alcuni ambienti operativi presentano ostacoli che rendono impraticabile l'uso di TLS (come la presentazione di certificati client da un browser) o l'uso di funzionalità necessarie a fornire autenticità del messaggio. Inoltre, alcune applicazioni richiedono il legame di una chiave specifica dell'applicazione a livello superiore al messaggio HTTP, separata da qualsiasi certificato TLS in uso. Di conseguenza, sebbene TLS possa soddisfare le esigenze di integrità e autenticità del messaggio per molte applicazioni basate su HTTP, non è una soluzione universale.

Inoltre, molte applicazioni devono poter generare e verificare firme nonostante una conoscenza incompleta del messaggio HTTP così come visto sul filo, a causa di librerie, proxy o framework applicativi che alterano o nascondono porzioni del messaggio all'applicazione al momento della firma o della verifica. Tali applicazioni necessitano di un mezzo per proteggere le parti del messaggio più rilevanti per l'applicazione senza violare stratificazione e astrazione.

Infine, meccanismi di firma basati su oggetti come JSON Web Signature [JWS] richiedono la trasmissione intatta delle informazioni esatte che sono state firmate. Applicando tali tecnologie a un messaggio HTTP, elementi del messaggio HTTP devono essere duplicati nel payload dell'oggetto direttamente o tramite inclusione di un hash. Tale pratica introduce complessità, poiché le informazioni ripetute devono essere controllate attentamente per coerenza quando la firma viene verificata.

Questo documento definisce un meccanismo per fornire integrità e autenticità end-to-end per componenti di un messaggio HTTP mediante una firma distaccata (detached signature) sui messaggi HTTP. Il meccanismo consente alle applicazioni di creare firme digitali o codici di autenticazione dei messaggi (MAC) solo sulle componenti del messaggio significative e appropriate per l'applicazione. Regole rigorose di canonicalizzazione assicurano che il verificatore possa verificare la firma anche se il messaggio è stato trasformato in molti dei modi consentiti da HTTP.

Il meccanismo di firma descritto in questo documento consta di tre parti:

  • Una nomenclatura comune e un insieme di regole di canonicalizzazione per i diversi elementi di protocollo e altre componenti dei messaggi HTTP, usate per creare la base della firma (signature base, Sezione 2).

  • Algoritmi per generare e verificare firme sulle componenti del messaggio HTTP usando tale base della firma tramite l'applicazione di primitive crittografiche (Sezione 3).

  • Un meccanismo per allegare una firma e metadati correlati a un messaggio HTTP e per analizzare firme e metadati allegati dai messaggi HTTP. A tal fine, questo documento definisce i campi Signature-Input e Signature (Sezione 4).

Questo documento fornisce anche un meccanismo per negoziare l'uso di firme in uno o più messaggi successivi tramite il campo Accept-Signature (Sezione 5). Tale meccanismo di negoziazione opzionale può essere usato insieme a firme dei messaggi opportunistiche o guidate dall'applicazione da entrambe le parti.

I meccanismi definiti in questo documento sono strumenti importanti per costruire un meccanismo di sicurezza complessivo per un'applicazione. Questo kit di strumenti offre capacità potenti ma non è sufficiente a creare una storia di sicurezza completa. In particolare, i requisiti elencati nella Sezione 1.4 e le considerazioni di sicurezza discusse nella Sezione 7 sono di alta importanza per tutti gli implementatori di questa specifica. Ad esempio, questa specifica non definisce un mezzo per coprire direttamente il contenuto del messaggio HTTP (definito nella Sezione 6.4 di [HTTP]); piuttosto, si affida alla specifica Digest [DIGEST] per fornire un hash del contenuto del messaggio, come discusso nella Sezione 7.2.8.

1.1. Convenzioni e terminologia (Conventions and Terminology)

Le parole chiave "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY" e "OPTIONAL" in questo documento devono essere interpretate come descritto in BCP 14 [RFC2119] [RFC8174] quando, e solo quando, compaiono tutte in maiuscolo, come qui mostrato.

I termini "HTTP message", "HTTP request", "HTTP response", "target URI", "gateway", "header field", "intermediary", "request target", "trailer field", "sender", "method" e "recipient" sono usati come definiti in [HTTP].

Per brevità, il termine "signature" (firma) da solo in questo documento si riferisce sia a firme digitali (che usano crittografia asimmetrica) sia a MAC con chiave (che usano crittografia simmetrica). Analogamente, il verbo "sign" (firmare) indica la generazione di una firma digitale o di un MAC con chiave su una data base della firma. Il termine qualificato "digital signature" (firma digitale) si riferisce specificamente all'output di un'operazione di firma crittografica asimmetrica.

Questo documento usa la terminologia della Sezione 3 di [STRUCTURED-FIELDS] per specificare i tipi di dati: List, Inner List, Dictionary, Item, String, Integer, Byte Sequence e Boolean.

Questo documento definisce diverse costruzioni di stringhe usando ABNF [ABNF] e usa le seguenti regole ABNF: VCHAR, SP, DQUOTE e LF. Usa le regole ABNF da [STRUCTURED-FIELDS]: sf-string, inner-list e parameters. Usa le regole ABNF da [HTTP] e [HTTP/1.1]: field-content, obs-fold e obs-text.

Oltre a quelli elencati sopra, questo documento usa i seguenti termini:

HTTP Message Signature (firma del messaggio HTTP): Una firma digitale o MAC con chiave che copre una o più porzioni di un messaggio HTTP. Un dato messaggio HTTP può contenere più firme dei messaggi HTTP.

Signer (firmatario): L'entità che sta generando o ha generato una firma del messaggio HTTP. Più entità possono agire come firmatari e applicare firme distinte del messaggio HTTP a un dato messaggio HTTP.

Verifier (verificatore): Un'entità che sta verificando o ha verificato una firma del messaggio HTTP rispetto a un messaggio HTTP. Una firma del messaggio HTTP può essere verificata più volte, potenzialmente da entità diverse.

HTTP Message Component (componente del messaggio HTTP): Una porzione di un messaggio HTTP che può essere coperta da una firma del messaggio HTTP.

Derived Component (componente derivato): Una componente del messaggio HTTP derivata dal messaggio HTTP tramite l'uso di un algoritmo o processo specificato. Vedere Sezione 2.2.

HTTP Message Component Name (nome della componente del messaggio HTTP): Una String che identifica la sorgente di una componente del messaggio HTTP, come un nome di campo o un nome di componente derivato.

HTTP Message Component Identifier (identificatore della componente del messaggio HTTP): La combinazione di un nome di componente del messaggio HTTP e di eventuali parametri. Tale combinazione identifica in modo univoco una specifica componente del messaggio HTTP rispetto a una particolare firma del messaggio HTTP e al messaggio HTTP a cui si applica.

HTTP Message Component Value (valore della componente del messaggio HTTP): Il valore associato a un dato identificatore di componente nel contesto di un particolare messaggio HTTP. I valori delle componenti sono derivati dal messaggio HTTP e di solito sono soggetti a un processo di canonicalizzazione.

Covered Components (componenti coperte): Un insieme ordinato di identificatori di componenti del messaggio HTTP per campi (Sezione 2.1) e componenti derivate (Sezione 2.2) che indica l'insieme di componenti del messaggio coperte dalla firma, senza mai includere l'identificatore @signature-params stesso. L'ordine di tale insieme è preservato e comunicato tra firmatario e verificatore per facilitare la ricostruzione della base della firma.

Signature Base (base della firma): La sequenza di byte generata dal firmatario e dal verificatore usando l'insieme delle componenti coperte e il messaggio HTTP. La base della firma è elaborata dall'algoritmo crittografico per produrre o verificare la firma del messaggio HTTP.

HTTP Message Signature Algorithm (algoritmo di firma del messaggio HTTP): Un algoritmo crittografico che descrive il processo di firma e verifica per la firma, definito in termini delle primitive HTTP_SIGN e HTTP_VERIFY descritte nella Sezione 3.3.

Key Material (materiale di chiave): Il materiale di chiave richiesto per creare o verificare la firma. Il materiale di chiave è spesso identificato con un identificatore di chiave esplicito, consentendo al firmatario di indicare al verificatore quale chiave è stata usata.

Creation Time (istante di creazione): Un timestamp che rappresenta il momento in cui la firma è stata generata, come asserito dal firmatario.

Expiration Time (istante di scadenza): Un timestamp che rappresenta il momento dopo il quale la firma non dovrebbe più essere accettata dal verificatore, come asserito dal firmatario.

Target Message (messaggio di destinazione): Il messaggio HTTP a cui si applica una firma del messaggio HTTP.

Signature Context (contesto della firma): La sorgente dati da cui sono tratti i valori delle componenti del messaggio HTTP. Il contesto include il messaggio di destinazione e qualsiasi informazione aggiuntiva che il firmatario o il verificatore possono avere, come l'URI target completo di una richiesta o il messaggio di richiesta correlato per una risposta.

Il termine "UNIX timestamp" si riferisce a ciò che la Sezione 4.16 di [POSIX.1] chiama "seconds since the Epoch".

Questo documento contiene esempi non normativi di messaggi HTTP parziali e completi. Alcuni esempi usano un singolo backslash finale (\) per indicare l'andare a capo di valori lunghi, come da [RFC8792]. Il carattere \ e gli spazi iniziali sulle righe continuate non fanno parte del valore.

1.2. Requisiti (Requirements)

HTTP consente, e talvolta richiede, agli intermediari di trasformare i messaggi in vari modi. Ciò può far sì che un destinatario riceva un messaggio non bitwise-equivalente a quello inviato originariamente. In tal caso, il destinatario non sarà in grado di verificare protezioni di integrità sui byte grezzi del messaggio HTTP del mittente, poiché verificare firme digitali o MAC richiede che firmatario e verificatore abbiano esattamente la stessa base della firma. Poiché non si può fare affidamento sui byte grezzi esatti del messaggio come sorgente affidabile per una base della firma, firmatario e verificatore devono creare indipendentemente la base della firma dalle rispettive versioni del messaggio, tramite un meccanismo resiliente a cambiamenti sicuri che non alterano il significato del messaggio.

Per vari motivi, è impraticabile definire rigorosamente cosa costituisca un cambiamento sicuro rispetto a uno non sicuro. Le applicazioni usano HTTP in modi molto diversi e possono dissentire sulla rilevanza di una particolare informazione in un messaggio (ad esempio il contenuto del messaggio, il metodo o un particolare campo header). Pertanto, una soluzione generica deve fornire ai firmatari un certo grado di controllo su quali componenti del messaggio sono firmate.

Le applicazioni HTTP possono essere eseguite in ambienti che non forniscono accesso o controllo completi sui messaggi HTTP (come l'ambiente JavaScript di un browser) o possono usare librerie che astraggono i dettagli del protocollo (come la libreria Java HTTP Client (HttpClient) (https://openjdk.java.net/groups/net/httpclient/intro.html)). Tali applicazioni devono poter generare e verificare firme nonostante una conoscenza incompleta del messaggio HTTP.

1.3. Trasformazioni dei messaggi HTTP (HTTP Message Transformations)

Come già detto, HTTP consente esplicitamente, e in alcuni casi richiede, alle implementazioni di trasformare i messaggi in vari modi. Le implementazioni devono tollerare molte di queste trasformazioni. Di seguito una lista non normativa e non esaustiva di trasformazioni che possono verificarsi sotto HTTP, fornita come contesto:

  • Riordinamento di campi con nomi di campo diversi (Sezione 5.3 di [HTTP]).

  • Combinazione di campi con lo stesso nome di campo (Sezione 5.2 di [HTTP]).

  • Rimozione dei campi elencati nel campo header Connection (Sezione 7.6.1 di [HTTP]).

  • Aggiunta di campi che indicano opzioni di controllo (Sezione 7.6.1 di [HTTP]).

  • Aggiunta o rimozione di una codifica di trasferimento (Sezione 7.7 di [HTTP]).

  • Aggiunta di campi come Via (Sezione 7.6.3 di [HTTP]) e Forwarded (Sezione 4 di [RFC7239]).

  • Conversione tra diverse versioni di HTTP (ad esempio HTTP/1.x verso HTTP/2, o viceversa).

  • Variazioni di maiuscole/minuscole (ad esempio "Origin" in "origin") di qualsiasi componente non sensibile alle maiuscole, come nomi di campo, schema dell'URI della richiesta o host.

  • Modifiche al request target e all'authority che, applicate insieme, non comportano un cambiamento dell'URI target del messaggio, come definito nella Sezione 7.1 di [HTTP].

Inoltre, vi sono trasformazioni deprecate o altrimenti non consentite ma che possono ancora verificarsi sul campo. Tali trasformazioni possono ancora essere gestite senza rompere la firma; includono azioni come:

  • Uso, aggiunta o rimozione di spazi bianchi iniziali o finali in un valore di campo.

  • Uso, aggiunta o rimozione di obs-fold nei valori di campo (Sezione 5.2 di [HTTP/1.1]).

Si possono identificare questi tipi di trasformazioni come trasformazioni che non dovrebbero impedire la verifica della firma, anche quando eseguite su componenti del messaggio coperte dalla firma. Inoltre, tutte le modifiche a componenti non coperte dalla firma non dovrebbero impedire la verifica della firma.

Alcuni esempi di tali trasformazioni e l'effetto che hanno sulla firma del messaggio si trovano nell'Appendice B.4.

Altre trasformazioni, come l'analisi e la riserializzazione dei valori di campo di una componente coperta o la modifica del valore di una componente derivata, possono far sì che una firma non sia più valida rispetto a un messaggio di destinazione. Le applicazioni di questa specifica devono fare attenzione a garantire che le trasformazioni attese dall'applicazione siano adeguatamente gestite dalla scelta delle componenti coperte.

1.4. Applicazione delle firme dei messaggi HTTP (Application of HTTP Message Signatures)

Le firme dei messaggi HTTP sono progettate come strumento generico applicabile in molteplici circostanze e applicazioni. Per applicare correttamente e in sicurezza le firme dei messaggi HTTP, un'applicazione o un profilo di questa specifica DEVE specificare, come minimo, tutti gli elementi seguenti:

  • L'insieme di identificatori di componenti (Sezione 2) e parametri della firma (Sezione 2.3) attesi e richiesti nell'elenco delle componenti coperte. Ad esempio, un protocollo di autorizzazione potrebbe imporre che il campo Authorization sia coperto per proteggere le credenziali di autorizzazione e che i parametri della firma contengano un parametro created (Sezione 2.3), mentre un'API che si aspetta contenuto HTTP semanticamente rilevante potrebbe richiedere che il campo Content-Digest definito in [DIGEST] sia presente e coperto e imporre un valore per il parametro tag (Sezione 2.3) specifico dell'API protetta.

  • I tipi Structured Field [STRUCTURED-FIELDS] attesi di eventuali campi o parametri di componenti coperti richiesti o attesi.

  • Un mezzo per recuperare il materiale di chiave usato per verificare la firma. Un'applicazione userà di solito il parametro keyid dei parametri della firma (Sezione 2.3) e definirà regole per risolvere una chiave da lì, sebbene la chiave appropriata possa essere nota con altri mezzi come la preregistrazione della chiave del firmatario.

  • L'insieme di algoritmi di firma consentiti da usare dai firmatari e accettati dai verificatori.

  • Un mezzo per determinare che l'algoritmo di firma usato per verificare la firma sia appropriato per il materiale di chiave e il contesto del messaggio. Ad esempio, il processo potrebbe usare il parametro alg dei parametri della firma (Sezione 2.3) per dichiarare esplicitamente l'algoritmo, derivare l'algoritmo dal materiale di chiave o usare un algoritmo preconfigurato concordato tra firmatario e verificatore.

  • Un mezzo per determinare che una data chiave e algoritmo usati per una firma siano appropriati per il contesto del messaggio. Ad esempio, un server che si aspetta solo firme ECDSA dovrebbe sapere di rifiutare qualsiasi firma RSA, o un server che si aspetta crittografia asimmetrica dovrebbe sapere di rifiutare qualsiasi crittografia simmetrica.

  • Un mezzo per determinare il contesto per la derivazione delle componenti del messaggio da un messaggio HTTP e dal suo contesto applicativo. Se di norma è il messaggio HTTP di destinazione stesso, il contesto può includere informazioni aggiuntive note all'applicazione tramite configurazione, come un hostname esterno.

  • Se è necessario un legame tra richiesta e risposta usando il meccanismo fornito nella Sezione 2.4, tutti gli elementi del messaggio di richiesta e del messaggio di risposta che sarebbero richiesti per fornire proprietà di tale legame.

  • I messaggi di errore e i codici restituiti dal verificatore al firmatario quando la firma non è valida, il materiale di chiave non è appropriato, la finestra temporale di validità è fuori specifica, un valore di componente non può essere calcolato o si verificano altri errori durante la verifica della firma. Ad esempio, se una firma è usata come meccanismo di autenticazione, un codice di stato HTTP 401 (Unauthorized) o 403 (Forbidden) potrebbe essere appropriato. Se la risposta proviene da un'API HTTP, una risposta con codice di stato come 400 (Bad Request) potrebbe includere maggiori dettagli [RFC7807] [RFC9457], come un indicatore che è stato usato il materiale di chiave sbagliato.

Scegliendo questi parametri, un'applicazione delle firme dei messaggi HTTP deve garantire che il verificatore abbia accesso a tutte le informazioni richieste per ricostruire la base della firma. Ad esempio, un server dietro un reverse proxy dovrebbe conoscere l'URI originale della richiesta per usare la componente derivata @target-uri, sebbene l'URI target apparente sia cambiato dal reverse proxy (vedere anche Sezione 7.4.3). Inoltre, un'applicazione che usa firme nelle risposte deve garantire che i client che ricevono risposte firmate abbiano accesso a tutte le porzioni firmate del messaggio, incluse eventuali porzioni della richiesta firmate dal server usando il parametro req ("request-response") (Sezione 2.4).

I dettagli su tale profilazione rientrano nell'ambito dell'applicazione e sono fuori dall'ambito di questa specifica; tuttavia, alcune considerazioni aggiuntive sono discusse nella Sezione 7. In particolare, scegliendo l'insieme richiesto di identificatori di componenti, occorre fare attenzione a garantire che la copertura sia sufficiente per l'applicazione, come discusso nelle Sezioni 7.2.1 e 7.2.8. Questa specifica definisce solo parte di un sistema di sicurezza completo per un'applicazione. Costruendo un sistema di sicurezza completo basato su questo strumento, è importante eseguire un'analisi di sicurezza dell'intero sistema, di cui le firme dei messaggi HTTP sono una parte. I sistemi storici, come AWS Signature Version 4 [AWS-SIGv4], possono fornire ispirazione ed esempi su come applicare meccanismi simili a un'applicazione, sebbene l'esame di tali sistemi storici non elimini la necessità di un'analisi di sicurezza di un'applicazione delle firme dei messaggi HTTP.