Aggiungi intestazioni delle richieste HTTP aggiuntive

Le richieste HTTP contengono intestazioni come User-Agent o Content-Type. Oltre alle intestazioni allegate dai browser, le app per Android possono aggiungere intestazioni aggiuntive, come Cookie o Referrer, tramite l'extra Intent EXTRA_HEADERS. Per motivi di sicurezza, Chrome filtra alcune intestazioni aggiuntive a seconda di come e dove viene avviato un intent.

Le richieste multiorigine richiedono un ulteriore livello di sicurezza poiché il client e il server non appartengono alla stessa parte. Questa guida illustra l'avvio di queste richieste tramite le schede personalizzate di Chrome, ovvero intent avviati da app che aprono un URL nella scheda del browser. Fino a Chrome 83, gli sviluppatori potevano aggiungere qualsiasi intestazione all'avvio di una scheda personalizzata. A partire dalla versione 83, Chrome ha iniziato a filtrare tutte le intestazioni multiorigine, ad eccezione di quelle approvelisted, poiché le intestazioni non approvelisted rappresentavano un rischio per la sicurezza. A partire da Chrome 86, è possibile allegare intestazioni non incluse nell'elenco approvato alle richieste multiorigine quando il server e il client sono correlati tramite un link di asset digitali. Questo comportamento è riassunto nella tabella seguente:

Versione di Chrome Intestazioni CORS consentite
prima di Chrome 83 approvelisted, non-approvelisted
Chrome 83 a Chrome 85 approvelisted
A partire da Chrome 86 approvelisted, non-approvelisted quando viene configurato un link all'asset digitale

Tabella 1: Filtro delle intestazioni CORS non incluse nell'elenco approvati.

Questo articolo mostra come configurare una connessione verificata tra il server e il client e come utilizzarla per inviare intestazioni HTTP approvate e non approvate. Puoi passare direttamente alla sezione Aggiunta di intestazioni extra agli intent delle schede personalizzate per il codice.

Sfondo

Intestazioni delle richieste CORS approvelisted e non approvelisted

La condivisione delle risorse tra origini (CORS) consente a un'applicazione web di un'origine di richiedere risorse di un'origine diversa. L'elenco delle intestazioni CORS-approvelisted viene gestito nello standard HTML. Le intestazioni approvelisted di esempio sono riportate nella tabella seguente:

Header Descrizione
accept-language pubblicizza le lingue naturali che il client comprende
content-language descrive il linguaggio destinato al pubblico attuale
content-type indica il tipo di media della risorsa

Tabella 2: Esempio di intestazioni CORS approvate.

Le intestazioni incluse nell'elenco approvato sono considerate sicure perché non contengono informazioni utente sensibili ed è improbabile che il server esegua operazioni potenzialmente dannose.

Nella tabella seguente sono riportati esempi di intestazioni non incluse nell'elenco approvati:

Header Descrizione
bearer-token autentica il client su un server
origine indica l'origine della richiesta
biscotto contiene cookie impostati dal server

Tabella 3: Esempio di intestazioni CORS non incluse nell'elenco approvato.

L'allegato di intestazioni non approvate alle richieste CORS è sconsigliato dallo standard HTML e i server presuppongono che le richieste multiorigine contengano solo intestazioni approvate. L'invio di intestazioni non incluse nell'elenco di approvazione da domini cross-origin consentirebbe ad app di terze parti malintenzionate di creare intestazioni che utilizzano in modo improprio i cookie dell'utente che Chrome (o un altro browser) memorizza e allega alle richieste. I cookie potrebbero autenticare transazioni server dannose che altrimenti non sarebbero possibili.

Allegare intestazioni approvate da CORS alle richieste di schede personalizzate

Le schede personalizzate sono un modo speciale per avviare pagine web in una scheda del browser personalizzata. Gli intent delle schede personalizzate possono essere creati utilizzando CustomTabsIntent.Builder(). Puoi anche allegare intestazioni a questi intent utilizzando Bundle con il flag Browser.EXTRA_HEADERS:

CustomTabsIntent intent = new CustomTabsIntent.Builder(session).build();

Bundle headers = new Bundle();
headers.putString("bearer-token", "Some token");
headers.putString("redirect-url", "Some redirect url");   
intent.intent.putExtra(Browser.EXTRA_HEADERS, headers);

intent.launchUrl(Activity.this, Uri.parse("http://www.google.com"));

Possiamo sempre allegare le intestazioni approvate alle richieste CORS delle schede personalizzate. Tuttavia, Chrome filtra le intestazioni non incluse nell'elenco approvati per impostazione predefinita. Sebbene altri browser possano avere un comportamento diverso, gli sviluppatori devono aspettarsi che le intestazioni non approvate vengano bloccate in generale.

Il modo supportato per includere intestazioni non approvate nelle schede personalizzate è verificare prima la connessione multiorigine utilizzando un link di accesso digitale. La sezione successiva mostra come configurare questi elementi e avviare un intent Schede personalizzate con le intestazioni richieste.

Aggiungere intestazioni aggiuntive agli intent delle schede personalizzate

Per consentire il passaggio di intestazioni non incluse nell'elenco approvato tramite gli intent della scheda personalizzata, è necessario configurare un collegamento di asset digitali tra l'applicazione web e quella Android che verifichi che l'autore sia proprietario di entrambe le applicazioni.

Segui la guida ufficiale per configurare un collegamento alle risorse digitali. Per la relazione tra link, utilizza "delegate_permission/common.use_as_origin", che indica che entrambe le app appartengono alla stessa origine una volta verificato il link.

Crea un intent scheda personalizzata con intestazioni aggiuntive

Esistono diversi modi per creare un intent Schede personalizzate. Puoi utilizzare il builder disponibile in AndroidX aggiungendo la libreria alle dipendenze di build:

implementation 'androidx.browser:browser:1.2.0'

Crea l'intent e aggiungi intestazioni aggiuntive:

CustomTabsIntent constructExtraHeadersIntent(CustomTabsSession session) {
    CustomTabsIntent intent = new CustomTabsIntent.Builder(session).build();

    // Example non-cors-approvelisted headers.
    Bundle headers = new Bundle();
    headers.putString("bearer-token", "Some token");
    headers.putString("redirect-url", "Some redirect url");
    intent.intent.putExtra(Browser.EXTRA_HEADERS, headers);
    return intent;
}

Una connessione Schede personalizzate viene utilizzata per configurare un CustomTabsSession tra l'app e la scheda Chrome. Abbiamo bisogno della sessione per verificare che l'app e l'app web appartengano alla stessa origine. La verifica viene superata solo se i link alle risorse digitali sono stati configurati correttamente.

Ti invitiamo a chiamare il numero CustomTabsClient.warmup(). Consente all'applicazione browser di pre-inizializzarsi in background e velocizzare la procedura di apertura dell'URL.

// Set up a connection that warms up and validates a session.
CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
    @Override
    public void onCustomTabsServiceConnected(@NonNull ComponentName name, 
        @NonNull CustomTabsClient client) {
        // Create session after service connected.
        mSession = client.newSession(callback);
        client.warmup(0);
        // Validate the session as the same origin to allow cross origin headers.
        mSession.validateRelationship(CustomTabsService.RELATION_USE_AS_ORIGIN, 
            Uri.parse(url), null);
    }
    @Override
    public void onServiceDisconnected(ComponentName componentName) { }
};

Configurare un callback che avvii l'intent dopo la convalida

Il CustomTabsCallback è stato passato alla sessione. Abbiamo configurato il relativo onRelationshipValidationResult() per avviare CustomTabsIntent creato in precedenza una volta verificata l'origine.

// Set up a callback that launches the intent after session validated.
CustomTabsCallback callback = new CustomTabsCallback() {
    @Override
    public void onRelationshipValidationResult(int relation, @NonNull Uri requestedOrigin, 
        boolean result, @Nullable Bundle extras) {
        // Launch custom tabs intent after session was validated as the same origin.
        CustomTabsIntent intent = constructExtraHeadersIntent(mSession);
        intent.launchUrl(MainActivity.this, Uri.parse(url));
    }
};

Collega la connessione del servizio delle schede personalizzate

L'associazione del servizio avvia il servizio e alla fine verrà chiamato il onCustomTabsServiceConnected() della connessione. Non dimenticare di dissociare il servizio in modo appropriato. Il binding e l'unbinding vengono eseguiti comunemente nei metodi del ciclo di vita delle attività onStart() e onStop().

// Bind the custom tabs service connection.
// Call this in onStart()
CustomTabsClient.bindCustomTabsService(this,
    CustomTabsClient.getPackageName(MainActivity.this, null), connection);

// …
// Unbind the custom tabs service.
// Call this in onStop().
unbindService(connection);

Codice dell'applicazione demo

Puoi trovare maggiori dettagli sul servizio Schede personalizzate qui. Per un'app di esempio funzionante, consulta il repository GitHub android-browser-helper.

Riepilogo

Questa guida mostra come aggiungere intestazioni arbitrarie alle richieste CORS delle schede personalizzate. Le intestazioni approvate possono essere allegate a ogni richiesta CORS delle schede personalizzate. Le intestazioni non incluse nell'elenco approvato sono generalmente considerate non sicure nelle richieste CORS e Chrome le filtra per impostazione predefinita. L'allegato è consentito solo per client e server della stessa origine, verificati da un collegamento asset digitale.