Do you build things with AMP? Fill out the AMP Developer Survey!
AMP

Protezione dei contenuti degli utenti con la crittografia lato client

Gli editori che pubblicano contenuti online probabilmente offrono servizi in abbonamento ai propri clienti da cui ricavano profitti. I contenuti premium offerti potrebbero essere protetti dietro un paywall sul client utilizzando degli strumenti di offuscamento CSS (display: none).

I contenuti premium sono accessibili solo agli utenti autenticati.

Purtroppo, gli utenti più esperti di tecnologia sono spesso in grado di aggirare questi strumenti.

Si potrebbe allora adottare una soluzione che mostra agli utenti un documento completamente privo di contenuti premium! Quindi si potrebbe fornire una pagina completamente nuova solo dopo che il backend ha effettuato la verifica dell'utente. Sebbene più sicuro, questo metodo costa tempo, risorse e non soddisfa gli utenti.

Entrambi questi problemi possono essere risolti implementando procedure di verifica degli abbonati premium e la decrittografia dei contenuti sul lato client. Con questa soluzione, gli utenti con accesso premium potranno decrittografare i contenuti senza dover caricare una nuova pagina o attendere la risposta di un sistema di backend!

Panoramica della configurazione

Per implementare la decrittografia sul lato client, occorre combinare procedure di crittografia a chiave simmetrica con procedure di crittografia a chiave pubblica, nel modo seguente:

  1. Creare una chiave simmetrica casuale per ogni documento, assegnando a ogni documento una chiave univoca.
  2. Crittografare i contenuti premium con la chiave simmetrica del suo documento.
    La chiave simmetrica permette di usare la stessa chiave per crittografare e decrittografare i contenuti.
  3. Crittografare la chiave del documento con una chiave pubblica, usando un protocollo di crittografia ibrido per crittografare le chiavi simmetriche.
  4. Usare i componenti <amp-subscriptions> e/o <amp-subscriptions-google> per memorizzare la chiave del documento crittografato all'interno del documento AMP, insieme ai contenuti premium crittografati.

Il documento AMP conserva la chiave crittografata al suo interno. Ciò impedisce il disaccoppiamento del documento crittografato dalla chiave che lo decodifica.

Come funziona questo processo?

  1. AMP è in grado di individuare la chiave nel contenuto criptato dei documenti di destinazione dell'utente.
  2. Durante la pubblicazione dei contenuti premium, AMP invia la chiave simmetrica crittografata dal documento al provider di autorizzazioni nell'ambito della procedura di lettura dei diritti dell'utente.
  3. Il provider di autorizzazioni decide se l'utente dispone delle credenziali corrette. In caso affermativo, l'autorizzazione prosegue decrittografando la chiave simmetrica del documento con la chiave privata del provider, che dispone della coppia chiave pubblica/privata. Quindi il provider di autorizzazioni restituisce la chiave del documento alla logica del componente amp-subscriptions.
  4. Quindi AMP si occupa della decrittografia dei contenuti premium con la chiave del documento e li mostra all'utente!

Passi dell'implementazione

Applicare la seguente procedura per integrare la gestione della procedura di crittografia AMP nel server interno delle credenziali.

Passo 1: creare una coppia di chiavi pubblica/privata

Per crittografare la chiave simmetrica del documento, è necessario disporre della propria coppia di chiavi pubblica/privata. La crittografia a chiave pubblica è un protocollo di crittografia ibrido, in particolare quello adottato è un sistema di crittografia asimmetrica ECIES a Curva Ellittica P-256 integrato con un sistema di crittografia simmetrica AES-GCM (a 128 bit).

Richiediamo che la gestione della chiave pubblica venga eseguita con Tink utilizzando questo tipo di chiave asimmetrica. Per creare la coppia di chiavi pubblica-privata, utilizzare uno dei seguenti strumenti:

Entrambi gli strumenti supportano la rotazione delle chiavi. L'utilizzo della rotazione delle chiavi riduce la vulnerabilità del sistema alla violazione delle chiavi private.

Per semplificare la creazione di chiavi asimmetriche, abbiamo creato questo script. Esso permette di:

  1. Creare una nuova chiave ECIES con AEAD.
  2. Memorizzare la chiave pubblica in un file di output in formato testo.
  3. Memorizzare la chiave privata in un altro file di output.
  4. Crittografare la chiave privata generata utilizzando una chiave ospitata su Google Cloud (GCP) prima di scriverla sul file di output (procedura comunemente denominata crittografia di tipo envelope).

Richiediamo che il Set di chiavi pubbliche Tink dell'utente sia memorizzato/pubblicato in formato JSON. Ciò consente ad altri strumenti forniti da AMP di funzionare perfettamente. Il nostro script dà in output la chiave pubblica in questo formato.

Passo 2: crittografia degli articoli

Occorre poi scegliere se crittografare manualmente o automaticamente i contenuti premium.

Crittografia manuale

Richiediamo che i contenuti premium siano crittografati con il sistema simmetrico AES-GCM 128 che utilizza lo strumento Tink. La chiave simmetrica del documento utilizzata per crittografare il contenuto premium deve essere univoca per ogni documento. Aggiungere la chiave del documento a un oggetto JSON contenente la chiave in formato testo semplice con codifica base64, insieme agli SKU richiesti per accedere ai contenuti crittografati del documento.

Il seguente oggetto JSON contiene un esempio della chiave in formato testo semplice con codifica base64 e gli SKU.

{
  AccessRequirements: ['thenewsynews.com:premium'],
  Key: 'aBcDef781-2-4/sjfdi',
}

Crittografare tale oggetto JSON utilizzando la chiave pubblica generata al passo Creazione di una coppia di chiavi pubblica/privata.

Aggiunere il risultato della procedura di crittografia come valore alla chiave "local". Memorizzare la coppia chiave-valore all'interno di un oggetto JSON racchiuso in un tag <script type="application/json" cryptokeys="">. Posizionare il tag nell'intestazione del documento.

<head>
...
<script type="application/json" cryptokeys="">
{
  "local": ['y0^r$t^ff'], // Questo è per il tuo ambiente
  "google.com": ['g00g|e$t^ff'], // Questo è per l'ambiente Google
}
</script></head>

È necessario crittografare la chiave del documento con l'ambiente locale e la chiave pubblica di Google. L'inclusione della chiave pubblica di Google consente alla cache AMP Google di pubblicare il documento. Occorre creare un'istanza di un Set di chiavi Tink per accettare la chiave pubblica di Google dal suo URL:

https://news.google.com/swg/encryption/keys/prod/tink/public\_key

La chiave pubblica di Google è un Set di chiavi Tink in formato JSON. Qui è disponibile un esempio di utilizzo di questo set di chiavi.

Continua a leggere: Guarda un esempio di documento AMP crittografato funzionante.

Crittografia automatica

Il documento può essere crittografato utilizzando il nostro script. Lo script accetta un documento HTML ed esegue la crittografia di tutti i contenuti all'interno della sezione <section subscriptions-section="content" encrypted>. Servendosi delle chiavi pubbliche che si trovano negli URL passati allo script, esso procederà alla crittografia della chiave del documento creata dallo script. L'utilizzo di questo script garantisce che tutto il contenuto sia codificato e formattato correttamente per la pubblicazione. Qui sono disponibili ulteriori istruzioni sull'utilizzo di questo script.

Passo 3: integrazione del provider di autorizzazioni

È necessario aggiornare il proprio provider di autorizzazioni per procedere alla decrittografia delle chiavi del documento quando un utente dispone dei diritti richiesti. Il componente amp-subscriptions invia automaticamente la chiave del documento crittografata al sistema di autorizzazione "local" tramite un parametro URL "crypt =". Esso esegue:

  1. L'analisi della chiave del documento dal campo della chiave JSON "local".
  2. La decrittografia dei documenti.

Per decrittografare le chiavi del documento occorre usare Tink nel proprio provider di autorizzazioni. Per eseguire la decrittografia con Tink, occorre creare l'istanza di un client HybridDecrypt utilizzando le chiavi private generate nella sezione Creazione di una coppia di chiavi pubblica/privata. La procedura va applicata all'avvio del server per ottimizzare le prestazioni.

La distribuzione del proprio provider di autorizzazioni/HybridDecrypt deve coincidere all'incirca con le rotazioni delle chiavi previste. Ciò rende tutte le chiavi generate disponibili al client HybridDecrypt.

Tink offre una vasta gamma di documenti ed esempi in C ++, Java, Go e Javascript per facilitare l'implementazione dei sistemi lato server.

Gestione delle richieste

Quando il provider di autorizzazioni riceve una richiesta:

  1. Analizza l'URL di pingback delle credenziali per il parametro "crypt=".
  2. Decodifica il valore del parametro "crypt =" con base64. Il valore memorizzato nel parametro URL è l'oggetto JSON crittografato con codifica base64.
  3. Quando la chiave crittografata è in forma di byte grezzi, usa la funzione di decrittografia di HybridDecrypt per decrittografare la chiave tramite la relativa chiave privata.
  4. Se la decrittografia riesce, analizza il risultato in un oggetto JSON.
  5. Verifica l'accesso dell'utente a uno dei diritti elencati nel campo JSON AccessRequirements.
  6. Restituisce la chiave del documento prelevata dal campo "Key" dell'oggetto JSON decrittografato nella risposta alla verifica dei diritti. Aggiunge la chiave decrittografata del documento in un nuovo campo denominato "decryptedDocumentKey" nella risposta alla verifica dei diritti. Ciò garantisce l'accesso al framework AMP.

L'esempio seguente mostra un frammento di pseudo-codice che riepiloga i passaggi della procedura descrtta sopra:

string decryptDocumentKey(string encryptedKey, List < string > usersEntitlements,
    HybridDecrypt hybridDecrypter) {
    // 1. Decodifica in Base64 la chiave crittografata di input.
    bytes encryptedKeyBytes = base64.decode(encryptedKey);
    // 2. Tenta di decrittografare la chiave.
    bytes decryptedKeyBytes;
    try {
        decryptedKeyBytes = hybridDecrypter.decrypt(
            encryptedKeyBytes, null /* contextInfo */ );
    } catch (error e) {
        // Errore di decrittografia. Gestirlo come necessario.
        LOG("Errore durante la decrittografia: ", e);
        return "";
    }
    // 3. Analizza il testo decrittografato in un oggetto JSON.
    string decryptedKey = new string(decryptedKeyBytes, UTF_8);
    json::object decryptedParsedJson = JsonParser.parse(decryptedKey);
    // 4. Controlla se l'utente che ha inviato la richiesta dispone dei diritti
    // indicati nella sezione AccessRequirements dell'oggetto JSON.
    for (entitlement in usersEntitlements) {
        if (decryptedParsedJson["AccessRequirements"]
            .contains(entitlement)) {
            // 5. Restituisce la chiave del documento se l'utente ha i diritti.
            return decryptedParsedJson["Key"];
        }
    }
    // Se l'utente non ha le credenziali richieste, restituisce stringa vuota.
    return "";
}

JsonResponse getEntitlements(string requestUri) {
    // Qui esegue la normale gestione dei diritti…
    List < string > usersEntitlements = getUsersEntitlementInfo();

    // Controlla se l'URI della richiesta URI ha il parametero "crypt".
    String documentCrypt = requestUri.getQueryParameters().getFirst("crypt");

    // Se URI ha param."crypt", prova a decrittografarlo.
    string documentKey;
    if (documentCrypt != null) {
        documentKey = decryptDocumentKey(
            documentCrypt,
            usersEntitlements,
            this.hybridDecrypter_);
    }

    // Costruisce risposta JSON.
    JsonResponse response = JsonResponse {
        signedEntitlements: getSignedEntitlements(),
        isReadyToPay: getIsReadyToPay(),
    };
    if (!documentKey.empty()) {
        response.decryptedDocumentKey = documentKey;
    }
    return response;
}

Risorse correlate

Consultare la documentazione e gli esempi disponibili nella pagina Github Tink.

Tutti gli script di supporto si trovano nell'archivio Github subscriptions-project / encryption.

Ulteriore supporto

In caso di dubbi, domande o commenti, inviaci una segnalazione GitHub.