4 puan yazan GN⁺ 2023-11-03 | 1 yorum | WhatsApp'ta paylaş
  • Bear Blog, hız, verimlilik ve kararlılık kısıtları nedeniyle istemci tarafı JavaScript olmadan çalışan kendi analitik sistemini uyguladı
  • Yaygın analitik betikleri reklam engelleyicilere takılabilir; yalnızca sunucu günlükleriyle ise crawler’lar, scraper’lar ve GPT tabanlı ayrıştırıcılar da karıştığı için ziyaret istatistikleri çarpılabilir
  • Her sayfanın CSS’inde body:hover gerçekleştiğinde border-image ile /hit/{{ post.id }}/ endpoint’i çağrılıyor; hover ya da mobil kaydırma bir okuma sinyali olarak kullanılıyor
  • Sunucu, user-agent ile bot olup olmadığını, tarayıcıyı ve platformu kontrol ediyor; IP adresini yalnızca ülke tespiti için kullandıktan sonra yinelenen okumaları IP+tarih hash’i ile eliyor
  • Aynı IP’den aynı gün birden fazla cihazla okunursa tek okuma sayılıyor; ancak tanımlayıcı bilgi saklamadan sayfa bazında benzersiz okuma sayısını basitçe toplamak mümkün oluyor

CSS hover ile okuma olayı oluşturma

  • Bear Blog’un analitik sistemi, istemci tarafında JavaScript kullanmama kısıtına uyuyor
  • Yaygın analitik araçları, istemci JavaScript’iyle trafiğin gerçekliğini veya bot olup olmadığını kısmen değerlendirebilir; ancak birçok reklam engelleyici yalnızca Google Analytics’i değil Fathom, Plausible gibi analitik betiklerini de engeller
  • Yalnızca sunucu günlüklerini ayrıştırmak, arama motoru crawler’larının, scraper’ların ve GPT tabanlı ayrıştırıcıların normal trafik gibi karışmasına ve çarpık bir bakış oluşmasına yol açabilir
  • Bear, kullanıcının imleci sayfanın üzerine getirdiğinde ya da mobilde kaydırma yaptığında body:hover gerçekleşsin diye her sayfaya şu CSS’i ekliyor
body:hover {
  border-image: url("/hit/{{ post.id }}/?ref={{ request.META.HTTP_REFERER }}");
}
  • body:hover tetiklendiğinde ilgili yazının hit URL’i çağrılır
  • Bu isteğe açıkça yeniden eklenen bilgi referrer’dır; HTTP_REFERER yazımı ise yanlış yazımın standart gibi kalmış bir biçimidir
  • Botların hover yapmamasından yararlanılarak, body:hover tabanlı çağrı insan okuyucu sinyali olarak kullanılır
  • Ardından sunucuda user-agent’ın bot olup olmadığı kontrol edilir ve user-agent dizesinden tarayıcı ile platform çıkarılır

Tanımlayıcı bilgi olmadan yinelenen okumaları eleme

  • İkinci kısıt, okuyucuyu tanımlayabilecek bilgileri tarayıcı çerezlerinde veya sunucuda saklamamaktır
  • IP adresi yalnızca ülkeyi belirlemek için kullanılır; saklanmadan önce IP adresi ve tarih birlikte hash’lenir
  • Aynı sayfa için gelen sonraki istekler IP adresi + tarih hash’iyle karşılaştırılır; yineleniyorsa atılır
  • Bu yöntemde bir IP adresi, bir sayfa için bir gün boyunca tek bir read olarak sayılır
  • Ham IP adresi saklanmaz; tarihi içeren hash, günlük bazda sona erme etkisi yaratır
user_agent = httpagentparser.detect(self.request.META.get('HTTP_USER_AGENT', None))
if user_agent.get('bot', False):
    print('Bot traffic')
    return

ip_hash = hashlib.md5(f"{client_ip(self.request)}-{timezone.now().date()}".encode('utf-8')).hexdigest()
country = get_user_location(client_ip(self.request)).get('country_name', '')
device = user_agent.get('platform', {}).get('name', '')
browser = user_agent.get('browser', {}).get('name', '')
referrer = self.request.GET.get('ref', '')

if referrer:
    referrer = urlparse(referrer)
    referrer = '{uri.scheme}://{uri.netloc}/'.format(uri=referrer)

Hit.objects.get_or_create(
    post_id=self.pk,
    ip_address=ip_hash,
    referrer=referrer,
    country=country,
    device=device,
    browser=browser)
  • IP hash’i yalnızca gün içinde yinelenen hit’leri engellemek için kullanılır; tüm sayfa görüntülemeleri varsayılan olarak benzersiz işlenir
  • Her günün sonunda bir arka plan görevi hit günlüklerindeki hash’leri silerek GDPR’ın aşırı katı yorumlarıyla çakışmayı önler
  • Aynı IP adresinden aynı gün birden fazla cihazla okunsa bile yalnızca tek bir read olarak sayılması bu yöntemin dezavantajıdır
  • Bear, bu tür durumların trafiğin küçük bir bölümünü oluşturduğunu düşünüyor ve CSS tabanlı yöntemin çeşitli analitik toplama yöntemlerine kıyasla daha öz, basit ve doğru okuma sayıları sağladığını değerlendiriyor

1 yorum

 
GN⁺ 2023-11-03
Hacker News yorumları
  • Yazarıyım. IP adresi karması bu bağlamda yalnızca aynı gün içindeki yinelenen görüntülemeleri engellemek için kullanılıyor
    Her sayfa görüntülemesini varsayılan olarak benzersiz kılmak için var; her günün sonunda bir worker işi, görüntüleme bilgisini bırakıp karmayı temizliyor. Yazıda da bunu netleştirmek için bir düzeltme ekledim

    • Gece yarısı süresi dolan özel bir cache header’ı eklenmiş küçük, şeffaf bir görseli gerçekten servis edip IP’yi hiç saklamama yöntemini de değerlendirdiniz mi, merak ediyorum
    • Dünyanın herhangi bir yerindeki paylaşımlı bir VPN’de 10 kullanıcı aynı IP’yi kullanıp siteye girerse bunu yalnızca 1 kişi olarak mı sayıyorsunuz? Şirket ağları gibi durumlar da var; IP kötü bir metrik
  • CSS ile oluşan istekleri analitikte kullanma fikrini ilk gördüğümde gerçekten harika bulmuştum
    Twitter’da birisi sayfanın üzerine görünmez bir dikdörtgen ızgara yerleştirip, her hücrede hover olduğunda benzersiz bir arka plan görseli yüklenecek şekilde bunu fare izleme için kullanmıştı. Her arka plan görseli sunucuya belirli bir istek gönderiyor, sunucu da bunu yorumluyordu
    Bir yaz eğlence olsun diye bu fikri genişletip JavaScript’siz “yalnızca CSS ile asenkron web sohbeti” yaptım: https://github.com/kkuchta/css-only-chat

  • Yalnızca tarih ve IP’yi hash’leyerek IP adresini anonimleştirdiğini söylemek düpedüz güvenlik tiyatrosu
    Kriptografik hash’ler hızlı hesaplanacak şekilde tasarlanır. hashcat ile MacBook M1 Pro’da saniyede 6 milyar MD5 hash’i hesaplanabiliyor; IPv4 adresleri ise yalnızca 4 milyar tane. Tüm aralığa brute force uygulayıp IP adresini bulabilirsiniz; bu da fiilen hash’i geri çevirmekle aynı şey
    Kırık MD5 yerine SHA-256 gibi güvenli bir hash kullansanız bile durum aynı

    • Hash’ten IP’yi geri elde etmenin teknik olarak önemsiz olmasından ayrı olarak, AB veri koruma kurumları kişisel veriyi hash’lemenin anonimleştirme olmadığı konusunda çok net
      Birinin tam adını hash’leseniz bile daha sonra “bu hash şu belirli tam adla eşleşiyor mu?” sorusuna cevap verebilirsiniz. Bu soruya cevap verebilmek, anonimleştirme sürecinin geri alınabilir olduğu anlamına gelir
    • Yazarıyım. Aşağıda da yazdım ama bu thread ile daha ilgili görünüyor
      IP adresi karması bu bağlamda yalnızca aynı gün içindeki yinelenen görüntülemeleri engellemek için kullanılıyor. Her sayfa görüntülemesini varsayılan olarak benzersiz kılmak için var; her günün sonunda bir worker işi artık gerek kalmayan IP karmasını kaldırıyor
    • Bu arada Storybook’un telemetride benzer bir şey yaptığı tartışmada da aynı sorun gündeme gelmişti[0]; hiçbir optimizasyon olmadan bile evdeki dizüstü bilgisayarımda tüm IPv4’ler için salt’lı hash hesaplamak yaklaşık iki saat sürüyor
      [0] https://news.ycombinator.com/item?id=37596757
    • Hash’e salt eklenmeli. Salt kullanırsanız sorun yok, kullanmazsanız sorun var
      Salt’ın kalıcı olarak saklanıp saklanmayacağı ya da düzenli olarak değiştirilip değiştirilmeyeceği gibi şeyler yalnızca uygulama ayrıntısı; analitik amaçlı hash’e salt eklerken asıl nokta, salt’ın asla istemcinin dışına çıkmaması
      Yazının açıklamasına göre salt yok gibi görünüyor. Ya da mevcut tarihi salt gibi kullanıyor olabilir; bu da rastgele bir salt olmadığı için “IP x.y.z.w, yy-aa-gg tarihinde ziyaret etti mi?” sorusunu bilmek isteyen herkes tarafından kolayca tahmin edilebilir
      Saldırgan açısından bakınca bu tür sorunları değerlendirmek kolaydır. Verilen veriyle belirli bir kişi hakkında bir şey öğrenmek için ne yapardım? Bunu yapamıyorsanız o veriyi saklamak büyük olasılıkla genel olarak sorun olmayabilir
    • Gizli salt ya da dönen salt kullanılabilir, değil mi? Örnek kodda yok; o yüzden eleştiri doğru gibi. Yine de tek bir eklemeyle bunu oldukça makul biçimde güvenli hâle getirebilirsiniz
      Ancak bu tür güvenlik tiyatrosu bile kişisel verilerle ilgili birçok yasa ve düzenlemeden geçmek için yeterli olur diye endişeleniyorum
  • Zekice görünüyor ama body:hover yalnızca klavye kullanan kullanıcıları ve işaretçi cihaz kullanmayan user agent’ları, yani yardımcı teknoloji kullanıcılarını neredeyse tamamen kaçırabilir
    Bu gruplar marjinal olabilir, ama herhangi bir şekilde dışlandıklarını görmek her zaman çok kötü bir işaret
    Sadece temel CSS ile tüm user agent’larda “gerçek bir kullanıcı bu yazıyı okuyor” bilgisini %100 güvenilir şekilde algılayıp HTTP isteği göndermenin bir yolu var mı bilmiyorum; bundan şüpheliyim de. Bazıları CSS’i hiç desteklemiyor olabilir ya da CSS’in dekoratif görsel yüklemesini kapatmış olabilir
    Yardımcı olabilecek modern seçicilerden biri :root:focus-within, ama kullanıcının gerçekten etkileşimli bir öğeye odak vermesi gerekir ve tüm user agent’lar bunu da garanti etmez. En yeni scroll bağlantılı animasyonlardan @scroll-timeline da mümkün olabilir, fakat Braille okuyucular yine de dışarıda kalabilir

    • Marjinal mi? :hover desteklemeyen telefon ve tabletleri, yani user agent’ların %50’den fazlasını etkilemiyor mu? Elbette fare takılı değilse
    • Yazıldığı hâliyle, işaretçisi olan cihazlarda işaretçinin konumuna bağlı. İşaretçi ortadaki 760px alanın içindeyse etkinleşiyor, dışındaysa etkinleşmiyor
      Bu alan, içerik sütunu ile iki yandaki 20px padding’i içeren genişlik. Bu yüzden bazı klavye kullanıcıları yakalanırken bazı fare kullanıcıları, özellikle büyük viewport kullananlar, yakalanmıyor
  • “Google Analytics gibi kötü şeylerin yanı sıra Fathom ve Plausible da reklam engelleyen tarayıcılarda etkinlik kaydetmekte zorlanıyor” denmesi, bence onların fiilen zehirli bir çorak arazide yaşamaya çalışmasından kaynaklanıyor
    Bizim gibi kullanıcılar bu kavramın tamamından bıktı; bu yüzden CSS analitiği popülerleşirse onun da etrafından dolaşmaya yönelik girişimler ortaya çıkacaktır diye düşünüyorum

    • Neden?
      Ben uBlock’ta Piwik/Matomo, Plausible ve Fathom’un engelini elle kaldırdım. Bunların neyi nasıl izlediğinde zararlı bir şey görmüyorum. Üstelik site sahiplerine “hizmeti iyileştirmek” için faydalı bilgiler veriyorlar
      Örneğin Plausible, benim hakkımda sıradan nginx ya da Apache loglarından daha az bilgi topluyor. Bir blog yazarı açısından bir yazının HN’e çıkıp çıkmadığını, bir yerlerde linklenip linklenmediğini, hangi içeriğin değerli bulunduğunu ve hangisinin görmezden gelindiğini görmek önemlidir. Böylece insanların gerçekten okumak istediği şeyleri yazabilir ve bunları gerçekten erişebileceğin kanallardan yayabilirsin
    • Web sunucusunun access.log dosyasını bir analiz servisine vermek hiçbir şeyi engellemez
      Hatta yalnızca user agent’a bakarak tüm bot trafiğini ayıklamak fiilen imkânsız olduğundan sayılar şişebilir
    • Web’de bana zehirli bir çorak arazi gibi gelen şey her türden reklam. İzleme çok daha nüanslı bir mesele; uzun vadede ise bana yön vermenin en iyi yolunu bulmak için üzerinde deney yapılabilecek bir dijital ikiz oluşturulabilmesi gibi bir zararı var
      Gerçekte kaç kişinin bundan korktuğunu bilmiyorum. Tepkiler “evet, ürkütücü”den “saçmalık, sadece bilimkurgu”ya kadar ayrılabilir
    • CSS yüklemeyi bile engelleyebilen uMatrix aklıma geldi
    • Bu yöntem JavaScript yönteminden daha zor engellenir değil. Sonuçta belli bir URL desenine giden istekleri engellemekten ibaret
  • Bu, onlarca yıldır piksel izleyici olarak biliniyor

    • E-postada da kullanılır. 1x1 şeffaf bir görsel yüklemek, hover olayını tetiklemekten daha kesin ama reklam engelleyiciler bu tür görselleri sık sık engeller
    • Doğru. Yine de CSS ile yapılınca birkaç ilginç yanı var. :hover kullanırsan tam WebDriver kullanmayan botları, yani botların çoğunu filtreleyebilirsin
      Bazı açılardan, neredeyse boş bir .css dosyasını supports ile birlikte @import üzerinden yüklemek daha iyi bile olabilir. Reklam engelleyiciler 1px şeffaf izleme pikselini çok iyi yakalar, ama düzeni bozmamak için .css dosyalarını engelleme olasılıkları daha düşüktür. Ancak bu durumda :hoverın akıllıca avantajı ortadan kalkar
  • Gerçekten merak ettiğim bir soru ama küçümseyen bir yorum gibi okunmasından endişe ediyorum. Bearblog gibi görünen ticari olmayan kişisel bloglarda analiz verisi toplamanın amacı nedir?

    • 2000 civarından beri düzenli blog yazan ve başından beri “istatistiklere” çok ilgi duyan bir yazarın bakış açısından söyleyebilirim
      Analize ilgi duymamın başlıca nedeni yazıların okunup okunmadığını görmek. Dışarıdan ve bir bakıma kibir gibi görünebilir; ama aslında mesele yazar ile okur arasındaki bağ. Okurların neye tepki verdiğini gerçekten merak ediyorum ve onlara bundan daha fazlasını vermek istiyorum. O “şey” konu da olabilir, üslup da, uzunluk da. Malzemeyi okuruma göre inceltmeme yardımcı oluyor. Sonuçta ben on iki farklı konuyu yirmi dört farklı biçimde yazabilirim. Elbette sevdiğim şeyleri yazıyorum, ama okurda daha iyi karşılık bulacak şekilde rafine ediyorum
      Bu anlamda analiz, okuru tanımanın da bir yolu. Etkileşimi yüksek olan bloglarda analizler okura dair bulanık bir portre gibi bir şey verirdi. Sadece neyi sevdiklerini değil, ne zaman sevdiklerini de görebiliyordum. Sabah ilk iş mi okuyorlar, öğle arasında mı, gece geç saatlerde mi; bunu anlayabiliyor, belli bir saatte yayımlayıp yayımlamamaya karar vermeme ya da o karardan emin olmama yardımcı oluyordu. Elbette bunların hepsi bulanık bilgilerdi ama okurla daha etkin bağ kurmama gerçekten yardımcı oldu
    • Nedeni geri bildirim döngüsü. Pek çok kişinin düşündüğünün aksine analiz yalnızca reklam veya veri satışı için değildir; site ve içerik performansını analiz etme işidir
      Elbette reklam için kullanılabilir ve kötüye de kullanılabilir, ama yaptığım işe dair geri bildirim istiyorsam vazgeçilmezdir
      Siteyi 12 kişi de okusa 12.000 kişi de okusa parasal bir değeri olmayabilir. Ama kişisel açıdan insanların benden ne okumak istediğini bilmek güzel; yazmaya harcadığım zamanın iyi değerlendirilmiş olduğunu hissedebilirim ve istersem daha popüler olana doğru ayar çekebilirim
    • Merak değil mi? Yazdıklarımı birilerinin okuyup okumadığını bilmek isterim. İnsanların neyle ilgilendiğini bilmek de faydalı
      Kişisel bir blog yazarı bile içeriğini okuruna göre ayarlamak isteyebilir. Bir konudaki yazıyı 500 kişinin, başka bir konudaki yazıyı ise sadece 3 kişinin okuduğunu bilmek iyidir
  • Bu yılın başlarında buna benzer bir şey denemek istemiştim ama web UI yaparken motivasyonumu kaybettim. Benim yöntemim CSS değil, sadece bir etiketle sahte görsel yüklemekti
    https://github.com/nolytics

  • Neden bu bilgiyi doğrudan HTTP sunucusundan almıyorsunuz?

    • Blog yazısında şöyle açıklıyor
      “Sunucu loglarını ayrıştırma seçeneği her zaman vardır ve sunucuya erişen trafik türü hakkında kabaca fikir verebilir. Ancak genel olarak tüm sunucu trafiği aynı görünür. Teknik olarak botların kendilerini bot olarak tanıtan bir user agent’a sahip olması gerekir, fakat tarayıcı kullanan bir ‘insan’ gibi bilgi kazımaya çalıştıkları için kendilerini neredeyse hiç böyle tanıtmazlar. Özünde, analiz için yalnızca sunucu loglarını kullanırsan arama motoru crawler’ları, scraper’lar ve artık GPT tabanlı parser’lar da çok olduğu için trafiği çarpık görürsün”
    • Botların hepsi araya karışır
    • Sunucusuz çalıştırıyorsan zordur
  • Analiz verileri nasıl saklanır?
    Bir e-ticaret siteniz olduğunu ve satmak istediğiniz ürünler bulunduğunu varsayalım. Analizin yanı sıra, oturum açmış bir kullanıcının ürün detay sayfasını ziyaret etmesi gibi bazı davranışları doğrudan loglamaya karar verdiniz. Bu yüzden kullanıcı ID’si, ürün ID’si, zaman damgası gibi şeyleri saklamak istiyorsunuz.
    Peki gerçekte nasıl saklamak gerekir? Safça, bunları bir tabloya koymanın yeterli olacağını düşünmüştüm. DBA veriye ne kadar süre ihtiyaç olduğunu sordu, ben de en az bir ay dedim. Bunun üzerine tamam dedi; muhtemelen daha eski verileri başka bir tabloya taşıyacak bir iş planlamıştı.
    Gerçekte bu tür loglar nasıl saklanır ve ne kadar süre tutulur?

    • Muazzam bir ölçekte değilseniz, bunları Postgres tablosuna koymak tamamen sorun değil. Ölçek büyük olsa bile, devasa indekslerle uğraşmamak için tabloyu tarihe veya uygun başka bir özelliğe göre partition edebilirsiniz.
      Eskiden bunu yapmıştım; yaklaşık 1 milyar satıra gelene kadar partition etmeyi düşünmeye bile gerek olmamıştı. Yine de bundan daha erken partition etmek daha iyi. O deneyim pek keyifli değildi.
    • Analitik veritabanı daha iyidir. ClickHouse veya BigQuery gibi şeyler.
      Aggregation’ları çok daha hızlı yapabilir ve seyrek doldurulmuş çok sayıda kolonu da iyi yönetir. Örneğin paid event’inde amount özelliği, page_view event’inde ise url özelliği olması gibi.
    • MySQL’de 13 yıllık veri saklıyorum. Yıllık 5 milyon ziyaretçi ölçeğinde. Orada sorgulama yapmak sancılı olduğu için ClickHouse’ta da bir kopyasını tutuyorum. ClickHouse sorgulamak için gerçekten çok rahat.
    • Postgres ve TimescaleDB kullanıyorum. E-ticaret siteniz amazon.com ölçeğinde değilse iyi çalışır.
      TimescaleDB’nin güzel yanı, saat başına ürün görüntülenme sayısı gibi ilgilendiğiniz aggregation’lar için materialized view oluşturmayı kendi başına halletmesidir. Çok fazla event olduğu için veritabanının aşırı büyümesini önlemek isterseniz, event’lerin kendisini “atıp” yalnızca aggregation’ları tutmayı da seçebilirsiniz.
    • ClickHouse