Bugün Product Hunt'tayız! Yorum bırakın

Authenticator 1.16.0 yayınlandı. Yenilikleri gör

Nasıl çalışır

Güvenlik incelemesi yapanlar için teknik bir genel bakış. Buradaki her şey kaynak kodla doğrulanabilir — bizi daha az parlak gösteren kısımlar dahil; onları atlamak yerine açıkça yazıyoruz.

Mimari

Uzantı, TOTP kodlarını OTPAuth ile yerel olarak üreten bir Manifest V3 Chrome uzantısıdır. Kod üretmek, hesapları saklamak ve onları şifrelemek hiçbir arka uca dayanmaz; kullanıcı hesabı da yoktur. Ücretsiz plan ve Pro için tek bir sunucu işletiyoruz — aşağıda anlatılan api.authenticator.sh — ve bu sunucu hiçbir zaman bir gizli anahtar, hesap adı, hizmet adı (issuer) ya da kod almaz.

Bu sunucu kimsenin hesapları için anahtar malzemesi tutmaz: anahtar emaneti ya da bizim denetimimizdeki bir kurtarma yolu yoktur. Bir kullanıcı parolasını unutur ve kurtarma kodunu kaybederse yardımcı olamayız — bu tasarım gereği böyle.

Kriptografi

Parola koruması isteğe bağlıdır ve varsayılan olarak kapalıdır. Açıkken:

Şifre
AES-256-GCM, her kayıt ve her yeniden yazma için rastgele 96 bitlik IV
Anahtar türetme
PBKDF2-HMAC-SHA256, 600.000 yineleme, rastgele 128 bitlik tuz (OWASP önerisi)
Ana anahtar
256 bit, crypto.getRandomValues ile bir kez üretilir; parola yalnızca onu sarmalar
Parmak izleri
HKDF ile türetilmiş bir alt anahtar altında HMAC-SHA256; kayıtları cihazlar arasında birleştirmek için kullanılır
Kilidi açık anahtarın saklanması
chrome.storage.session — yalnızca bellekte, diske hiç yazılmaz, tarayıcı kapanınca silinir, content script'lerden erişilemez
Otomatik kilit
Her açılışta / 5, 15 veya 60 dakika hareketsizlikten sonra / tarayıcı kapanana kadar
Uygulama
Yalnızca WebCrypto. Hiçbir ilkel elle yazılmadı ve pakete hiçbir kripto kütüphanesi konmadı.

Neden iki katmanlı anahtar

Veriler hiçbir zaman doğrudan paroladan türetilen bir anahtarla şifrelenmez. Kayıtları rastgele bir ana anahtar şifreler; PBKDF2 çıktısı yalnızca bu ana anahtarı sarmalar. Bundan iki sonuç çıkar ve ikisi de önemlidir:

  • Parola değiştirmek, her kaydı, her yedeği ve her dışa aktarımı yeniden şifrelemek yerine 32 baytı yeniden yazar. Depolama sistemleri veriyi tam da bu toplu yeniden yazmalarda kaybeder.
  • 160 bitlik bir kurtarma kodu aynı ana anahtarı bağımsız olarak sarmalayabilir, yani unutulan parola telafi edilebilir. Kod bir kez gösterilir, onay için geri yazılması gerekir ve her kullanımdan sonra yenilenir. Kullanıcı onaylamadan diske hiçbir şey yazılmaz.

Ne şifreleniyor, ne şifrelenmiyor

Parola koruması açıkken hesap kaydının tamamı, tanımlayıcısı ve parmak izi dışında şifrelenir — servis adı dahil; böylece çalınan bir profil, kullanıcının hangi servislerde hesabı olduğunu ele vermez. Koruma açıldığında uzantı kayıtları şifreler, şifresini çözüp karşılaştırarak doğrular ve ancak ondan sonra düz metin kopyaların tümünü siler: tarayıcının yerel deposu, senkronizasyon ve yedi dönüşümlü yedek anlık görüntüsünün hepsi.

Değerlendirmeniz açısından önemli olduğu için açıkça yazıyoruz:

  • Parola koruması kapalıyken hesaplar şifresiz saklanır ve Chrome Sync açıksa kullanıcının kendi Google hesabı üzerinden çoğaltılır. Bize hiçbir zaman ulaşmazlar ama Google'da bulunurlar. Senkronizasyon kapatılabilir; bu, orada halihazırda bulunanı da siler.
  • Site bazlı kullanım geçmişi — hangi hesabın hangi alan adında kullanıldığı — yerel olarak saklanır ve toplandığı sürece kasanın kapsamında değildir. Parola korumasını açmak bu geçmişi siler; ayrıca bağımsız olarak da kapatılabilir.

Tehdit modeli

Şunlara karşı korur

  • Çalınmış veya kopyalanmış bir tarayıcı profili dizini
  • Tarayıcı verisini toplu hâlde sızdıran infostealer türü zararlı yazılım
  • Başında kimse olmayan bir makineye fiziksel erişimi olan biri
  • Hesap kayıtlarının Chrome Sync üzerinden Google'a ulaşması
  • Yedek dosyasının kaybolması veya çalınması (parola korumalı dışa aktarım)

Şunlara karşı korumaz

  • Kasa kilidi açıkken kullanıcı yetkisiyle çalışan zararlı yazılım
  • Parolayı yazılırken yakalayan bir tuş kaydedici
  • Ele geçirilmiş bir tarayıcı veya işletim sistemi
  • Kodların ait olduğu üçüncü taraf servislerin ele geçirilmesi
  • Kendi yazdığınız şifrelenmemiş bir dışa aktarım — düz JSON, otpauth:// bağlantıları veya CXF, dosyayı açan herkes tarafından okunabilir

Kısacası: bu, veriyi beklemedeyken korur. Kullanım sırasında zaten saldırganın denetiminde olan bir cihazı savunmaz, savunamaz da.

İzinler

Manifest beş izin ve hiçbir host izni bildirmez:

storage
Hesaplar ve ayarlar yerel depoda, kilidi açık anahtar oturum deposunda, bir de isteğe bağlı senkronizasyon kopyası
activeTab
Eşleşen hesabı öne çıkarmak için etkin sekmenin ana bilgisayar adını okur ve kullanıcı ekrandan QR kod taradığında sekmeyi yakalar
contextMenus
Sağ tık menüsüne “2FA kodunu ekle” öğesini ekler, yalnızca http(s) sayfalarındaki düzenlenebilir alanlarda
scripting
Kodu alana yazan tek fonksiyonu enjekte eder — tek bir sekme ve tek bir çağrı için, ancak o menü öğesi seçildikten sonra
sidePanel
Uygulamayı, o yüzey seçildiğinde Chrome'un yan panelinde açar; hiçbir sayfaya erişim vermez

Hiç content script yok yok, tabs, cookies veya webRequest izinleri yok, web-accessible resources da yok. Siz orada bir kod istemedikçe sayfada bize ait hiçbir şey bulunmaz; o an çalışan şey, yalnızca o sekme ve o çağrı için, kendi tıklamanızın verdiği izinle enjekte edilir ve geriye hiçbir şey bırakmaz.

Kamera

Kamerayla QR tarama, açılır pencerede değil sekmede açılan bir uzantı sayfasında çalışır — açılır pencere odağı kaybettiği anda yok edilir ve izin istemi tam olarak bunu yapar. Bunun için manifestte hiçbir izin gerekmez: tarayıcının standart kamera istemi kullanılır, uzantı origin'i başına verilir, site ayarlarından geri alınabilir ve kullanıcı tarayıcıyı açana kadar hiç sorulmaz. Video yerel olarak çözülür, hiçbir zaman iletilmez veya saklanmaz.

Ücretsiz plan, Pro ve günlük kontrol

1.14.0'dan beri uzantı günde bir kez api.authenticator.sh ile iletişim kurar — tarayıcı başladığında ya da açılır pencere çizildikten sonra; bir kodun gösterilmesini asla bekletmez. İstek kapalı bir alan listesidir: src/billing/sync.ts dosyasındaki tek bir fonksiyonda oluşturulur ve bir test onu bu listeye bağlı tutar:

iid
Bu kurulumun oluşturduğu rastgele bir kimlik. Bir Google hesabına, e-posta adresine ya da tarayıcıya bağlı değildir. Pro satın alınırsa satın alma kaydı, satın alınan kurulumu ve lisans anahtarının etkin olduğu her kurulumu ödemede kullanılan e-posta adresine bağlar
ver, ui_lang, browser_lang
Uzantı sürümü, arayüz dili, tarayıcı dili
installed_at, legacy, legacy_src
Kurulumun ne zaman oluştuğu ve faturalandırmadan önceye ait olup olmadığı
accounts, groups
Kaç hesap tuttuğu ve bunların kaç grupta olduğu — yalnızca sayılar, hangi hesaplar ya da grupların adları asla
vault, sync, open_mode, view_mode, style, dark, os
Parola korumasının ve senkronizasyonun açık olup olmadığı ve uzantının nasıl açıldığı, hesap listesinin nasıl gösterildiği (normal, sıkışık ya da kodlar gizli), hangi stilin ve açık mı koyu mu temanın kullanıldığı, ayrıca işletim sistemi (Windows, macOS, Linux, ChromeOS)
pid, lid, has_key, key_hint
Kurulumun şu anda elinde tuttuğu imzalı politika ve lisans, lisans anahtarının zaten onda olup olmadığı ve bu anahtarın son dört karakteri
opens
Son kontrolden bu yana uzantının her gün kaç kez açıldığı (en fazla son 14 gün) — gün başına bir sayı; neye bakıldığına dair hiçbir şey yok
events
Kapalı bir listeden, sırada bekleyen faturalandırma olayları: sınıra ulaşıldı, ödeme ekranı (paywall) gösterildi ya da kapatıldı, bir plan seçildi, bir ödeme ya da anahtar denendi

Asla gönderilmeyenler: gizli anahtarlar, hesap adları, hizmet adları (issuer), kodlar ya da bunların kullanıldığı siteler. Sunucu ülkeyi kendi uç noktasında (edge) istekten alır ve IP adresini saklamaz. Kaldırma sayfası aynı kurulum kimliğini ?i= parametresiyle alır: sunucuya kurulumun kaldırıldığını bildirir ve isteğe bağlı bir anket yanıtını bu kuruluma bağlar.

Bunun için chrome.storage.local içinde tutulanlar: kurulum kimliği, son imzalı politika ile lisans, bu kurulumun elindeki lisans anahtarı (elle yazılmış ya da bu kurulumdan satın aldıktan sonra gelmiş), sunucuya ulaşana kadar günlük açılma sayıları ve sırada bekleyen olaylar — hesap verisi yok. Senkronizasyon açıkken, kurulumun faturalandırmadan önceye ait olup olmadığı ve o lisans anahtarı da Chrome Sync'e gider; böylece kullanıcının diğer Chrome profilleri de bunları alır ve Pro'yu kendiliğinden açar. Senkronizasyon kapatılınca ikisi de Chrome Sync'ten silinir, yeniden açılınca geri konur.

Sunucudan ne döndüğü ve uzantının onu nasıl ele aldığı:

Token'lar
Politika (ücretsiz planın hesap sınırı) ve lisans (Pro), ES256 (ECDSA P-256) ile imzalanmış JWS'lerdir
Doğrulama
WebCrypto ile, derlemeye gömülü açık anahtarlara (src/billing/keys.ts) karşı. Chrome Web Store derlemesi yalnızca üretim anahtarına güvenir; başka herhangi bir anahtar taşıyan derlemeyi derleme denetimi reddeder
Çevrimdışı
Sınır ve lisans, son imzalı token'lardan yerel olarak kontrol edilir. İmzalı bir politika alınana kadar hiçbir şey sınırlanmaz — ulaşılamayan bir sunucu kimseyi asla dışarıda bırakamaz
Sınırın yapabildikleri
Bir hesabın eklenmesini durdurmak, başka hiçbir şey. Bir hesabı gizleyemez, kilitleyemez, silemez ya da değiştiremez; kodları, dışa aktarmayı, yedekleri, geri yüklemeyi veya senkronizasyonu engelleyemez
Satın almalar
Yeni bir sekmede Stripe Checkout; satıcı (merchant of record) Link'tir. Alıcının e-postası, lisans anahtarını vermek ve kurtarmak için Stripe'tan bize ulaşır; anahtarlar özet (hash) olarak saklanır, ayrıca kaybolan bir anahtar yeniden gönderilebilsin diye şifreli bir kopyası tutulur
Lisans anahtarı
Günlük kontrolün yanıtı anahtarın kendisini yalnızca Pro'nun satın alındığı kuruluma, o kurulumun key_hint ile bildirdiği dört karakter bu anahtarla eşleşene kadar taşır — böylece sonradan satın alınan bir anahtar eskisinin yerini alır; anahtarın elle yazıldığı bir kuruluma hiç gönderilmez

Sınır bir DRM değildir: kod açık kaynaktır ve bir çatal (fork) onu kaldırabilir. Asla mümkün olmaması gereken şey, bir kişinin başka birinin lisansını elde edebilmesi ya da kullanabilmesi veya başka birinin kurulumunu sınırlı hâle getirebilmesidir — bu bir zafiyettir ve güvenlik politikamızın kapsamındadır.

Dışa giden ağ trafiği

Kendiliğinden gerçekleşen iki tür istek vardır: saat kontrolü ve günlük faturalandırma kontrolü. Aşağıdaki diğer her şey kullanıcı bir yere tıkladığı için gerçekleşir. Manifest V3 uzak kodu yasaklar ve buradakilerin hiçbiri hesapları, gizli anahtarları veya üretilen kodları taşımaz. Listenin tamamı:

SunucuNe zamanKullanıcı verisi taşır mı?
time.akamai.com
timeapi.io
cloudflare.com
Saat sapması kontrolü, önbelleklenir; hiçbir kaynağa ulaşılamazsa Ayarlar bunu belirtir. Saat kayarsa TOTP bozulur.Hayır
authenticator.shKurulumda karşılama sayfası; kaldırmada, adresinde kurulum kimliğini taşıyan geri bildirim sayfası; açılır pencereden açıldığında yardım ve destek sayfaları.Yalnızca kaldırma sayfasında kurulum kimliği; bunun dışında hayır (sıradan web sunucusu günlükleri)
api.authenticator.shGünde bir kez faturalandırma kontrolü; kullanıcı Pro satın aldığında, bir anahtar girdiğinde, bir satın alımı geri yüklediğinde ya da bir aboneliği yönettiğinde ödeme, lisans ve portal çağrıları.Yukarıda listelenen alanlar — asla hesap verisi değil. Lisans anahtarı ya da e-posta adresi yalnızca kullanıcı birini yazdığında
checkout.stripe.com
billing.stripe.com
Stripe Checkout ve müşteri portalı; kullanıcı Pro satın aldığında ya da bir aboneliği yönettiğinde sekmede açılır.Alıcının orada girdikleri. Stripe'ın ve Link'in kendi koşulları geçerlidir
chromewebstore.google.comMağaza sayfası, yalnızca tıklandığında sekmede açılır: puanlama isteğinden değerlendirme formu.Hayır (Google bunu herhangi bir mağaza sayfası ziyareti gibi görür)

Üçüncü taraf sunuculardan yazı tipi, betik, stil veya görsel yüklenmez. Arayüzü çizmek için gereken her şey paketin içinde gelir.

Yayımladığımızı doğrulamak

Yukarıdakilerin hiçbirini bize güvenerek kabul etmek zorunda değilsiniz. Uzantı açık kaynaktır ve her sürüm yeniden üretilebilir:

  1. Yayımlanan .crx dosyasını Chrome Web Store'dan indirip açın
  2. Eşleşen git etiketine geçin
  3. Node 20 LTS üzerinde npm ci && npm run build çalıştırın
  4. Oluşan dist/ dizinini açılmış paketle karşılaştırın

Üretilen dist/ içindeki her dosyanın SHA-256 özeti, her GitHub sürümüyle birlikte SHA256SUMS-v<version>.txt olarak ve sha256sum biçiminde yayımlanır; böylece 4. adım tek bir sha256sum -c çalıştırmasına iner. Farklar, arşiv içindeki dosya sırası ve Node yama sürümleri arasında küçültülmüş çıktıdaki boşluklarla sınırlı kalmalıdır.

Çalışma zamanı bağımlılıkları bilinçli olarak az — OTPAuth, React, jsQR, Zustand, Framer Motion ve Lucide — ve depoya işlenmiş bir lock dosyasıyla sabitlenmiş. CycloneDX biçiminde SBOM talep üzerine verilir.

Kaynak kodu inceleyin

Sahip olmadıklarımız

Biz küçük ve bağımsız bir sağlayıcıyız. Aşağıdakilerden biri süreciniz için kesin bir gereklilikse, bunu bir değerlendirmenin üçüncü haftasında değil şimdi bilmeniz daha iyi:

  • SOC 2, ISO 27001 veya benzeri bir sertifikamız yok
  • Bugüne kadar bağımsız bir sızma testi yaptırmadık
  • Ücretli bir bug bounty programımız yok

Bunların yerine sunduğumuz şey: kaynak kodun tümüyle şeffaf olması, doğrulanabilir bir derleme, asgari izin yüzeyi ve gizli anahtarlarınızın, hesap adlarınızın ya da kodlarınızın en baştan hiç gönderilmediği bir sunucu.

Bize ulaşmak

Zafiyet bildirimleri ve güvenlik soruları: security@authenticator.sh. Açıklama politikamız, kapsam, yanıt süreleri ve safe harbour koşulları güvenlik politikası sayfasında; neyin saklandığı ve cihazdan neyin çıktığı ise gizlilik politikası içinde anlatılıyor.

Yazılı bir tedarikçi değerlendirme formunu memnuniyetle yanıtlarız ya da kodu bir güvenlik ekibiyle birlikte adım adım gözden geçiririz.

Güvenlikle ilgili olmayan her şey için — kurulum, hesap kurtarma, bir dağıtımdaki faturalandırma soruları — destek sayfasına bakın. Lütfen zafiyet bildirimlerini oraya göndermeyin; o kutu gizli kabul edilmiyor.