QR’dan Kriptografik Kanıta: Tek Kullanımlık Eşleştirme, Nonce ve Cihaz Anahtarı
İki QR, kurum ve oturuma bağlı eşleştirme, Secure Enclave cihaz imzası, şablon sürümü sabitleme ve SoftHSM ile imzalanan paylaşım sonucunu adım adım inceliyoruz.

Bir dijital kimlik cüzdanında en kritik an, kurumun talebiyle vatandaşın onayının birbirine güvenli biçimde bağlandığı andır. Ekranda yalnızca bir QR kod görünse de arka planda şu sorular çözülmelidir:
- Kurum doğru cüzdana mı talep gönderiyor?
- Cüzdan doğru kurumun ve doğru işlemin QR kodunu mu okudu?
- Eski bir sunum tekrar kullanılabilir mi?
- Kullanıcı hangi alanları onayladı?
- Sunumu gerçekten kayıtlı cihaz mı üretti?
Serinin bu bölümünde yerel dijital kimlik demosundaki uçtan uca akışı, neden iki farklı QR kullanıldığını ve paylaşımın hangi kriptografik bağlarla korunduğunu inceliyorum.
Akışın özeti
1. Cüzdan geçici eşleştirme QR/kodu üretir
2. Kurum kodu tek sefer tüketir
3. Kurum, eşleştirilmiş cüzdana talep gönderir
4. Cüzdan bildirimde kurum ve amacı gösterir
5. Kullanıcı kurumun işlem QR'ını okutur
6. Cüzdan alanları gösterir ve cihaz doğrulaması ister
7. Cihaz talep + nonce + seçilen alanları imzalar
8. Sunucu belgeyi, cihaz imzasını ve talep kapsamını doğrular
9. Kuruma kısa ömürlü, hedefe bağlı imzalı sonuç döner
10. Cüzdana işlem makbuzu yazılır
Birinci QR: Cüzdanı bulmak, veri paylaşmak değil
Kurum portalında vatandaş adı veya T.C. kimlik numarası aratılmıyor. Bunun yerine cüzdan 2 dakika geçerli, tek kullanımlık ve opak bir eşleştirme belirteci üretiyor. Kurum QR’ı okuyabiliyor veya 10 karakterli geçici kodu girebiliyor.

İlk QR cüzdanı geçici olarak keşfeder. Ad, kimlik numarası veya aile bilgisi taşımaz ve veri paylaşmaz. İlk sürüm ekranı.
Sunucu ham belirteci saklamak yerine SHA-256 özetini bellekte tutuyor. Yeni kod üretildiğinde aynı cüzdana ait önceki kullanılmamış kod geçersiz hâle geliyor. Kurum kodu tükettiğinde yalnızca o kurumda tek talep oluşturabilecek kısa ömürlü bir connectionToken alıyor.
token = randomBytes(32)
code = randomHex(5) // 10 karakter
store[SHA256(token)] = {
wallet: person,
code,
expiresAt: now + 120s
}
Kurum eşleştirme yanıtında kalıcı cüzdan kimliği veya kişi adı almaz. Bağlantı belirteci hem kurum kimliğine hem o kurum oturumuna bağlıdır; başka kurumda, başka oturumda veya ikinci talepte kullanılamaz.
Neden ikinci bir QR gerekiyor?
İlk QR yalnızca “bu kuruma bir talep gönderebilirsin” der. Vatandaşın gelen bildirimi açması ise tek başına paylaşım yetkisi vermemelidir. Aksi durumda yanlış ekrana bakan veya kötü niyetli bir kurumun talebi kullanıcı tarafından fark edilmeden onay akışına taşınabilir.
Bu nedenle kurum, talep oluşturduktan sonra ikinci ve işleme özel bir QR üretir. Cüzdan, bildirimi açan kullanıcının tam olarak aynı talebin QR’ını okuttuğunu doğrular. QR’ın içindeki rastgele sır; bildirimde, gelen kutusunda veya normal talep yanıtında bulunmaz.
request = {
id: UUID,
recipient: matchedWallet,
merchant: verifierId,
nonce: UUID,
qrHash: SHA256(randomQrSecret),
expiresAt: now + 5min,
status: "pending"
}
Cüzdan yanlış talebe ait QR’ı, farklı cüzdana gönderilmiş talebi ve bozuk QR sırrını reddeder. Başarılı eşleştirmede üretilen pairingToken yalnızca ilgili talepte kullanılabilir.
Bildirim neden paylaşım anlamına gelmiyor?
Native iOS uygulaması açıkken gelen talepleri 3 saniyede bir kontrol ediyor ve yerel bildirim oluşturuyor. Bildirimin içeriği özellikle genel tutuluyor; adres, aile üyesi veya paylaşılacak değer kilit ekranına yazılmıyor.
Bildirime dokunulduğunda cüzdan kurum adını ve amacı gösteriyor, ardından kullanıcıyı kurum ekranındaki ikinci QR’a yönlendiriyor. APNs bu sürümde uygulanmadığı için uygulama kapalıyken anlık bildirim gelmiyor; uygulama yeniden açıldığında süresi dolmamış talepler alınabiliyor.
Alan bazlı onay
QR eşleştirmesinden sonra kullanıcı talep edilen alanları tek tek görür. Örneğin teslimat senaryosu il, ilçe, açık adres ve posta kodunu isteyebilir. Kullanıcı açık adresi kaldırıp yalnızca il ve ilçeyi seçebilir. Sunucu üç ayrı kontrol yapar:
- Seçim listesi boş olamaz; kullanıcı hiçbir şey vermek istemiyorsa talebi reddetmelidir.
- Aynı alan iki kez gönderilemez.
- Seçilen her alan, kurumun talep kapsamı içinde olmalıdır.
Bu son kontrol önemlidir. Arayüzde gizlenmiş bir alan, değiştirilmiş istemci tarafından API isteğine eklenebilir. Güvenlik kararı her zaman sunucuda tekrar doğrulanmalıdır.
Face ID onaydır; cihaz imzası kriptografik bağdır
Kullanıcı “Doğrula ve paylaş” dediğinde iOS uygulaması deviceOwnerAuthentication politikasını çalıştırır. Apple’ın tanımına göre bu politika biyometriyi, kullanılamadığı durumda ise cihaz parolasını kullanabilir.
Başarılı cihaz sahibi doğrulamasından sonra uygulama P-256 cihaz anahtarıyla şu challenge değerini imzalar:
challenge = [
requestId,
nonce,
personId,
selectedClaims.sort().join(",")
].join("|")
Gerçek iPhone’da özel anahtar Secure Enclave içinde üretilir ve dışarı çıkarılmaz. Simulator’da Secure Enclave bulunmadığından Keychain tabanlı yazılım anahtarı kullanılır. Sunucu açık anahtarı kaydeder, cihaz imzasını doğrular ve kuruma gönderilen kanıta yalnızca device_verified: true sonucunu ekler; sabit cihaz kimliği verifier’a verilmez.
Apple’ın Secure Enclave dokümantasyonu, donanım temelli anahtar yöneticisinin ana işlemciden ayrıldığını ve uygulamanın özel anahtarın açık hâlini işlemeden imza operasyonu yapabildiğini belirtir. Yine de prototipte cihaz kaydı gerçek kişi kimlik doğrulamasına bağlı değildir; bu yüzden cihaz imzası “bu demo cüzdanı aynı anahtarla imzaladı” anlamına gelir, devlet seviyesinde kimlik güvencesi anlamına gelmez.
Sunumun verifier ve işleme bağlanması
Sunumda iki alan özellikle kritik:
audience: Kanıtın hangi kurum için üretildiğini belirtir.nonce: Kanıtı belirli bir doğrulama işlemine bağlar.
OpenID for Verifiable Presentations 1.0, yeniden oynatma saldırılarına karşı sunumun hedef client_id ve işlem nonce değerine bağlanmasını ve verifier’ın bu bağı doğrulamasını zorunlu güvenlik kontrolü olarak tanımlar. Demo OpenID4VP protokolünü uygulamasa da aynı güvenlik ilkesini küçük bir akışta görünür kılıyor.
{
"issuer": "Yerel Demo Nüfus Kurumu",
"audience": "social",
"nonce": "işleme-özel-değer",
"request_id": "talep-kimliği",
"family_members": [
{ "name": "Sentetik Kişi", "relation": "Eş" }
],
"device_verified": true,
"expires_at": 1792331073709,
"pairwise_id": "kuruma-ozel-tanimlayici"
}

Verifier yalnızca seçilen alanları, işlem bağlarını ve imza doğrulama sonucunu alır. İlk sürüm ekranı.
Tek kullanımlılık ve durum makinesi
Her talep pending durumunda başlar ve yalnızca bir terminal duruma geçebilir:
pending → approved
pending → incomplete
pending → ineligible
pending → rejected
pending → expired
Onaylanmış veya reddedilmiş talep yeniden sunulamaz. Cüzdan eşleştirme kodu, kurum bağlantı belirteci, işlem QR sırrı ve pairing token farklı amaçlar için kullanılır ve birbirinin yerine geçmez. Bu ayrım, tek bir uzun ömürlü QR’a çok fazla yetki yüklenmesini önler.
Kullanıcı açısından görünür güvenlik
Kriptografi doğru olsa bile kullanıcı yanlış kuruma yanlış bilgiyi gönderiyorsa sistem amacına ulaşmaz. Bu nedenle prototipte güvenlik kararları kullanıcı arayüzünde de görünür hâle getirildi:
- Kurum ve amaç onay ekranının üstünde gösteriliyor.
- Alanların gerçek demo değerleri paylaşım öncesinde görülebiliyor.
- Talebin kalan süresi geri sayılıyor.
- Reddetme seçeneği onay düğmesiyle aynı ekranda bulunuyor.
- Paylaşım sonrasında hangi alanların gönderildiği makbuza yazılıyor.
Bu aşamanın geliştirme sonucu
İki QR yaklaşımı akışı biraz uzatıyor; fakat iki farklı güvenlik sorusunu ayırıyor: “Talebi hangi cüzdana göndereceğim?” ve “Kullanıcı şu anda hangi işlemi onaylıyor?” Prototipteki en değerli öğrenimlerden biri, kimlik akışında sürtünmeyi tamamen kaldırmak yerine doğru noktaya yerleştirmenin daha güvenli olduğudur.
Serinin üçüncü bölümünde 22 testin neyi kanıtladığını, prototipin güven sınırlarını ve bu laboratuvarın OpenID4VCI, OpenID4VP, gerçek credential formatları, HSM, güven kayıtları ve bağımsız güvenlik değerlendirmesiyle üretime nasıl taşınabileceğini inceleyeceğiz.
Kurum oturumu da işlemin bir parçası
Geçici cüzdan kodunun tüketilmesi artık yalnızca kurum kimliğine değil, işlemi başlatan kurum oturumuna da bağlanıyor. Kurum, istemcinin gönderdiği serbest bir adla belirlenmiyor; giriş hesabının sunucudaki kurum kaydından geliyor. Hastane eşleştirmesi market hesabıyla veya yeni açılmış başka bir hastane oturumuyla sürdürülemiyor. API, yetkisiz denemeyi HTTP 403 ve açıklayıcı gerekçeyle reddediyor.

Kullanım akışı: kurum girişinden SoftHSM ile imzalı sonuca kadar on sıralı adım.
Şablon sürümünü talebe sabitlemek
Dinamik kurumlar için şablonun amacı, alanları, zorunlulukları ve sürümü talep oluşturulduğunda sabitleniyor. Örneğin v1’de telefon isteğe bağlıyken v2’de gerekli hâle getirilse bile, v1’den gönderilmiş açık talep eski koşullarla tamamlanıyor. İmzalı sonuca template_id ve template_version ekleniyor. Düzenlenmiş şablon geçmişte verilen onayın anlamını değiştiremiyor.
İki ayrı imza, iki ayrı kontrol
iPhone cihaz imzası talep kimliğini, nonce’u, sentetik kişi seçimini ve sıralanmış alan adlarını birbirine bağlıyor. API bu imzayı kayıtlı cihazın açık anahtarıyla doğruluyor. Ardından belge ve paylaşım politikaları kontrol edilerek seçilen bilgiler SoftHSM’deki ihraççı anahtarıyla ES256 olarak imzalanıyor. Dönen imza API’de ihraççının açık anahtarıyla kontrol ediliyor. Kurumun ekranındaki “imza doğrulandı” bu merkezi doğrulamanın sonucudur; kurumun ayrı bir doğrulama sunucusu çalıştırdığı anlamına gelmez.
Signer erişilemiyorsa işlem güvenlik nedeniyle duruyor; sağlık ve imzalama kontrolleri 503 döndürüyor. Yerel geliştirme anahtarına sessiz dönüş yapılmıyor. SoftHSM fiziksel HSM değildir; yazılım katmanı ayrımı ve anahtar kullanım politikasını test etmek için kullanılıyor.
Gerekli alanlar eksik paylaşıldığında incomplete, istenen uygunluk koşulu sağlanmadığında ineligible üretilir. Bu durumlarda seçilmiş bazı bilgiler kuruma iletilmiş olabilir; “işlem tamamlanmadı” ifadesi “hiç veri paylaşılmadı” anlamına gelmez. Kullanıcı açıkça reddettiğinde ise paylaşım yapılmaz.
Kaynaklar
Standartlar ve birincil kaynaklar
Üretim sistemlerinde güncel sürümleri ve kurumunuzun onaylı politikalarını esas alın.
Bu makaleyi nasıl değerlendirirsin?
Geri bildirimin sonraki içerikleri geliştirmeme yardımcı olur.