Usa cookie firmati

Questa pagina fornisce una panoramica dei cookie firmati e istruzioni per utilizzarli con Cloud CDN. I cookie firmati offrono accesso a risorse limitate nel tempo a un insieme di anche se gli utenti hanno o meno un Account Google.

I cookie firmati sono un'alternativa agli URL firmati. I cookie firmati proteggono l'accesso quando la firma separata di decine o centinaia di URL per ciascun utente non è possibile la tua applicazione.

I cookie firmati ti consentono di:

  • Autorizza un utente e forniscigli un token a tempo limitato per l'accesso i tuoi contenuti protetti (anziché firmare ogni URL).
  • Impostare l'accesso dell'utente a un prefisso URL specifico, ad esempio https://media.example.com/videos/ e concedi all'utente autorizzato l'accesso a contenuti protetti solo all'interno di quel prefisso URL.
  • Mantieni invariati gli URL e i manifest multimediali, semplificando la presentazione e il miglioramento della memorizzabilità nella cache.

Se invece vuoi limitare l'accesso a URL specifici, valuta la possibilità di utilizzare URL.

Prima di iniziare

Prima di utilizzare i cookie firmati, segui questi passaggi:

  • Assicurati che Cloud CDN sia abilitato. per le istruzioni, vedi Utilizzo di Cloud CDN. Puoi configurare di cookie firmati su un backend prima di abilitare Cloud CDN, ma non avrà alcun effetto finché Cloud CDN non sarà abilitato.

  • Se necessario, esegui l'aggiornamento alla versione più recente di Google Cloud CLI:

    gcloud components update
    

Per una panoramica, consulta la sezione URL e cookie firmati.

Configurazione delle chiavi di richiesta firmate

La creazione di chiavi per gli URL e i cookie firmati richiede diversi passaggi, descritti nelle sezioni seguenti.

Considerazioni sulla sicurezza

Cloud CDN non convalida le richieste nelle seguenti circostanze:

  • La richiesta non è firmata.
  • Il servizio di backend o il bucket di backend per la richiesta non contiene Cloud CDN abilitato.

Le richieste firmate devono sempre essere convalidate all'origine prima di gestire risposta. Questo perché le origini possono essere utilizzate per pubblicare una combinazione di e non firmati e perché un client potrebbe accedere direttamente all'origine.

  • Cloud CDN non blocca le richieste senza una query Signature o il cookie HTTP Cloud-CDN-Cookie. Rifiute le richieste non valide (o nel formato diverso) dei parametri della richiesta.
  • Quando la tua applicazione rileva una firma non valida, assicurati che il tuo l'applicazione risponde con un codice di risposta HTTP 403 (Unauthorized). I codici di risposta di HTTP 403 non sono memorizzabili nella cache.
  • Le risposte alle richieste firmate e non firmate vengono memorizzate nella cache separatamente, quindi una risposta corretta a una richiesta firmata valida non viene mai utilizzata per richiesta non firmata.
  • Se l'applicazione invia un codice di risposta memorizzabile nella cache a una richiesta non valida, richieste future valide potrebbero essere rifiutate erroneamente.

Per i backend Cloud Storage, assicurati di rimuovi l'accesso pubblico, in modo che Cloud Storage possa rifiutare le richieste prive di un indirizzo firma.

La seguente tabella riassume il comportamento.

La richiesta ha la firma Successo della cache Comportamento
No No Inoltra all'origine del backend.
No Pubblica dalla cache.
No Convalida firma. Se valido, esegui l'inoltro all'origine del backend.
Convalida firma. Se valido, pubblica dalla cache.

Crea chiavi di richiesta firmate

Puoi abilitare il supporto degli URL e dei cookie firmati di Cloud CDN creando una o più chiavi su un backend abilitato per Cloud CDN servizio, backend bucket o entrambi.

Per ogni servizio di backend o bucket di backend, puoi creare ed eliminare chiavi dettate dalle tue esigenze di sicurezza. Per ogni backend possono essere configurate fino a tre chiavi alla volta. Ti suggeriamo di ruotare periodicamente le chiavi eliminando le chiavi più vecchie aggiungendo una nuova chiave e utilizzando la nuova chiave quando si firmano URL o cookie.

Puoi utilizzare lo stesso nome di chiave in più servizi e bucket di backend poiché ogni set di chiavi è indipendente l'uno dall'altro. I nomi delle chiavi possono essere fino a 63 caratteri. Per assegnare un nome alle chiavi, utilizza i caratteri A-Z, a-z, 0-9, _ (trattino basso) e - (trattino).

Quando crei le chiavi, assicurati di tenerle al sicuro perché chiunque ne abbia uno le chiavi possono creare URL e cookie firmati che Cloud CDN accetta finché la chiave non viene eliminata da Cloud CDN. Le chiavi sono memorizzate su il computer in cui vengono generati gli URL o i cookie firmati. Cloud CDN archivia anche le chiavi per verificare le firme delle richieste.

Per mantenere segrete le chiavi, le coppie chiave-valore non vengono incluse nelle risposte a nessun richieste API. Se perdi una chiave, devi crearne una nuova.

Per creare una chiave di richiesta firmata, segui questi passaggi.

Console

  1. Nella console Google Cloud, vai alla pagina Cloud CDN.

    Vai a Cloud CDN

  2. Fai clic sul nome dell'origine a cui vuoi aggiungere la chiave.
  3. Nella pagina Dettagli origine, fai clic sul pulsante Modifica.
  4. Nella sezione Nozioni di base sull'origine, fai clic su Avanti per aprire lo Sezione Regole host e percorso.
  5. Nella sezione Regole host e percorso, fai clic su Avanti per aprire lo Sezione Prestazioni della cache.
  6. Nella sezione Contenuti con limitazioni, seleziona Limita l'accesso tramite URL e cookie firmati.
  7. Fai clic su Aggiungi chiave di firma.

    1. Specifica un nome univoco per la nuova chiave di firma.
    2. Nella sezione Metodo di creazione della chiave, seleziona Genera automaticamente. In alternativa, fai clic su Fammi accedere, quindi specifica una chiave di firma. valore.

      Per la prima opzione, copia la chiave di firma generata automaticamente in un file privato, che puoi utilizzare per creare URL firmati.

    3. Fai clic su Fine.

    4. Nella sezione Durata massima delle voci di cache, inserisci un valore, quindi seleziona un'unità di tempo.

  8. Fai clic su Fine.

gcloud

Lo strumento a riga di comando gcloud legge le chiavi da un file locale che da te specificato. Il file della chiave deve essere creato generando un codice 128 casuale forte bit, codificandoli con base64 e sostituendo il carattere + con - e sostituendo il carattere / con _. Per ulteriori informazioni, vedi RFC 4648. È fondamentale che la chiave sia fortemente casuale. In un sistema simile a UNIX, puoi generare una chiave fortemente casuale e archiviarla nel file della chiave con seguente comando:

head -c 16 /dev/urandom | base64 | tr +/ -_ > KEY_FILE_NAME

Per aggiungere la chiave a un servizio di backend:

gcloud compute backend-services \
   add-signed-url-key BACKEND_NAME \
   --key-name KEY_NAME \
   --key-file KEY_FILE_NAME

Per aggiungere la chiave a un bucket di backend:

gcloud compute backend-buckets \
   add-signed-url-key BACKEND_NAME \
   --key-name KEY_NAME \
   --key-file KEY_FILE_NAME

Configura le autorizzazioni di Cloud Storage

Se utilizzi Cloud Storage e hai limitato gli utenti che possono leggere devi concedere a Cloud CDN l'autorizzazione a leggere gli oggetti l'aggiunta dell'account di servizio Cloud CDN agli ACL di Cloud Storage.

Non è necessario creare l'account di servizio. L'account di servizio è vengono creati automaticamente la prima volta che aggiungi una chiave a un backend di un bucket in un progetto.

Prima di eseguire questo comando, aggiungi almeno una chiave a un bucket di backend nel tuo progetto. In caso contrario, il comando non va a buon fine e restituisce un errore perché L'account di servizio di riempimento della cache di Cloud CDN non viene creato finché non ne aggiungi uno o più chiavi per il progetto. Sostituisci PROJECT_NUM con il numero del progetto e BUCKET con il tuo spazio di archiviazione di sincronizzare la directory di una VM con un bucket.

gsutil iam ch \
  serviceAccount:service-PROJECT_NUM@cloud-cdn-fill.iam.gserviceaccount.com:objectViewer \
  gs://BUCKET

Account di servizio Cloud CDN service-PROJECT_NUM@cloud-cdn-fill.iam.gserviceaccount.com non viene visualizzato nell'elenco degli account di servizio del progetto. Questo perché l'account di servizio Cloud CDN è di proprietà di Cloud CDN, non del tuo progetto.

Per ulteriori informazioni sui numeri di progetto, consulta Individuare l'ID e il numero del progetto consulta la documentazione di assistenza della console Google Cloud.

Personalizza il tempo massimo di memorizzazione nella cache

Cloud CDN memorizza nella cache le risposte per le richieste firmate indipendentemente dal all'intestazione Cache-Control del backend. Il tempo massimo per cui le risposte possono essere memorizzate nella cache senza riconvalida viene impostato dal flag signed-url-cache-max-age, che il valore predefinito è un'ora e possono essere modificati come mostrato qui.

Per impostare il tempo massimo della cache per un servizio di backend o un bucket di backend, eseguine uno uno dei seguenti comandi:

gcloud compute backend-services update BACKEND_NAME
  --signed-url-cache-max-age MAX_AGE
gcloud compute backend-buckets update BACKEND_NAME
  --signed-url-cache-max-age MAX_AGE

Elenca i nomi delle chiavi di richiesta firmata

Per elencare le chiavi in un servizio di backend o in un bucket di backend, esegui una delle seguenti comandi:

gcloud compute backend-services describe BACKEND_NAME
gcloud compute backend-buckets describe BACKEND_NAME

Elimina le chiavi di richiesta firmate

Quando gli URL firmati da una determinata chiave non devono più essere rispettati, esegui una delle seguenti comandi per eliminare la chiave dal servizio di backend o dal bucket di backend:

gcloud compute backend-services \
   delete-signed-url-key BACKEND_NAME --key-name KEY_NAME
gcloud compute backend-buckets \
   delete-signed-url-key BACKEND_NAME --key-name KEY_NAME

Creazione di un criterio

Le norme relative ai cookie firmati sono una serie di coppie key-value (delimitate dal valore : ), simili ai parametri di ricerca utilizzati in un URL firmato. Per alcuni esempi, consulta l'articolo sull'emissione di cookie agli utenti.

I criteri rappresentano i parametri per i quali una richiesta è valida. I criteri sono utilizzando un codice HMAC (Hash-based Message Authentication Code) Cloud CDN esegue la convalida su ogni richiesta.

Definizione del formato e dei campi del criterio

Esistono quattro campi obbligatori che devi definire nel seguente ordine:

  • URLPrefix
  • Expires
  • KeyName
  • Signature

Le coppie key-value in un criterio relativo ai cookie firmati sono sensibili alle maiuscole.

URLPrefix

URLPrefix indica un prefisso URL con codifica Base64 sicuro per l'URL che include tutte percorsi per i quali deve essere valida la firma.

Un URLPrefix codifica uno schema (http:// o https://), un nome di dominio completo e un un percorso facoltativo. La fine del percorso con / è facoltativa, ma consigliata. La non deve includere parametri di ricerca o frammenti come ? o #.

Ad esempio, https://media.example.com/videos associa le richieste a entrambi seguenti:

  • https://media.example.com/videos?video_id=138183&user_id=138138
  • https://media.example.com/videos/137138595?quality=low

Il percorso del prefisso viene utilizzato come sottostringa di testo, non strettamente un percorso di directory. Ad esempio, il prefisso https://example.com/data concede l'accesso a entrambi i seguenti:

  • /data/file1
  • /database

Per evitare l'errore, ti consigliamo di terminare tutti i prefissi con /, a meno che scegliere intenzionalmente di terminare il prefisso con un nome file parziale come https://media.example.com/videos/123 per concedere l'accesso a:

  • /videos/123_chunk1
  • /videos/123_chunk2
  • /videos/123_chunkN

Se l'URL richiesto non corrisponde a URLPrefix, Cloud CDN rifiuta la richiesta e restituisce un errore HTTP 403 al client.

Scadenza

Expires deve essere un timestamp Unix (il numero di secondi dal 1° gennaio 1970).

KeyName

KeyName è il nome di una chiave creata per il bucket di backend oppure di servizio di backend. I nomi delle chiavi sono sensibili alle maiuscole.

Firma

Signature è la firma HMAC-SHA-1 codificata in Base64 e sicura per l'URL dei campi che costituiscono le norme sui cookie. Questo viene convalidato per ogni richiesta. richieste con una firma non valida vengono rifiutate con un errore HTTP 403.

Creazione programmatica di cookie firmati

I seguenti esempi di codice mostrano come creare in modo programmatico cookie.

Vai

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

// signCookie creates a signed cookie for an endpoint served by Cloud CDN.
//
// - urlPrefix must start with "https://" and should include the path prefix
// for which the cookie will authorize access to.
// - key should be in raw form (not base64url-encoded) which is
// 16-bytes long.
// - keyName must match a key added to the backend service or bucket.
func signCookie(urlPrefix, keyName string, key []byte, expiration time.Time) (string, error) {
	encodedURLPrefix := base64.URLEncoding.EncodeToString([]byte(urlPrefix))
	input := fmt.Sprintf("URLPrefix=%s:Expires=%d:KeyName=%s",
		encodedURLPrefix, expiration.Unix(), keyName)

	mac := hmac.New(sha1.New, key)
	mac.Write([]byte(input))
	sig := base64.URLEncoding.EncodeToString(mac.Sum(nil))

	signedValue := fmt.Sprintf("%s:Signature=%s",
		input,
		sig,
	)

	return signedValue, nil
}

Java

import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.time.ZonedDateTime;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class SignedCookies {

  public static void main(String[] args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.

    // The name of the signing key must match a key added to the back end bucket or service.
    String keyName = "YOUR-KEY-NAME";
    // Path to the URL signing key uploaded to the backend service/bucket.
    String keyPath = "/path/to/key";
    // The Unix timestamp that the signed URL expires.
    long expirationTime = ZonedDateTime.now().plusDays(1).toEpochSecond();
    // URL prefix to sign as a string. URL prefix must start with either "http://" or "https://"
    // and must not include query parameters.
    String urlPrefix = "https://media.example.com/videos/";

    // Read the key as a base64 url-safe encoded string, then convert to byte array.
    // Key used in signing must be in raw form (not base64url-encoded).
    String base64String = new String(Files.readAllBytes(Paths.get(keyPath)),
        StandardCharsets.UTF_8);
    byte[] keyBytes = Base64.getUrlDecoder().decode(base64String);

    // Create signed cookie from policy.
    String signedCookie = signCookie(urlPrefix, keyBytes, keyName, expirationTime);
    System.out.println(signedCookie);
  }

  // Creates a signed cookie for the specified policy.
  public static String signCookie(String urlPrefix, byte[] key, String keyName,
      long expirationTime)
      throws InvalidKeyException, NoSuchAlgorithmException {

    // Validate input URL prefix.
    try {
      URL validatedUrlPrefix = new URL(urlPrefix);
      if (!validatedUrlPrefix.getProtocol().startsWith("http")) {
        throw new IllegalArgumentException(
            "urlPrefix must start with either http:// or https://: " + urlPrefix);
      }
      if (validatedUrlPrefix.getQuery() != null) {
        throw new IllegalArgumentException("urlPrefix must not include query params: " + urlPrefix);
      }
    } catch (MalformedURLException e) {
      throw new IllegalArgumentException(
          "urlPrefix malformed: " + urlPrefix);
    }

    String encodedUrlPrefix = Base64.getUrlEncoder().encodeToString(urlPrefix.getBytes(
        StandardCharsets.UTF_8));
    String policyToSign = String.format("URLPrefix=%s:Expires=%d:KeyName=%s", encodedUrlPrefix,
        expirationTime, keyName);

    String signature = getSignatureForUrl(key, policyToSign);
    return String.format("Cloud-CDN-Cookie=%s:Signature=%s", policyToSign, signature);
  }

  // Creates signature for input string with private key.
  private static String getSignatureForUrl(byte[] privateKey, String input)
      throws InvalidKeyException, NoSuchAlgorithmException {

    final String algorithm = "HmacSHA1";
    final int offset = 0;
    Key key = new SecretKeySpec(privateKey, offset, privateKey.length, algorithm);
    Mac mac = Mac.getInstance(algorithm);
    mac.init(key);
    return Base64.getUrlEncoder()
        .encodeToString(mac.doFinal(input.getBytes(StandardCharsets.UTF_8)));
  }
}

Python

import argparse
import base64
from datetime import datetime
import hashlib
import hmac
from urllib.parse import parse_qs, urlsplit


def sign_cookie(
    url_prefix: str,
    key_name: str,
    base64_key: str,
    expiration_time: datetime,
) -> str:
    """Gets the Signed cookie value for the specified URL prefix and configuration.

    Args:
        url_prefix: URL prefix to sign.
        key_name: name of the signing key.
        base64_key: signing key as a base64 encoded string.
        expiration_time: expiration time.

    Returns:
        Returns the Cloud-CDN-Cookie value based on the specified configuration.
    """
    encoded_url_prefix = base64.urlsafe_b64encode(
        url_prefix.strip().encode("utf-8")
    ).decode("utf-8")
    epoch = datetime.utcfromtimestamp(0)
    expiration_timestamp = int((expiration_time - epoch).total_seconds())
    decoded_key = base64.urlsafe_b64decode(base64_key)

    policy = f"URLPrefix={encoded_url_prefix}:Expires={expiration_timestamp}:KeyName={key_name}"

    digest = hmac.new(decoded_key, policy.encode("utf-8"), hashlib.sha1).digest()
    signature = base64.urlsafe_b64encode(digest).decode("utf-8")

    signed_policy = f"Cloud-CDN-Cookie={policy}:Signature={signature}"

    return signed_policy

Convalida dei cookie firmati

Il processo di convalida di un cookie firmato è essenzialmente uguale alla generazione di un firmato. Ad esempio, supponiamo che tu voglia convalidare le seguenti intestazione cookie:

Cookie: Cloud-CDN-Cookie=URLPrefix=URL_PREFIX:Expires=EXPIRATION:KeyName=KEY_NAME:Signature=SIGNATURE; Domain=media.example.com; Path=/; Expires=Tue, 20 Aug 2019 02:26:49 GMT; HttpOnly

Puoi usare la chiave segreta denominata da KEY_NAME per a generare la firma in modo indipendente e a verificare che corrisponda SIGNATURE.

Invio di cookie agli utenti

L'applicazione deve generare e inviare a ogni utente (client) un singolo HTTP Cookie contenenti norme firmate correttamente:

  1. Crea un firmatario HMAC-SHA-1 nel codice dell'applicazione.

  2. Firma il criterio utilizzando la chiave scelta, prendendo nota del nome della chiave che hai aggiunto al backend, ad esempio mySigningKey.

  3. Crea una norma relativa ai cookie nel formato seguente, tenendo presente che sia il nome e valore sono sensibili alle maiuscole:

    Name: Cloud-CDN-Cookie
    Value: URLPrefix=$BASE64URLECNODEDURLORPREFIX:Expires=$TIMESTAMP:KeyName=$KEYNAME:Signature=$BASE64URLENCODEDHMAC
    

    Esempio di intestazione Set-Cookie:

    Set-Cookie: Cloud-CDN-Cookie=URLPrefix=aHR0cHM6Ly9tZWRpYS5leGFtcGxlLmNvbS92aWRlb3Mv:Expires=1566268009:KeyName=mySigningKey:Signature=0W2xlMlQykL2TG59UZnnHzkxoaw=; Domain=media.example.com; Path=/; Expires=Tue, 20 Aug 2019 02:26:49 GMT; HttpOnly
    

    Gli attributi Domain e Path nel cookie determinano se il client invia il cookie a Cloud CDN.

Consigli e requisiti

  • Imposta in modo esplicito gli attributi Domain e Path in modo che corrispondano al dominio e al percorso prefisso da cui intendi pubblicare contenuti protetti, che potrebbero differisce dal dominio e dal percorso in cui viene emesso il cookie (example.com rispetto a media.example.com o /browse contro /videos).

  • Assicurati di avere un solo cookie con un determinato nome per lo stesso nome Domain e Path.

  • Assicurati di non inviare cookie in conflitto poiché ciò potrebbe impedire accesso ai contenuti in altre sessioni del browser (finestre o schede).

  • Imposta i flag Secure e HttpOnly ove applicabile. Secure garantisce che il cookie viene inviato solo tramite connessioni HTTPS. HttpOnly impedisce di apportare disponibile per JavaScript.

  • Gli attributi dei cookie Expires e Max-Age sono facoltativi. Se le ometti, il cookie esiste mentre esiste la sessione del browser (scheda, finestra).

  • In caso di riempimento o fallimento della cache, il cookie firmato viene inviato attraverso un'origine definita nel servizio di backend. Assicurati di convalidare la tua richiesta il valore del cookie firmato su ogni richiesta prima della pubblicazione dei contenuti.