21 puan yazan GN⁺ 2025-09-19 | 1 yorum | WhatsApp'ta paylaş
  • UUIDv47, veritabanında sıralanabilir UUIDv7 saklarken dış API'lere UUIDv4 gibi görünen değerler sunar
  • Yalnızca timestamp alanı XOR ile maskelenir; böylece UUIDv7'nin zaman bilgisi korunurken diğer rastgele alanlar aynen kalır
  • SipHash-2-4 kullanan 128 bit anahtar ile maskeleme yaparak, anahtarın açığa çıkma riski olmadan bilgiyi güvenli biçimde korumak mümkündür
  • encode/decode işlemleri deterministik ve tersinirdir; rastgelelik korunduğu için çakışma riski düşüktür
  • Benchmark sonuçları, çok hızlı performans ve basit entegrasyon sunar; PostgreSQL gibi veritabanlarıyla kolayca entegre edilebilir

Projeye genel bakış ve önemi

  • UUIDv47, veritabanı içinde sıralama ve indeksleme için avantajlı UUIDv7 saklarken, dış API'ler ve sistemlere UUIDv4 gibi görünen değerler göstererek gizlilik koruması ile yüksek performanslı işlemeyi aynı anda sağlayan açık kaynaklı bir C kütüphanesidir
  • Diğer UUID dönüşüm algoritmalarına kıyasla tersinir eşleme, RFC uyumluluğu, anahtarın geri elde edilememesine dayalı güvenlik, zero-deps yapısı ve yalnızca basit bir header dosyası eklenerek kullanılabilmesi gibi alanlarda ayırt edici güçlü yönlere sahiptir

Başlıca özellikler

  • Header-only C (C89), harici bağımlılık olmadan kolay entegrasyon sağlar
  • UUIDv7'nin yalnızca timestamp alanını XOR ile maskeleyerek zaman bilgisinin açığa çıkmasını önler, diğer rastgele alanları ise değiştirmez
  • Anahtarlı SipHash-2-4 ile maskeleme yaparak 128 bit anahtarla bilgiyi güvenli biçimde koruyabilir
  • encode/decode süreci deterministik ve tamamen tersinirdir (orijinal değer eksiksiz geri elde edilebilir)
  • Veritabanı saklama için (v7) ve dışa gösterim için (v4) UUID'ler arasında hızlı eşleme sağlar
  • Test kodları ve benchmark araçları gibi zengin örnekler sunar

Kullanım amacı ve faydaları

  • VT içinde indeks locality ve sayfalama verimliliğini en üst düzeye çıkaran sıralanabilir UUIDv7 kullanılabilir
  • Dışarıya yalnızca UUIDv4 gibi görünen bir desen sunularak timestamp sızıntısı ve izleme riski engellenir
  • SipHash kullanıldığı için anahtar geri elde edilemez, gizli anahtar güvenliği korunur
  • RFC uyumlu sürüm/varyant bit işleme
  • Çalışma hızı yüksek olduğundan gerçek zamanlı işleme ve yüksek hacimli üretim ortamlarında da verimlidir

Temel yapı ve iç çalışma prensibi

UUIDv7 Layout

  • ts_ms_be: 48 bit big-endian timestamp
  • ver: 6. baytın high nibble değeri (0x7=VT, 0x4=dış)
  • rand_a: 12 bit rastgele değer
  • var: RFC variant (0b10)
  • rand_b: 62 bit rastgele değer

Maskeleme ve eşleme mantığı (Façade mapping)

  • Kodlama: ts48 XOR mask48(R), version=4 olarak ayarlanır
  • Çözme: encTS XOR mask48(R), version=7 olarak ayarlanır
  • Rastgele alanlarda değişiklik yoktur
  • SipHash girdisi olarak 10 baytlık rastgele alan kullanılır
  • XOR maskeleme, anahtar bilindiğinde anında tersine çevrilebilir

Güvenlik modeli

  • Hedef: Anahtar, girdileri seçmeli olarak verse bile açığa çıkmamalıdır
  • Uygulama: SipHash-2-4 adlı anahtarlı sözde rastgele fonksiyon (PRF) kullanılır
  • 128 bit anahtar kullanılır; anahtar türetimi için HKDF vb. önerilir
  • Anahtar rotasyonunda bunu UUID içine yazmak yerine, ayrı küçük bir anahtar kimliği tutmak önerilir

Public API (C)

  • uuidv47_encode_v4facade : v7→v4 dönüşümü
  • uuidv47_decode_v4facade : v4→v7 geri yükleme
  • Sürüm ayarlama, parse etme ve formatlama ile ilgili başka fonksiyonlar da sunulur

Performans ve benchmark

  • SipHash maskeleme (10B) işleminde 14ns/op altı, encode+decode tam round trip ise 33ns/op düzeyindedir (Apple M1 bazında)
  • Yüksek hacimli UUID üretimi ve eşlemesinde de hızlı işlem garantisi sunar
  • En iyi performans -O3 -march=native seçenekleriyle elde edilir

Entegrasyon ve genişletme

  • API sınırında encode/decode yapılması önerilir
  • PostgreSQL entegrasyonu için C uzantısı yazılabilir
  • Sharding sırasında v4 façade, xxh3 veya SipHash ile hashlenebilir

Diğer

  • Başka dil portları: Go (n2p5/uuid47) vb. mevcuttur
  • Önerilen hash: xxHash bir PRF olmadığı için bilgi sızıntısı riski taşır; SipHash önerilir

Lisans

  • MIT lisansı (Stateless Limited, 2025)

1 yorum

 
GN⁺ 2025-09-19
Hacker News görüşü
  • Merhaba, ben uuidv47’nin yazarıyım. Temel fikir, içeride veritabanı indeksleme ve sıralanabilirlik için UUIDv7 kullanırken, dışarıya istemciye zamanlama örüntülerini sızdırmamak için UUIDv4 gibi görünen değerler vermek
    Çalışma şekli, 48 bit zaman damgasını UUID’nin rastgele alanından türetilen SipHash-2-4 akışıyla XOR maskelemek
    Rastgele bitler olduğu gibi korunuyor, sürüm içeride 7, dışarıda 4 olarak değişiyor ve RFC varyant değeri de korunuyor
    Eşleme injective: yapı (ts, rand) → (encTS, rand)
    Çözme işlemi encTS ⊕ mask olduğu için kusursuz round-trip dönüşüm mümkün
    Güvenlik açısından SipHash bir PRF olduğu için, dışarıdan paketlenmiş değeri görmek anahtarı açığa çıkarmıyor
    Anahtar yanlışsa zaman damgası da tamamen farklı çıkıyor
    Anahtar kimliğini dışarıdan yöneterek anahtar rotasyonu da desteklenebilir
    Performans olarak 10 baytta bir SipHash, birkaç 48 bit load/store kadar; yani nanosaniye düzeyinde ek yük, C11 header-only, dış bağımlılık yok ve allocation gerekmiyor
    Testlerde SipHash referans vektörleri, round-trip encode/decode ve sürüm/varyant değişmezliği kontrol edildi
    Geri bildirimi merak ediyorum

    • Bu fikri beğendim
      UUID’ler çoğu zaman istemci tarafında üretiliyor; bu yöntemde bunun mümkün olmadığı anlaşılıyor
      İstemcinin ürettiği UUID’yi alıp maskeli sürümü geri verseniz bile, ts farklı ama rand aynı olan iki UUID birisi tarafından verilebilir ve bu bir zafiyet doğurmaz mı?
      Sonuç olarak bu yaklaşım yalnızca UUIDv7’yi doğrudan kendiniz ürettiğiniz durumlar için mi uygun, onu merak ediyorum

    • İki görüşüm var

      1. Bu yaklaşım, UUID v7’nin değerinin başkaları tarafından daha fazla kullanılabilmesi ihtimalini ortadan kaldırıyor; API kullanıcısı açısından bu biraz üzücü
      2. Dış API ile iç saklama biçimi farklı olunca, sürekli bu dönüşüm adımından geçmek gerekiyor; bu da yönetimi biraz daha zahmetli hale getiriyor
        Bu zahmete değecek kadar değer üretip üretmediğinden emin değilim
    • En büyük kaygım rastgele bitlerin entropi kalitesi
      UUIDv7, öngörülebilirlikten çok çarpışma önlemeye odaklanıyor
      Bu yüzden RFC, rastgele olmamayı zorunlu kılmak yerine öneri seviyesinde bırakıyor; zayıf PRNG ya da sayaç kullanımı, hatta rastgele bitlerin yerine ek saat verisi koyan uygulamalar bile var (bkz: RFC9562 s6.2 & s6.9)
      Dolayısıyla v7’nin rand_a ve rand_b alanlarını doğrudan PRF için seed olarak kullanmak, veri güven sınırının dışından geliyorsa düşünüldüğünden daha riskli olabilir
      PostgreSQL 18’in yeni uuidv7() işlevi bile yüksek çözünürlüklü zaman damgasıyla rand_a alanını tamamen dolduruyor; bu da RFC açısından sorun sayılmıyor
      Toplu import sırasında üretilen UUID’lere bakıldığında, bu v7-to-v4 yöntemiyle de gruplama yapılabildiği için bilgi sızabilir
      Motor parçası telemetrisi gibi şeylerde sorun olmayabilir ama insanlarla doğrudan bağlantılı tanımlayıcı verilerde dikkatli olmak gerekir
      Sonuç olarak, güvenilir entropiyi kendiniz garanti etmediğiniz sürece bu şema da zamanlama, seri ya da korelasyon bilgisi sızdırabilir; bu yüzden v7 uygulamasının kaynağını mutlaka doğrudan incelemek gerekir

    • Bunun iyi bir fikir olduğunu düşünmüyorum
      PostgreSQL 18’de isteğe bağlı shift parametresi zaman damgasını verilen aralık kadar kaydırıyor
      https://www.postgresql.org/docs/18/functions-uuid.html

  • Birkaç yıl önce kendi şemamı tasarlayıp DB’de sıralı artan sayısal ID, dışarıda ise 4–20 karakter uzunluğunda kısa rastgele string kullandığım bir yöntem uygulamıştım
    Bunun için Speck şifre ailesinin özelleştirilmiş bir örneğini kullanmıştım; sağlam ve oldukça makul olduğunu düşünüyorum
    Tamamlamıştım ama bunu kullanacağım projeyi ertelediğim için yayımlamadım
    Bu yıl ya da gelecek yıl ilgili materyali resmen yayımlamayı planlıyorum
    Uygulama biçimi ile artı ve eksilerini iyi özetleyen notlarım da var; ilgileniyorsanız bakabilirsiniz
    https://temp.chrismorgan.info/2025-09-17-tesid/

    • Ben de daha önce bigserial PKID’leri Speck ile obfuscate etmeyi denemiştim ama çapraz platform uygulama desteği zayıftı, özellikle de pgcrypto tarafında
      Bu yüzden base58(AES_K1(id{8} || HMAC_K2(id{8})[0..7])) seçtim
      Sonuçlar genelde yaklaşık 22 karakterle daha uzun oluyor ama neredeyse her ortamda uygulanabiliyor ve performansı da fazlasıyla yeterli

    • İyi fikir
      Benzer bir kavram olarak sqids’e (eski adıyla: hashids) de bakılabilir
      https://sqids.org/

  • Benzer bir şeyi zamanında ben de yaşadım; herkese açık uuid ile API’ye hiç çıkmayan bigint PK için iki ayrı sütun tutuyorduk (uuidv7 çıkmadan çok önceydi)
    uuid açısından biraz daha az kullanışlıydı ama PK’leri düzgün çıkardığınızda farklı DB dump’larını kolayca birleştirebilmek avantajdı
    Hash tabanlı sorgulama olsa bile sonunda yine iki sütun gerekecek gibi geliyor ama hash’in çalışma mantığını yanlış anlamış da olabilirim

    • Dönüşüm, gizli bir kriptografik anahtarla tersine çevrilebilir
      İstekteki uuidv4 değeri veritabanındaki uuidv7 değerine dönüştürülebilir
  • Fikir ilginç ama keşke veritabanı bunu doğrudan desteklese
    Yani UUIDv7 ile “UUIDv4” arasında karşılıklı dönüşüm yapılabilse ve sorgularda da iki format açıkça ayırt edilerek kullanılabilse

  • Gerçekten harika bir proje
    dchest’in siphash kütüphanesini kullanarak bir Go uygulaması yaptım
    https://github.com/n2p5/uuid47
    Referans: https://github.com/dchest/siphash

  • Proje ilginç görünüyor; UUID v7’de zaman kısmının açığa çıkma riskini gerçek bir örnekle gösterebilir misiniz diye merak ediyorum

    • Kullanıcının davranış örüntüleri ya da sıraları ortaya çıkarsa rahatsız edici durumlar doğabilir

      • “Eski kocan: kullanıcı ID’ne bakınca, Tom’un partisindeyken flört sitesinde hesap açtığın kesin değil mi?”
      • “Saat diliminin XYZ olduğunu söylüyorsun ama imageID’lerin (oluşturulma zamanına özgü) loglarda hep sabah 3’e denk geliyor gibi?”
        Tek tek mesajlar ya da gerçek zamanlı işlemler için önemli olmayabilir ama kullanıcı hesabı oluşturma ya da uzun ömürlü verilerde, biri bunu kimlik çıkarımı için kötüye kullanabilir
    • Eskiden bir CTF’de UUID’nin bir kısmını AES anahtarı olarak brute force etmiştim
      Anahtar zaman kaynağından kısmen türetildiği için, anahtarın üretildiği andaki sistem saatini öğrenince saldırı mümkün oluyordu
      Bir diğer basit örnek de bir dosya paylaşım servisinde yalnızca websitesi.com/GUID yapısının paylaşılması ve dosya yükleme zamanının ayrıca açıklanmaması durumu
      UUIDv7 kullanılıyorsa, yalnızca bundan dosya yükleme zamanını tahmin etmek mümkün olabilir
      Bu mutlaka büyük bir güvenlik tehdidi olmayabilir ama yine de istenmeyen bir bilgi sızıntısıdır

    • Örneğin tıbbi veri saklayan bir sistemi düşünün
      Analiz için MRI çekiminden hemen sonra sonuç yüklense ve kişisel bilgiler kaldırılmış olsa bile
      UUIDv7 zaman damgası üzerinden dış korelasyon analizi yapılarak “bu tarihte MRI çektiren tek kişi buydu, demek bu onun MRI’ı” denebilir

  • UUIDv7’nin en can sıkıcı yanı, listelerde insanların bunu gözle karşılaştırmasının (diff) çok zor olması
    psql’de rastgele bitleri öne alan ama gerçek sıralamayı zaman damgasına göre koruyan bir görselleştirme katmanı olsa UX inanılmaz iyileşirdi

    • Ben sadece UUID’nin son kısmına bakmayı alışkanlık haline getirdim

    • Kendiniz bir fonksiyon yazıp sorguda kullanabilirsiniz
      Örneğin hex gösteriminden sonra string’i ters çevirmek ya da reversed base64 kullanmak daha kısa ve ayırt etmesi daha kolay olabilir

  • Bu yaklaşım bana oldukça iyi görünüyor
    Ama zaman damgasının açığa çıkmasına fazla panik yapılmasını ve sıralı ID’lerin görünmesinin doğrudan saldırı yüzeyi ya da iş bilgisi sızıntısı sayılmasını, gerçek bir güvenlik sorunu olmaktan çok gereksiz endişe gibi görüyorum
    Belirli aralıklarla int değerine büyük bir rastgele sayı ekleseniz, monoton artış özelliği korunurken dış gözlemcinin örüntüyü kavraması da zorlaşır
    Sonuçta önemli bilgi sızıyormuş gibi davranıp konuyu biraz fazla büyütme eğilimi de var bence

    • Burada sızan şey iş verisi değil, istemci verisi
      Sistemin kendi sızdırdığı bilgi tek başına çok anlamlı olmayabilir ama toplu halde ya da zaman serisi şeklinde gözlemlenirse ek veri çıkarımı yapılabilir
      Örneğin David Kriesel’in SpiegelMining konuşmasında olduğu gibi, sadece gazete yazılarının tarihi ve yazarı toplanarak bile kimin ne zaman tatile çıktığına dair örüntüler çıkarılabiliyor
      Farklı yazar verileri karşılaştırıldığında şirket içi ilişkiler gibi şeyler bile ortaya dökülebilir
  • Neden oturum başına farklı bir şifreleme anahtarı kullanıp dışarıya sadece şifrelenmiş id göstermiyorsunuz diye merak ediyorum
    Böyle olursa DB’de sadece basit sıralı id kullanmak yeterli olmaz mı?

    • Tokendaki gizli zaman damgası bitlerini çözmek için hangi anahtarın kullanılması gerektiğini bilmek gerekir
      Anahtarı düzenli olarak değiştirirseniz anahtar yönetimi inanılmaz karmaşık hale gelir; o anda doğru anahtarın nasıl bulunacağı da ayrı bir sorun olur
  • Neden sürüm 4 yerine sürüm 8 kullanılmadığını merak ediyorum
    v4 rastgele bitler anlamına geliyor ama gerçekte o kadar da rastgele değil
    v8’de bitlerin anlamı üzerinde böyle bir kısıtlama yok

    • Ben de kesin cevabı bilmiyorum ama entropi yeterince yüksekse bunu seed tabanlı bir PRNG gibi görmek mümkün olabilir
      Bu yaklaşımın amacı zaten dışarıdan rastgele görünmek olduğu için, belki de v8 daha fazla dikkat çekerdi diye düşünüyorum