Hari ini kami ada di Product Hunt! Tulis komentar

Authenticator 1.16.0 sudah tersedia. Lihat yang baru

Cara kerjanya

Tinjauan teknis untuk peninjau keamanan. Semua di sini dapat dicocokkan dengan kode sumber — termasuk bagian yang kurang menguntungkan kami, yang kami sebutkan alih-alih kami hilangkan.

Arsitektur

Ekstensi ini adalah ekstensi Chrome Manifest V3 yang membuat kode TOTP secara lokal dengan OTPAuth. Pembuatan kode, penyimpanan akun, dan enkripsinya tidak melibatkan backend apa pun, dan tidak ada akun pengguna. Kami menjalankan satu server, api.authenticator.sh, untuk paket gratis dan Pro — dijelaskan di bawah — dan server itu tidak pernah menerima rahasia, nama akun, penerbit, atau kode.

Server itu tidak menyimpan material kunci untuk akun siapa pun: tidak ada penitipan kunci dan tidak ada jalur pemulihan yang kami kendalikan. Jika pengguna lupa kata sandi dan kehilangan kode pemulihannya, kami tidak bisa membantu — memang dirancang begitu.

Kriptografi

Perlindungan kata sandi bersifat opsional dan mati secara bawaan. Saat dinyalakan:

Sandi
AES-256-GCM, IV acak 96-bit untuk tiap catatan dan tiap penulisan ulang
Derivasi kunci
PBKDF2-HMAC-SHA256, 600.000 iterasi, salt acak 128-bit (sesuai panduan OWASP)
Kunci utama
256-bit, dari crypto.getRandomValues, dibuat sekali; kata sandi hanya membungkusnya
Sidik jari
HMAC-SHA256 dengan subkunci turunan HKDF, dipakai untuk menggabungkan catatan antarperangkat
Penyimpanan kunci yang terbuka
chrome.storage.session — hanya di memori, tidak pernah ditulis ke disk, dihapus saat peramban ditutup, dan tak terjangkau oleh content script
Kunci otomatis
Setiap kali dibuka / setelah 5, 15, atau 60 menit tanpa aktivitas / sampai peramban ditutup
Implementasi
Hanya WebCrypto. Tidak ada primitif yang ditulis sendiri dan tidak ada pustaka kripto yang disertakan.

Mengapa kuncinya dua lapis

Data tidak pernah dienkripsi langsung dengan kunci turunan kata sandi. Catatan dienkripsi oleh kunci utama acak; keluaran PBKDF2 hanya membungkus kunci utama itu. Ada dua akibatnya, dan keduanya penting:

  • Mengganti kata sandi menulis ulang 32 byte, bukan mengenkripsi ulang setiap catatan, setiap cadangan, dan setiap ekspor. Justru pada penulisan ulang massal seperti itulah sistem penyimpanan kehilangan data.
  • Kode pemulihan 160-bit dapat membungkus kunci utama yang sama secara terpisah, jadi kata sandi yang terlupa masih bisa dipulihkan. Kode ditampilkan sekali, harus diketik ulang untuk konfirmasi, dan diganti setiap kali dipakai. Tidak ada yang ditulis ke disk sebelum pengguna mengonfirmasinya.

Apa yang dienkripsi dan apa yang tidak

Dengan perlindungan kata sandi aktif, seluruh catatan akun dienkripsi kecuali pengenal dan sidik jarinya — termasuk nama layanannya, sehingga profil yang dicuri tidak membocorkan di layanan mana saja pengguna punya akun. Saat diaktifkan, ekstensi mengenkripsi catatan, memverifikasinya dengan mendekripsi dan membandingkan, lalu barulah menghapus semua salinan teks biasa: penyimpanan lokal peramban, sinkronisasi, dan ketujuh snapshot cadangan bergilir.

Kami sebutkan terus terang, karena ini memengaruhi penilaian Anda:

  • Tanpa perlindungan kata sandi, akun disimpan tanpa enkripsi dan, jika Chrome Sync menyala, direplikasi lewat akun Google pengguna sendiri. Data itu tidak pernah sampai ke kami, tetapi ada pada Google. Sinkronisasi bisa dimatikan, dan itu sekaligus menghapus yang sudah ada di sana.
  • Riwayat penggunaan per situs — akun mana dipakai di domain mana — disimpan secara lokal dan tidak tercakup brankas selama masih dikumpulkan. Mengaktifkan perlindungan kata sandi menghapusnya; riwayat ini juga bisa dimatikan sendiri.

Model ancaman

Melindungi dari

  • Direktori profil peramban yang dicuri atau disalin
  • Malware infostealer yang menyedot data peramban sekaligus
  • Orang dengan akses fisik ke komputer yang ditinggal tanpa pengawasan
  • Catatan akun yang sampai ke Google lewat Chrome Sync
  • Berkas cadangan yang hilang atau dicuri (ekspor berproteksi kata sandi)

Tidak melindungi dari

  • Malware yang berjalan sebagai pengguna saat brankas sedang terbuka
  • Keylogger yang menangkap kata sandi ketika diketik
  • Peramban atau sistem operasi yang sudah disusupi
  • Pembobolan layanan pihak ketiga yang kodenya dipakai
  • Ekspor tanpa enkripsi yang Anda pilih untuk ditulis — JSON biasa, tautan otpauth://, atau CXF bisa dibaca siapa pun yang membuka berkasnya

Singkatnya: ini melindungi data saat tersimpan. Ia tidak, dan tidak bisa, menjaga perangkat yang saat dipakai sudah berada dalam kendali penyerang.

Izin

Manifes mendeklarasikan lima izin dan tidak ada izin host:

storage
Akun dan pengaturan di penyimpanan lokal, kunci yang terbuka di penyimpanan sesi, serta salinan sinkronisasi opsional
activeTab
Membaca nama host tab aktif untuk menyorot akun yang cocok, dan menangkap tab saat pengguna memindai kode QR dari layar
contextMenus
Menambahkan item “Sisipkan kode 2FA” ke menu klik kanan, dan hanya pada kolom yang bisa diedit di halaman http(s)
scripting
Menyuntikkan satu fungsi yang menaruh kode ke dalam kolom — untuk satu tab dan satu pemanggilan saja, hanya setelah item menu itu dipilih
sidePanel
Membuka aplikasi di panel samping Chrome bila itu yang dipilih; ini tidak memberi akses ke halaman mana pun

Tidak ada Tidak ada content script, tidak ada izin tabs, cookies, atau webRequest, dan tidak ada web-accessible resources. Tidak ada milik kami yang berada di sebuah halaman sampai Anda meminta kode di sana; yang berjalan saat itu disuntikkan untuk satu tab dan satu pemanggilan itu saja, di bawah izin yang diberikan klik Anda sendiri, dan tidak meninggalkan apa pun.

Kamera

Pemindaian QR dengan kamera berjalan di halaman ekstensi yang dibuka dalam tab, bukan di popup — popup dimusnahkan begitu kehilangan fokus, dan permintaan izin melakukan persis itu. Untuk ini tidak perlu izin apa pun di manifes: yang dipakai adalah permintaan kamera bawaan peramban, diberikan per origin ekstensi dan bisa dicabut di setelan situs, dan tidak pernah muncul sebelum pengguna membuka pemindai. Video didekode secara lokal dan tidak pernah dikirim atau disimpan.

Paket gratis, Pro, dan check-in harian

Sejak 1.14.0 ekstensi menghubungi api.authenticator.sh sekali sehari — saat peramban dimulai, atau setelah popup selesai ditampilkan, dan tidak pernah menjadi bagian dari proses menampilkan kode. Permintaannya berupa daftar field yang tertutup, disusun dalam satu fungsi di src/billing/sync.ts dan dijaga tetap pada daftar itu oleh sebuah pengujian:

iid
ID acak yang dibuat oleh instalasi ini. Tidak terkait dengan akun Google, alamat email, maupun peramban — kecuali pengguna membeli Pro: catatan pembelian lalu mengaitkan instalasi tempat pembelian dilakukan, dan setiap instalasi tempat kunci lisensinya aktif, dengan alamat email yang dipakai untuk membayar
ver, ui_lang, browser_lang
Versi ekstensi, bahasa antarmuka, bahasa peramban
installed_at, legacy, legacy_src
Kapan instalasi itu muncul, dan apakah sudah ada sebelum penagihan diperkenalkan
accounts, groups
Berapa banyak akun yang disimpannya dan dalam berapa grup — hanya angka, tidak pernah akun yang mana atau nama grupnya
vault, sync, open_mode, view_mode, style, dark, os
Apakah perlindungan kata sandi dan sinkronisasi aktif, dan bagaimana ekstensi dibuka, bagaimana daftar akun ditampilkan (normal, ringkas, atau dengan kode tersembunyi), serta gaya yang dipakai, terang atau gelap, serta sistem operasinya (Windows, macOS, Linux, ChromeOS)
pid, lid, has_key, key_hint
Kebijakan dan lisensi bertanda tangan mana yang sedang dipegang instalasi, apakah kunci lisensinya sudah ada, dan empat karakter terakhir kunci itu
opens
Berapa kali ekstensi dibuka pada setiap hari sejak permintaan harian terakhir (paling banyak 14 hari terakhir) — satu hitungan per hari, tanpa apa pun tentang apa yang dilihat
events
Peristiwa penagihan yang mengantre, dari daftar tertutup: batas tercapai, paywall ditampilkan atau ditutup, sebuah paket dipilih, checkout atau kunci dicoba

Tidak pernah dikirim: rahasia, nama akun, penerbit, kode, atau situs tempat semua itu dipakai. Server mengambil negara dari permintaan di edge-nya dan tidak menyimpan alamat IP. Halaman pencopotan menerima ID instalasi yang sama sebagai ?i=: halaman itu memberi tahu server bahwa instalasi telah dicopot, dan mengaitkan jawaban survei yang opsional dengan instalasinya.

Yang disimpan di chrome.storage.local untuk keperluan ini: ID instalasi, kebijakan dan lisensi bertanda tangan terakhir, kunci lisensi yang dipegang instalasi ini (diketik, atau diterima setelah membeli di instalasi ini), jumlah pembukaan per hari sampai server menerimanya, serta peristiwa yang mengantre — tanpa data akun. Selama sinkronisasi aktif, keterangan apakah instalasi sudah ada sebelum penagihan dan kunci lisensi itu juga masuk ke Chrome Sync, sehingga profil Chrome pengguna yang lain ikut mendapatkannya dan menyalakan Pro sendiri; mematikan sinkronisasi menghapus keduanya dari Chrome Sync, dan menyalakannya lagi mengembalikannya.

Apa yang dikembalikan, dan bagaimana ekstensi memperlakukannya:

Token
Kebijakan (batas akun paket gratis) dan lisensi (Pro) berupa JWS yang ditandatangani dengan ES256 (ECDSA P-256)
Verifikasi
WebCrypto, terhadap kunci publik yang dikompilasi ke dalam build (src/billing/keys.ts). Build Chrome Web Store hanya memercayai kunci produksi, dan pemeriksaan build menolak build yang membawa kunci lain
Luring
Batas dan lisensi diperiksa secara lokal, dari token bertanda tangan terakhir. Selama belum ada kebijakan bertanda tangan yang diterima, tidak ada yang dibatasi — server yang tak terjangkau tidak akan pernah bisa mengunci siapa pun
Yang bisa dilakukan batas
Mencegah akun ditambahkan, dan tidak lebih. Batas tidak bisa menyembunyikan, mengunci, menghapus, atau mengubah akun, maupun memblokir kode, ekspor, cadangan, pemulihan, atau sinkronisasi
Pembelian
Stripe Checkout di tab baru, dengan Link sebagai merchant of record. Email pembeli sampai ke kami dari Stripe, untuk menerbitkan dan memulihkan kunci lisensi; kunci disimpan sebagai hash, ditambah salinan terenkripsi agar kunci yang hilang bisa dikirim lagi
Kunci lisensi
Jawaban atas permintaan harian membawa kuncinya sendiri hanya ke instalasi tempat Pro dibeli, dan hanya sampai empat karakter yang dilaporkannya di key_hint cocok dengan kunci itu — jadi kunci yang dibeli belakangan menggantikan kunci yang lebih lama; instalasi tempat kunci diketik tidak pernah dikirimi kunci

Batas ini bukan DRM: kodenya sumber terbuka, dan sebuah fork bisa menghapusnya. Yang tidak boleh pernah mungkin adalah seseorang memperoleh atau memakai lisensi milik orang lain, atau membuat instalasi orang lain menjadi terbatas — itu kerentanan, dan termasuk dalam cakupan kebijakan keamanan kami.

Lalu lintas jaringan keluar

Dua jenis permintaan dibuat ekstensi atas inisiatifnya sendiri: pemeriksaan jam dan check-in penagihan harian. Sisanya di bawah ini terjadi karena pengguna mengeklik sesuatu. Manifest V3 melarang kode jarak jauh, dan tak satu pun di sini membawa akun, kunci rahasia, atau kode yang dihasilkan. Daftar lengkapnya:

HostKapanMembawa data pengguna?
time.akamai.com
timeapi.io
cloudflare.com
Pemeriksaan selisih jam, di-cache; kalau tidak ada sumber yang bisa dihubungi, Pengaturan menyebutkannya. TOTP rusak kalau jam melenceng.Tidak
authenticator.shHalaman sambutan saat pemasangan; halaman masukan saat pencopotan, dengan ID instalasi di alamatnya; halaman bantuan dan dukungan bila dibuka dari popup.ID instalasi, hanya di halaman pencopotan; selain itu tidak (log server web biasa)
api.authenticator.shCheck-in penagihan sekali sehari; panggilan checkout, lisensi, dan portal saat pengguna membeli Pro, memasukkan kunci, memulihkan pembelian, atau mengelola langganan.Field yang tercantum di atas — tidak pernah data akun. Kunci lisensi atau alamat email hanya bila pengguna mengetiknya sendiri
checkout.stripe.com
billing.stripe.com
Stripe Checkout dan portal pelanggan, dibuka di tab saat pengguna membeli Pro atau mengelola langganan.Apa yang dimasukkan pembeli di sana. Berlaku ketentuan Stripe dan Link sendiri
chromewebstore.google.comHalaman toko, dibuka di tab baru hanya saat diklik: formulir ulasan dari ajakan memberi nilai.Tidak (bagi Google ini kunjungan ke halaman toko seperti yang lain)

Tidak ada font, skrip, gaya, atau gambar yang dimuat dari host pihak ketiga. Semua yang dibutuhkan untuk menggambar antarmuka sudah ada di dalam paket.

Memverifikasi apa yang kami publikasikan

Anda tidak perlu memercayai satu pun hal di atas begitu saja. Ekstensi ini sumber terbuka, dan setiap rilis dapat direproduksi:

  1. Unduh .crx yang dipublikasikan dari Chrome Web Store lalu ekstrak
  2. Checkout tag git yang sesuai
  3. Jalankan npm ci && npm run build di Node 20 LTS
  4. Bandingkan dist/ yang dihasilkan dengan paket yang diekstrak

SHA-256 untuk setiap berkas di dalam dist/ hasil build dipublikasikan pada setiap rilis GitHub sebagai SHA256SUMS-v<version>.txt, dalam format sha256sum, sehingga langkah 4 cukup satu kali menjalankan sha256sum -c. Perbedaan seharusnya terbatas pada urutan berkas di dalam arsip dan spasi pada keluaran terminifikasi antarversi patch Node.

Dependensi runtime sengaja sedikit — OTPAuth, React, jsQR, Zustand, Framer Motion, dan Lucide — dikunci oleh lockfile yang ikut di-commit. SBOM CycloneDX tersedia atas permintaan.

Baca kode sumbernya

Yang tidak kami punya

Kami vendor kecil dan independen. Jika salah satu hal berikut adalah syarat mutlak dalam proses Anda, lebih baik tahu sekarang daripada tiga minggu setelah evaluasi berjalan:

  • Tidak ada sertifikasi SOC 2, ISO 27001, atau yang setara
  • Belum pernah memesan uji penetrasi pihak ketiga sampai hari ini
  • Tidak ada program bug bounty berbayar

Sebagai gantinya kami menawarkan keterbukaan penuh kode sumber, build yang dapat diverifikasi, permukaan izin yang minimal, dan server yang sejak awal memang tidak pernah dikirimi rahasia, nama akun, atau kode Anda.

Menghubungi kami

Laporan kerentanan dan pertanyaan keamanan: security@authenticator.sh. Kebijakan pengungkapan, cakupan, waktu tanggap, dan ketentuan safe harbour ada di halaman kebijakan keamanan; apa yang disimpan dan apa yang keluar dari perangkat dijelaskan di kebijakan privasi.

Dengan senang hati kami mengisi kuesioner penilaian vendor tertulis atau menelusuri kode bersama tim keamanan Anda.

Untuk hal apa pun yang bukan soal keamanan — pemasangan, pemulihan akun, pertanyaan penagihan dari sebuah penerapan — lihat dukungan. Mohon jangan mengirim laporan kerentanan ke sana; kotak masuk itu tidak diperlakukan sebagai rahasia.