Bermigrasi ke Petunjuk Klien Agen Pengguna

Strategi untuk memigrasikan situs Anda dari mengandalkan string agen pengguna ke Client Hints Agen Pengguna baru.

String Agen Pengguna adalah platform pelacakan sidik jari pasif yang signifikan di browser, serta sulit diproses. Namun, ada berbagai alasan yang valid untuk mengumpulkan dan memproses data agen pengguna, sehingga yang diperlukan adalah jalur menuju solusi yang lebih baik. User-Agent Client Hints memberikan cara eksplisit untuk mendeklarasikan kebutuhan Anda akan data dan metode user-agent untuk menampilkan data dalam format yang mudah digunakan.

Artikel ini akan memandu Anda mengaudit akses ke data agen pengguna dan memigrasikan penggunaan string agen pengguna ke Client Hints Agen Pengguna.

Mengaudit pengumpulan dan penggunaan data agen pengguna

Seperti halnya bentuk pengumpulan data apa pun, Anda harus selalu memahami alasan Anda mengumpulkannya. Langkah pertama, terlepas dari apakah Anda akan mengambil tindakan atau tidak, adalah memahami tempat dan alasan Anda menggunakan data agen pengguna.

Jika Anda tidak tahu apakah atau di mana data agen pengguna digunakan, pertimbangkan untuk menelusuri kode frontend Anda untuk penggunaan navigator.userAgent dan kode backend Anda untuk penggunaan header HTTP User-Agent. Anda juga harus memeriksa kode frontend untuk mengetahui penggunaan fitur yang sudah tidak digunakan lagi, seperti navigator.platform dan navigator.appVersion.

Dari sudut pandang fungsional, pikirkan di mana pun dalam kode Anda saat Anda mencatat atau memproses:

  • Nama atau versi browser
  • Nama atau versi sistem operasi
  • Merek atau model perangkat
  • Jenis, arsitektur, atau bit CPU (misalnya, 64-bit)

Anda mungkin juga menggunakan library atau layanan pihak ketiga untuk memproses agen pengguna. Dalam hal ini, periksa apakah browser tersebut diupdate untuk mendukung Client Hints Agen Pengguna.

Apakah Anda hanya menggunakan data agen pengguna dasar?

Kumpulan default Petunjuk Klien Agen Pengguna mencakup:

  • Sec-CH-UA: nama browser dan versi utama/signifikan
  • Sec-CH-UA-Mobile: nilai boolean yang menunjukkan perangkat seluler
  • Sec-CH-UA-Platform: nama sistem operasi
    • Perhatikan bahwa hal ini telah diperbarui dalam spesifikasi dan akan ditampilkan di Chrome dan browser berbasis Chromium lainnya dalam waktu dekat.

Versi string agen pengguna yang dikurangi yang diusulkan juga akan mempertahankan informasi dasar ini dengan cara yang kompatibel dengan versi sebelumnya. Misalnya, string akan menyertakan Chrome/90.0.0.0, bukan Chrome/90.0.4430.85.

Jika Anda hanya memeriksa string agen pengguna untuk nama browser, versi utama, atau sistem operasi, kode Anda akan terus berfungsi meskipun Anda mungkin melihat peringatan penghentian.

Meskipun Anda dapat dan harus bermigrasi ke Client Hints Agen Pengguna, Anda mungkin memiliki kode atau batasan resource lama yang mencegah hal ini. Pengurangan informasi dalam string agen pengguna dengan cara yang kompatibel dengan versi sebelumnya ini dimaksudkan untuk memastikan bahwa meskipun kode yang ada akan menerima informasi yang kurang mendetail, kode tersebut masih harus mempertahankan fungsi dasar.

Strategi: JavaScript API sisi klien on demand

Jika saat ini Anda menggunakan navigator.userAgent, Anda harus bertransisi untuk memilih navigator.userAgentData sebelum kembali mengurai string agen pengguna.

if (navigator.userAgentData) {
  // use new hints
} else {
  // fall back to user-agent string parsing
}

Jika Anda memeriksa perangkat seluler atau desktop, gunakan nilai boolean mobile:

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands adalah array objek dengan properti brand dan version tempat browser dapat mencantumkan kompatibilitasnya dengan merek tersebut. Anda dapat mengaksesnya langsung sebagai array atau Anda dapat menggunakan panggilan some() untuk memeriksa apakah entri tertentu ada:

function isCompatible(item) {
  // In real life you most likely have more complex rules here
  return ['Chromium', 'Google Chrome', 'NewBrowser'].includes(item.brand);
}
if (navigator.userAgentData.brands.some(isCompatible)) {
  // browser reports as compatible
}

Jika memerlukan salah satu nilai agen pengguna dengan entropi tinggi yang lebih mendetail, Anda harus menentukannya dan memeriksa hasilnya di Promise yang ditampilkan:

navigator.userAgentData.getHighEntropyValues(['model'])
  .then(ua => {
    // requested hints available as attributes
    const model = ua.model
  });

Anda juga dapat menggunakan strategi ini jika ingin beralih dari pemrosesan sisi server ke pemrosesan sisi klien. JavaScript API tidak memerlukan akses ke header permintaan HTTP, sehingga nilai agen pengguna dapat diminta kapan saja.

Strategi: Header sisi server statis

Jika Anda menggunakan header permintaan User-Agent di server dan kebutuhan Anda untuk data tersebut relatif konsisten di seluruh situs, Anda dapat menentukan petunjuk klien yang diinginkan sebagai kumpulan statis dalam respons. Ini adalah pendekatan yang relatif sederhana karena Anda biasanya hanya perlu mengonfigurasinya di satu lokasi. Misalnya, header tersebut mungkin ada di konfigurasi server web jika Anda sudah menambahkan header di sana, konfigurasi hosting, atau konfigurasi tingkat teratas framework atau platform yang Anda gunakan untuk situs Anda.

Pertimbangkan strategi ini jika Anda mengubah atau menyesuaikan respons yang ditayangkan berdasarkan data agen pengguna.

Browser atau klien lain dapat memilih untuk memberikan petunjuk default yang berbeda, jadi sebaiknya tentukan semua yang Anda butuhkan, meskipun umumnya disediakan secara default.

Misalnya, setelan default saat ini untuk Chrome akan direpresentasikan sebagai:

⬇️ Header respons

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

Jika Anda juga ingin menerima model perangkat dalam respons, Anda akan mengirim:

⬇️ Header respons

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA

Saat memprosesnya di sisi server, Anda harus memeriksa terlebih dahulu apakah header Sec-CH-UA yang diinginkan telah dikirim, lalu kembali ke penguraian header User-Agent jika tidak tersedia.

Strategi: Mendelegasikan petunjuk ke permintaan lintas origin

Jika Anda meminta sub-resource lintas origin atau lintas situs yang memerlukan Client Hints Agen Pengguna untuk dikirim pada permintaannya, Anda harus menentukan petunjuk yang diinginkan secara eksplisit menggunakan Kebijakan Izin.

Misalnya, https://blog.site menghosting resource di https://cdn.site yang dapat menampilkan resource yang dioptimalkan untuk perangkat tertentu. https://blog.site dapat meminta petunjuk Sec-CH-UA-Model, tetapi harus mendelegasikannya secara eksplisit ke https://cdn.site menggunakan header Permissions-Policy. Daftar petunjuk yang dikontrol kebijakan tersedia di draf Infrastruktur Client Hints

⬇️ Respons dari blog.site yang mendelegasikan petunjuk

Accept-CH: Sec-CH-UA-Model
Permissions-Policy: ch-ua-model=(self "https://cdn.site")

⬆️ Permintaan ke subresource di cdn.site menyertakan petunjuk yang didelegasikan

Sec-CH-UA-Model: "Pixel 5"

Anda dapat menentukan beberapa petunjuk untuk beberapa origin, dan bukan hanya dari rentang ch-ua:

⬇️ Respons dari blog.site yang mendelegasikan beberapa petunjuk ke beberapa origin

Accept-CH: Sec-CH-UA-Model, DPR
Permissions-Policy: ch-ua-model=(self "https://cdn.site"),
                    ch-dpr=(self "https://cdn.site" "https://img.site")

Strategi: Mendelegasikan petunjuk ke iframe

Iframe lintas origin berfungsi dengan cara yang mirip dengan resource lintas origin, tetapi Anda menentukan petunjuk yang ingin didelegasikan dalam atribut allow.

⬇️ Respons dari blog.site

Accept-CH: Sec-CH-UA-Model

↪️ HTML untuk blog.site

<iframe src="https://widget.site" allow="ch-ua-model"></iframe>

⬆️ Permintaan ke widget.site

Sec-CH-UA-Model: "Pixel 5"

Atribut allow di iframe akan mengganti header Accept-CH apa pun yang dapat dikirim oleh widget.site, jadi pastikan Anda telah menentukan semua yang diperlukan situs iframe.

Strategi: Petunjuk sisi server dinamis

Jika Anda memiliki bagian tertentu dari perjalanan pengguna yang memerlukan lebih banyak pilihan petunjuk daripada di seluruh situs, Anda dapat memilih untuk meminta petunjuk tersebut sesuai permintaan, bukan secara statis di seluruh situs. Hal ini lebih rumit untuk dikelola, tetapi jika Anda sudah menetapkan header yang berbeda berdasarkan per rute, hal ini mungkin dapat dilakukan.

Hal penting yang harus diingat di sini adalah setiap instance header Accept-CH akan secara efektif menimpa kumpulan yang ada. Jadi, jika Anda menetapkan header secara dinamis, setiap halaman harus meminta kumpulan petunjuk lengkap yang diperlukan.

Misalnya, Anda mungkin memiliki satu bagian di situs tempat Anda ingin menyediakan ikon dan kontrol yang cocok dengan sistem operasi pengguna. Untuk itu, Anda mungkin ingin menarik Sec-CH-UA-Platform-Version secara tambahan untuk menayangkan subresource yang sesuai.

⬇️ Header respons untuk /blog

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

⬇️ Header respons untuk /app

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA

Strategi: Petunjuk sisi server diperlukan pada permintaan pertama

Mungkin ada kasus saat Anda memerlukan lebih dari kumpulan petunjuk default pada permintaan pertama, tetapi hal ini mungkin jarang terjadi, jadi pastikan Anda telah meninjau alasannya.

Permintaan pertama benar-benar berarti permintaan tingkat teratas pertama untuk origin tersebut yang dikirim dalam sesi penjelajahan tersebut. Kumpulan petunjuk default mencakup nama browser dengan versi utama, platform, dan indikator seluler. Jadi, pertanyaan yang harus diajukan di sini adalah, apakah Anda memerlukan data yang diperluas pada pemuatan halaman awal?

Untuk petunjuk tambahan pada permintaan pertama, ada dua opsi. Pertama, Anda dapat menggunakan header Critical-CH. Ini menggunakan format yang sama dengan Accept-CH, tetapi memberi tahu browser bahwa browser harus segera mencoba ulang permintaan jika permintaan pertama dikirim tanpa petunjuk penting.

⬆️ Permintaan awal

[With default headers]

⬇️ Header respons

Accept-CH: Sec-CH-UA-Model
Critical-CH: Sec-CH-UA-Model

🔃 Browser mencoba ulang permintaan awal dengan header tambahan

[With default headers + …]
Sec-CH-UA-Model: Pixel 5

Hal ini akan menimbulkan overhead percobaan ulang pada permintaan pertama, tetapi biaya penerapannya relatif rendah. Kirim header tambahan dan browser akan melakukan sisanya.

Untuk situasi saat Anda benar-benar memerlukan petunjuk tambahan pada pemuatan halaman pertama, proposal Keandalan Client Hints akan menyusun rute untuk menentukan petunjuk di setelan tingkat koneksi. Hal ini menggunakan ekstensi Application-Layer Protocol Settings(ALPS) ke TLS 1.3 untuk mengaktifkan penerusan petunjuk awal ini pada koneksi HTTP/2 dan HTTP/3. Hal ini masih dalam tahap yang sangat awal, tetapi jika Anda secara aktif mengelola setelan TLS dan koneksi Anda sendiri, ini adalah waktu yang ideal untuk berkontribusi.

Strategi: Dukungan lama

Anda mungkin memiliki kode lama atau pihak ketiga di situs yang bergantung pada navigator.userAgent, termasuk bagian string agen pengguna yang akan dikurangi. Dalam jangka panjang, Anda harus merencanakan untuk beralih ke panggilan navigator.userAgentData yang setara, tetapi ada solusi sementara.

UA-CH retrofill adalah library kecil yang memungkinkan Anda menimpa navigator.userAgent dengan string baru yang dibuat dari nilai navigator.userAgentData yang diminta.

Misalnya, kode ini akan menghasilkan string agen pengguna yang juga menyertakan petunjuk "model":

import { overrideUserAgentUsingClientHints } from './uach-retrofill.js';
overrideUserAgentUsingClientHints(['model'])
  .then(() => { console.log(navigator.userAgent); });

String yang dihasilkan akan menampilkan model Pixel 5, tetapi masih menampilkan 92.0.0.0 yang dikurangi karena petunjuk uaFullVersion tidak diminta:

Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36

Dukungan lebih lanjut

Jika strategi ini tidak mencakup kasus penggunaan Anda, mulai Diskusi di repo privacy-sandbox-dev-support dan kita dapat mempelajari masalah Anda bersama-sama.

Foto oleh Ricardo Rocha di Unsplash