Güvenlik ve Mesajlaşma

doublethink, commit'lerle anlatıldı

doublethink'in neden var olduğunu daha önce yazmıştım. Bu, diğer yarısı: nasıl kurulduğu, doğrudan git geçmişinden okundu, çıkmazlar da dahil. Sonunda kendi tarayıcınızda çalıştırabileceğiniz canlı bir demo var.

Ramazan Yavuz
Ramazan Yavuz ·
doublethink, commit'lerle anlatıldı

Bir projenin git log'u, README'sinden daha dürüst olma eğilimindedir. README, insanların bitmiş şey hakkında inanmasını istediğin şeydir; commit geçmişi ise gerçekte olan şeydir, sırayla, atlamayı tercih edeceğin kısımlar dahil. doublethink, kurduğum küçük bir yayınla/abone ol mesaj broker'ı; ntfy kadar kolay ayağa kaldırılıyor ama broker'ın kendisinin bile okuyamadığı gerçekten özel kanallara sahip. Neden var olduğunu daha önce yazdım. Bu yazı ise nasıl yapıldığı, commit commit yürünerek, yanlış dönüşler de bırakılarak. Aşağıdaki her kısa hash, GitHub'daki gerçek commit'e bağlanıyor, böylece diff'i kendiniz okuyabilirsiniz.


Her şey kodla değil, bir belgeyle başladı. İlk commit depoyu spesifikasyonlar, ön-araştırma ve ilk kilometre taşının tasarımıyla başlatıyor. Bunu bilerek yapıyorum: tek satır yazmadan önce, bu şeyin ne işe yaradığını yazdım, sonra hiç var olması gerekip gerekmediğini kontrol ettim. Araştırma tek bir soru sordu. Zaten hem ntfy kadar kolay hem de gerçekten özel olan bir broker var mı? ntfy'ın kendi erişim kontrolüne, MQTT broker'larına, NATS'a ve yönetilen servislere baktıktan sonra cevap hayırdı: baktığım her yerde bu iki özellik birbiriyle takas ediliyordu. Sonraki otuz commit'in yazılmasının nedeni bu.

Bu beş commit ilk kilometre taşı: çalışan bir çekirdek. Sabit biçimli bir mesaj zarfı, mesajları dağıtan broker, istemcide çalışan kripto, ağ taşıması ve bunu sürmek için bir komut satırı aracı. Bunların sonunda doublethink bir mesaj taşıyabiliyordu. Yalnızca benden başka kimse tarafından henüz güvenilemiyordu ve güvenilmek için sorduğu yol yanlış çıktı.


Çıkmaz tam da log'da duruyor. Bir commit şöyle diyor: Keep keypair auth (deviate from mock contract); add MITM-resistant pairing. Fikir ağır olanıydı: her taraf bir kriptografik cihaz keypair'i taşır, broker bağlantıları imzalı bir challenge ile kimliklendirir ve iki tarafı eşleştirmek, ortadaki adamı dışlamak için tek kullanımlık bir davet kodu ile her iki insanın yüksek sesle okuduğu kısa bir dizgeden oluşur. Kâğıt üstünde güçlü tasarım budur. Her şeyi kurdum, sonra kullanmaya çalıştım. Artık her özel kanal çok adımlı bir kurulum gerektiriyordu ve ntfy'ı kopyalamaya değer kılan o tek nitelik, yani bir aracı dakikalar içinde ona yöneltebilmen, gitmişti. Artık kolay olmayan güvenli bir broker kurmuştum, ki bu zaten var olan bir şeyi yeniden kurmuş olmam demekti.

Sonraki commit onu siliyor. Redesign to ntfy-easy shared-secret channels (drop admin/keypair/SAS pairing). Yerine geleni neredeyse utandıracak kadar daha basit ve sadelik tam da bu özelliğin kendisi. Özel bir kanal, tek bir yüksek entropili paylaşımlı secret ile korunuyor. Tek bir istekle kanal oluşturup secret'ı geri alıyorsun; onu zaten sahip olduğun güvenilir bir yoldan karşı tarafa veriyorsun; secret'a sahip olan katılabilir, başkası katılamaz. Bu tek secret'tan her taraf farklı etiketlerle iki bağımsız anahtar türetiyor: birini broker, içeri girmene izin verilip verilmediğini kontrol etmek için saklıyor; diğerini, broker'ın asla hesaplayamadığı olanı, gerçek mesajları şifrelemek için. Broker kimin katılabileceğini biliyor ve okuyamadığı şifreli metni sadakatle iletiyor. O silme, projedeki en sevdiğim commit. Güçlü görünen tasarım yanlış olandı, doğrusu daha küçüktü.


Sonra küçük bir commit kümesi geliyor; bunlar paketleme konusunda fikrimi değiştirdiğimi kaydediyor. Önce bir Debian .deb ve bir systemd birimi olarak çıkıyor. Birkaç commit sonra bu, Docker ve tek bir yerel ikili lehine söküldü ve .deb ile birim silindi. Log, her şeyi en baştan bildiğimi varsayan temiz bir çizgi yerine hem ilk kararı hem de düzeltmeyi tutuyor. Bir GitHub Pages sitesi ve bir sürekli entegrasyon iş akışı aşağı yukarı aynı sıralarda kuruluyor, ki bu kişisel bir denemenin başkalarının kullanabileceği bir proje gibi davranmaya başladığı andır.


İkinci kilometre taşı gösterişsiz olanı ve bir oyuncağı açık internete koyabileceğin bir şeye dönüştüren olanı. Bir broker herkes tarafından erişilebilir olduğu an, "herkes kanal oluşturabilir" sevimli bir ntfy özelliği olmaktan çıkıp internete teslim ettiğin açık bir aktarıcıya dönüşüyor. Yoğun bir tek commit, M2: accounts, SQLite retention, TTL aging, quotas, abuse control, admin key, açık bir örneğin gerçekten ihtiyaç duyduğu tüm mekanizmayı ekliyor: bir API anahtarı olan hafif hesaplar, çevrimdışı kalmış bir tarafın yeniden bağlanıp kaçırdığını yakalamasını sağlayan isteğe bağlı mesaj saklama, eski mesajları yaşlandıran bir yaşam süresi, kimsenin diski dolduramaması için kanal başına ve hesap başına depolama kotaları, hız sınırları ve yalnızca sunucuda yaşayan bir operatör anahtarı. Bunların hiçbiri heyecan verici değil. Hepsi bir demo ile bir servis arasındaki farktır.

Ondan sonraki iki commit, bu yazının böyle bitebilmesinin nedeni. Biri, tarayıcıda çalışan kriptonun Go'da çalışan kriptoyla tam olarak aynı baytları ürettiğini doğruluyor, varsayılmak yerine parite-kontrollü olarak, ve bir tarayıcının ihtiyaç duyduğu çapraz-köken erişimi açıyor. Sonraki, proje sayfasına canlı, tarayıcı içi bir demo ekliyor, böylece gizlilik iddiası güvenmen gereken bir cümle olmaktan çıkıp izleyebileceğin bir şeye dönüşüyor.


Üçüncü kilometre taşı, tasarımın henüz ele almadığı bir kullanım durumundan geldi: birinin asla sona ermeyen bir topic oluşturmasına izin vermek, uzun ömürlü bir akış gibi bir şey için. Bundan iki sorun çıkıyor. Asla sona ermeyen bir topic süresiz olarak depolama kullanır, dolayısıyla internetteki herkesin diskinde kalıcı alan ayırmasına izin veremezsin; operatörün onayını gerektirir. Ama operatör kanalın secret'ını asla öğrenmemeli, yoksa gizlilik sözü bozulur. Cevap, M3 commit'lerinde, bir grant bileti: operatör tek kullanımlık, zamanla sınırlı bir bilet veriyor ki bu, kalıcı, sınırlandırılmış bir kanalı yetkilendiriyor ve kullanıcı bunu kendi secret'ıyla kullanıyor. Operatör kanalı secret'ı hiç görmeden yetkilendiriyor. Bir de devam eden bir durum var: topic herkese açık olacaksa, uçtan uca şifreleme için ödeme yapmak hiçbir şey kazandırmaz, bu yüzden grant şifrelemeden bağımsız hale geldi ve seçim verinin sahibine taşındı, kullanma anında yapılıyor. Bir yerde depolama motoru SQLite'tan Redis'e geçti, çünkü yük yüksek-hacimli değil yüksek-verimli, ve sert bir çökmenin tam olarak ne kadar kaybedebileceğini yazdım, yaklaşık bir saniye, çünkü "kalıcı" verinin yaşlanmaması anlamına gelmeli, diskin tutamayacağı bir dayanıklılık sözü değil.

O sondan bir önceki commit, dahili planlama belgelerini yayınlamayı durduran, bir şey yayınlamak hakkında küçük bir ders: geliştirdiğin depo ile yayınladığın depo aynı değil ve neyi dışarıda bırakacağını seçmek işin bir parçası. Bu geçmişte en çok düşündüğüm an bir özellik bile değil. Bir secret taramasının, gerçek bir admin anahtarını bir test verisi olarak herkese açık bir depoya commit etmek üzereyken beni yakaladığı an. doublethink'teki çekirdek fikir kısa. Onu güvenilir kılan çabanın çoğu, etrafındaki heyecan vermeyen kısımlara gitti.


Gelelim demoya. Proje sayfası, tamamen tarayıcınızda çalışan tek bir canlı demo taşıyor; kendi sunucumdaki gerçek bir örnekle konuşuyor. Şifreli gidiş-dönüşü gözünüzün önünde yapıyor: tarayıcınız bir secret üretiyor, tek kullanımlık bir kanal oluşturuyor, bir mesaj gönderiyor ve hem broker'ın ilettiği tam şifreli metni hem de yalnızca secret sahibinin kurtarabildiği düz metni gösteriyor. Sonra aynı baytları yanlış bir secret ile deniyor ve hiçbir şey kurtaramıyor. Kanal geçici ve hemen yıkılıyor, dolayısıyla hiçbir şey saklanmıyor. Demonun altında, sayfada broker'ı kendiniz çalıştırmak ve düz curl ile terminalden yayınlayıp abone olmak için kopyala-yapıştır komutları var. Proje sayfasının tamamı bu: izleyebileceğiniz bir demo ve çalıştırabileceğiniz komutlar, başka bir şey değil.

Çalışırken görün: tarayıcı içi demo ve çalıştırma komutları doublethink proje sayfasında. Yukarıda bağlanan her commit dahil olmak üzere tam kaynak GitHub'da.

İşte proje, kurulduğu haliyle: koddan önce bir araştırma notu, daha basit bir tasarım uğruna bırakılan daha güçlü görünen bir tasarım, geri alınan bir paketleme kararı, dağıtımı güvenli kılan gösterişsiz kilometre taşı, kalıcı topic'ler için eklenen bir yetenek ve gerçek bir hatayı durduran bir secret taraması. doublethink açık kaynak, Docker'da ya da tek bir ikili olarak çalışıyor ve sade bir garanti-yok notu taşıyor; çünkü işi başkalarının özel trafiğini tutmak olan bir araç, tek bir kişinin işi olduğu konusunda dürüst olmalı, gözden geçirilmiş ama yanılmaz değil. Commit geçmişi buraya nasıl geldiğinin en doğru anlatımı, bu yazıyı ondan yazmamın nedeni de bu.