Come rilevare il browser Brave sul vostro sito
4 aprile 2020
Guybrush Threepwood
di Guybrush Threepwood

Come sappiamo bene, Brave, e in generale tutta la community a esso afferente, è molto attento al concetto di privacy durante la navigazione.

Dal punto di vista del webmaster, però, a volte è anche utile sapere che tipo di browser sta utilizzando il visitatore per poter proporre features particolari. Nel caso di Brave per esempio potrebbe essere utile rilevare se l'utente può, grazie al supporto integrato di Basic Attention Token, donare qualche token alla vostra causa, e quindi visualizzare una call to action o un pulsante "DONA BAT".

In questo articolo vedremo come, utilizzando una semplice tecnica di reverse engineering (neanche tanto approfondito) del codice open source di Brave, possiamo rilevare se il browser che sta visualizzando le vostre pagine è effettivamente Brave.

Generalmente per discriminare quale browser è in uso da un visitatore dei nostri siti, è sufficiente controllare l'header User-Agent del protocollo HTTP.

Ad esempio, nel vostro caso, la stringa User-Agent che il browser espone è

Se state usando Brave Browser vi renderete subito conto che la stringa User-Agent che viene inviata al web server è indistinguibile da quella di Chrome!

Brave, esattamente come Google Chrome, si basa interamente sul codice di Chromium, un web browser completamente libero e open source.

Per caso un giorno sono andato a controllare nella console di sviluppo di Brave quale fosse la stringa User-Agent che il browser invia, e mi sono accorto di uno strano comportamento.

Se il sito visitato è il motore di ricerca DuckDuckGo (valida alternativa a Google) la stringa inviata è leggermente diversa da quella inviata agli altri siti!

In questo caso, compare il nome "Brave" proprio lì, in bella vista!
Sono andato allora sul repository ufficiale del browser all'indirizzo https://github.com/brave/brave-core e ho semplicemente cercato la stringa "duckduckgo".

https://github.com/brave/brave-core/search?q=duckduckgo

Nella moltitudine dei risultati mi colpisce subito il file

/common/shield_exceptions.cc

All'interno del quale troviamo questa funzione:

bool IsUAWhitelisted(const GURL& gurl) {
  static std::vector<URLPattern> whitelist_patterns({
    URLPattern(URLPattern::SCHEME_ALL, "https://*.adobe.com/*"),
    URLPattern(URLPattern::SCHEME_ALL, "https://*.duckduckgo.com/*"),
    URLPattern(URLPattern::SCHEME_ALL, "https://*.brave.com/*"),
    // For Widevine
    URLPattern(URLPattern::SCHEME_ALL, "https://*.netflix.com/*")
  });
  return std::any_of(whitelist_patterns.begin(), whitelist_patterns.end(),
      [&gurl](URLPattern pattern){
        return pattern.MatchesURL(gurl);
      });
}

IsUAWhitelisted() mi fa pensare subito a "Is User Agent Whitelisted?", quindi subito provo ad andare anche su adobe.com e netflix.com e mi accorgo che effettivamente quando visito questi siti l'header User-Agent è diverso!

A questo punto voglio vedere dove è usata la funzione IsUAWhitelisted e quindi eseguo una nuova ricerca:

https://github.com/brave/brave-core/search?q=IsUAWhitelisted

E mi accorgo che è usata una volta sola nel file:

/common/shield_exceptions.cc

In questo modo:

https://github.com/brave/brave-core/blob/7a728838c72ca645207b46a294ad5a748b731bc6/browser/net/brave_site_hacks_network_delegate_helper.cc#L128-L146

int OnBeforeStartTransaction_SiteHacksWork(
    net::HttpRequestHeaders* headers,
    const ResponseCallback& next_callback,
    std::shared_ptr<BraveRequestInfo> ctx) {

  // Se il sito visitato è nella white list
  if (IsUAWhitelisted(ctx->request_url)) {
    std::string user_agent;
    if (headers->GetHeader(kUserAgentHeader, &user_agent)) {
      if (std::string::npos == user_agent.find("Brave")) {

        // //////////////////////////////////////////
        // Qui lo User-Agent viene modificato!
        // //////////////////////////////////////////
        base::ReplaceFirstSubstringAfterOffset(&user_agent, 0,
          "Chrome", "Brave Chrome");


        headers->SetHeader(kUserAgentHeader, user_agent);
        ctx->set_headers.insert(kUserAgentHeader);
      }
    }
  }
  return net::OK;
}

In sostanza, se il sito che si sta visitando è nella white list, (cioè se il risultato della funzione IsUAWhitelisted è true) la stringa "Chrome" all'interno dell'header User-Agent viene sostituito con la stringa "Brave Chrome", rivelando così la vera natura del nostro software!

E ora come facciamo all'interno del nostro sito, che NON è all'interno della white list a capire se il browser in questione è Brave?

DuckDuckGo, in quanto motore di ricerca, mette a disposizione delle API ( https://duckduckgo.com/api) da usare gratuitamente con Ajax e in particolare risponde in maniera abbastanza esaustiva alla domanda:

"What's my user agent?"

https://api.duckduckgo.com/?q=whats+my+user+agent&format=json&pretty=1

Come potete vedere la risposta ci aiuta!

A questo punto sarà sufficiente inviare una richiesta in Ajax dal vostro sito verso questa API di DuckDuckGo e se la risposta (il campo Answer) contiene la stringa Brave, il gioco è fatto!