Türkiye'ye göre yapılmış SMS-OTP altyapısı. Auth stack'ine iki endpoint'le oturur.
Evraksız, beklemesiz — hemen başla. Başlık onayı, BTK süreci, operatör anlaşması gerekmez — SMS'i biz göndermeyiz, kullanıcın kendi hattından gönderir. API key al, çağır.
Türkiye'de kalan. Numara, kod, oturum — İstanbul'daki altyapımızda işlenir; loglarda maskelenir, işi bitince silinir.
Fraud-korumalı. Kendi inisiyatifimizle tek SMS göndermeyiz: SMS bombing'e yapısal bağışıklık, gönderen-bazlı rate-limit, ön ödemeli kredi. Faturan patlamaz.
İlk 250 başarılı doğrulama ücretsiz — kredi kartı gerekmez.
curl -X POST https://otp.mioe.com.tr/auth/init \ -H "X-API-Key: $API_KEY" \ -d '{ "phone": "+905xxxxxxxxx" }' # → { "code": "WXKZ", "otp": "482910", # "sessionId": "1cce6791…" }
verified callback# Kullanıcı kodu SMS'leyince: POST /sms-login/cb X-Login-Signature: t=1746635012,v1=8c5d… { "type": "verified", "phone": "+905321112233" }
Başlık onayı, BTK süreci, operatör API entegrasyonu — bu modelde hiçbiri
sana düşmez: dışarıya SMS göndermiyoruz, inbound numarayı ve operatör tarafını
biz işletiyoruz. Sen iki ucu bağla — /auth/init'i çağır, imzalı
verified callback'ini karşıla. 250 doğrulamalık ücretsiz deneme
ile dakikalar içinde canlı ol; Better Auth vb. auth stack'ine doğrudan oturur.
Doğrulama verisi — numara, kod, oturum — İstanbul'daki altyapımızda işlenir ve saklanır; yedekler dahil yurt dışına çıkmaz, KVKK Madde 9 aktarımı hiç doğmaz. Üstüne veri minimizasyonu: loglarda numaralar maskelenir, biten oturumlar en geç 60 dakika içinde KVKK süpürmesiyle silinir. KVKK Aydınlatma Metni ve Veri İşleme Sözleşmesi hazır.
Sistem kendi inisiyatifiyle hiçbir zaman SMS göndermez — kötüye kullanılacak bir "kod gönder" ucu yok, SMS bombing ve toll fraud yapısal olarak imkânsız. İnbound tarafta taşıyıcı IP allowlist, gönderen-bazlı deneme sınırı ve HMAC imzalı callback yerleşik. Krediler ön ödemeli: bir gecede sürpriz fatura riski yok.
Klasik tek kullanımlık şifrede (OTP) kodu biz kullanıcıya yollarız, kullanıcı da
onu ekrana yazar — oysa yazılan bir kod paylaşılabilir, yönlendirilebilir,
kandırılabilir. Biz yönü tersine çevirdik: kodu sizin ekranınızda
gösteriyoruz, kullanıcı onu kendi telefonundan kısa numaramıza SMS olarak
gönderiyor. Doğrulama, mesaj gerçekten o telefondan çıkmadan kabul
edilmiyor — asıl güvenlik tam burada. Taşıyıcı göndericinin o numara olduğuna
şahitlik ediyor, biz oturumu eşleştirip uygulamanıza HMAC-SHA256 imzalı bir
verified webhook'u atıyoruz.
Yandaki kodu gösterilen numaraya SMS atmak için SMS gönder butonuna basın.
Mobil ağ, SMS'in bu numaradan geldiğine şahitlik etti. Tarayıcı kaynaklı hiçbir alan bu zincirde yer almadı. Bu numara yalnızca bu oturumda, yalnızca bu ekranda gösteriliyor — herkese açık değil.
60 saniye içinde eşleşen bir SMS ulaşmadı. Yeni bir kod alıp tekrar deneyebilirsin.
Bağlantıda bir sorun oluştu.
Form tabanlı OTP'lerde kullanıcı kodu okur ve yazar. Biz işin yönünü çeviriyoruz — taşıyıcı doğrudan kim olduklarına şahitlik ediyor.
POST /auth/init. Yanıt: 4 harfli prefix + 6 haneli OTP + 60 sn ömürlü oturum kimliği.
Ekrandaki WXKZ 482910 kombinasyonunu kısa numaraya yollar — bu işlem onun ispatıdır.
GSM operatörü (veya seçtiğiniz sağlayıcı) bize POST eder. Prefix + OTP eşleşirse oturum kapanır.
callback_url'nize yalnızca verified — sessionId ve doğrulanan phone birlikte, HMAC imzalı. Eşleşme olmazsa hiçbir şey göndermeyiz.
SMS'in göndericisi mobil ağ tarafından belirlenir — formdan değil. Tarayıcı kaynaklı hiçbir bilgi güvenilmez. Bu, telefon numarası doğrulamasını yapısal olarak sahteciliğe kapatır.
Her eşleşme sorgusu expires_at > now ister; 60 saniyelik pencere dolduğunda OTP
sunucu tarafında eşleşmeyi bırakır ve süpürülür — clock drift ya da açık kalmış oturum yok.
Backend'iniz hiçbir form alanına güvenmez. Sadece X-Login-Signature başlığını
webapp'a özel HMAC secret'la doğrular — gövdeyi biz attest ediyoruz.
Telefon doğrulaması ancak sahte üretilemediğinde işe yarar. Bu yüzden tarayıcının söylediği hiçbir şeye değil, taşıyıcının ettiği şahitliğe güveniyoruz.
Çıplak reverse OTP'nin, klasik (sistemin SMS gönderdiği) OTP'ye göre yapısal olarak daha geniş bir sahtecilik yüzeyi vardır — kimlik ispatı, taşıyıcının ilettiği bir iddiaya dayanır. Biz bu yüzeyi, her production ortamında gerçekten çalışan dört katmanla kapatıyoruz: taşıyıcının doğrulanmış ağına kilitli IP allowlist, ayrı bir paylaşılan header secret, gönderen numarası başına deneme sınırı ve HMAC-imzalı geri çağrılar. Sonuç: klasik OTP'nin kendi zayıf noktalarını taşımayan, daha güvenli bir sistem.
| Risk / kriter | Klasik OTP (SMS ile gönderim) | Çıplak reverse OTP (sertleştirmesiz) | Bizim sistemimiz |
|---|---|---|---|
| Kimlik ispatı nereye dayanır | Kullanıcının kodu doğru okuyup tarayıcıya yazması | Taşıyıcının "bu SMS bu numaradan geldi" şahitliği — doğrulanmamış | Aynı şahitlik + o iddianın gerçekten taşıyıcının kendi ağından geldiğinin doğrulanması |
| Sahte webhook / API isteğiyle backend'i kandırma | Uygulanamaz — böyle bir "kimden geldi" güven noktası yok | Ucuz saldırı — secret URL'i bilen herkes sahte istek atabilir | Kapalı — yalnızca taşıyıcının doğrulanmış IP aralığından, ayrıca doğru paylaşılan token'la gelen istekler kabul edilir |
| Deneme / brute-force / spoof probing | Genelde hız sınırlama var, uygulamaya bağlı değişir | Yok | Var — gönderen numarası başına deneme penceresi, eşik aşılınca otomatik durdurma |
| Gerçek zamanlı phishing / OTP-relay dolandırıcılığı | Yüksek risk — bugün SMS-OTP ele geçirmelerinin çoğu bu yolla oluyor | Daha düşük — kodu yazmak yerine aktif SMS göndermek gerekir | Daha da düşük — üstüne tek kullanımlık kod + sunucu tarafında kesin zorlanan 60 saniyelik pencere; yakalansa bile hızla ölür |
| SMS bombing / toll fraud (rastgele numaraya SMS bastırma) | Var — "kod gönder" uç noktası kötüye kullanılıp maliyet/taciz yaratabilir | Yapısal olarak bağışık | Yapısal olarak bağışık — sistem hiçbir zaman kendi inisiyatifiyle SMS göndermez |
| Geri çağrı bütünlüğü / tekrar oynatma | Uygulamaya bağlı, genelde zayıf | Garanti yok | HMAC-SHA256 imzalı ve zaman damgalı geri çağrı, tek kullanımlık OTP |
| SIM-swap / SS7 mesaj yönlendirme | Klasik zayıf nokta — mesaj başka bir cihaza sessizce yönlendirilebilir | Benzer taşıyıcı-seviyesi risk | Hiçbir OTP modelinin tek başına ortadan kaldıramadığı tek katman — ama IP allowlist + throttle bunu HTTP seviyesinde istismar etmeyi de zorlaştırır |
| Savunma katmanları (özet) | Genelde yalnızca hız sınırlama + captcha | Yok | Taşıyıcı IP allowlist · paylaşılan header secret · gönderen-bazlı throttle · HMAC imzalı geri çağrı · kiracı başına izolasyon |
Bu sertleştirmelerle birlikte reverse OTP, klasik (SMS-gönderimli) OTP'den daha güvenlidir. Çıplak reverse OTP'nin tek gerçek açığı — webhook/API sahteciliği — taşıyıcının doğrulanmış ağına kilitli IP allowlist ve ayrı bir paylaşılan token ile pratikte kapatılmıştır; kalan tek risk katmanı (taşıyıcı-seviyesi SIM-swap/SS7) zaten klasik OTP'nin de taşıdığı bir risktir.
Buna karşılık reverse OTP, klasik modelin gerçek dünyada en çok istismar edilen iki zayıf noktasına — gerçek zamanlı OTP-relay phishing ve SMS bombing/toll fraud — karşı yapısal olarak bağışık veya çok daha dirençlidir. Aynı taşıyıcı-seviyesi riski taşıyıp, klasik OTP'nin taşıdığı ekstra iki riski taşımıyoruz — üstelik dört bağımsız savunma katmanı eklendi.
Operatör webapp'ı oluştururken hangisinin kullanılacağını seçer. Sonradan değiştirmek bir tıklama.
4 harfli prefix tüm webapp'ları aynı kısa numarada toplar.
<prefix> <otp> yazar. Toplam 11 karakter.Numara doğrudan webapp'ınıza bağlı, prefix gerekmez.
Twilio, Vonage veya self-hosted SMSC'i webapp'a özel inbound URL'e bağlayın.
Bir uca /auth/init'i çağırıyorsunuz, diğer uçta bizden imzalı bir POST bekliyorsunuz.
POST /auth/init HTTP/1.1 Host: otp.mioe.com.tr X-API-Key: lvsr_a3f…b21 Content-Type: application/json { "phone": "+905321112233" }
sessionId, code (prefix), otp ve
dedicated modda inboundNumber döner.
POST /sms-login/cb HTTP/1.1 X-Login-Signature: t=1746635012,v1=8c5d… Content-Type: application/json { "type": "verified", "sessionId": "1cce6791…", "phone": "+905321112233", "verifiedAt": "2026-05-07T16:00:42Z" }
v1 == HMAC_SHA256(secret, t + "." + rawBody) —
sabit zamanlı kıyaslama şart. Kullanıcıyı callback'teki
phone ile giriş yapın, istemcinin bildirdiği
numaraya değil — oturum → numara bağını biz imzalıyoruz.
Kullanıcıya OTP kodunu gösterdikten sonra SMS göndermeyi kolaylaştırmanın en iyi yolu masaüstünde QR kodu, mobilde SMS butonu sunmaktır. Yukarıdaki canlı demo da bu yaklaşımı kullanır.
Masaüstü tarayıcılarda kullanıcı telefonuyla QR kodu okutarak SMS uygulamasını numara ve mesaj doldurulmuş halde açar. Tek adımda göndermeye hazır.
Mobil cihazlarda <a href="sms:…"> bağlantısı
telefonun SMS uygulamasını doğrudan açar. Kullanıcı sadece
"Gönder"e basar.
Android kamera uygulamaları sms: protokolünü doğrudan
açamaz. QR'a HTTPS yönlendirme linki koyun; sayfa
açılınca sms:'e yönlendirir.
sms: şeması// SMS URI formatı: sms:+90XXXXXXXXXX?body=WXKZ%20482910 // HTML'de kullanımı: <a href="sms:+90..?body=WXKZ%20482910"> SMS gönder </a> // JS ile oluşturmak: var smsUri = 'sms:' + number + '?body=' + encodeURIComponent( code + ' ' + otp );
?body= veya ?&body= — iOS ve Android'in
her ikisi de bu formatı kabul eder.
// QR içine konan URL (sms: değil!): https://yourapp.example/sms-redirect ?to=+90XXXXXXXXXX&body=WXKZ%20482910 // Yönlendirme sayfasının JS'i: var p = new URLSearchParams(location.search); var uri = 'sms:' + encodeURIComponent(p.get('to')) + '?body=' + encodeURIComponent(p.get('body')); // Otomatik yönlendir: window.location.href = uri;
sms: URI →
SMS uygulaması açılır.
navigator.userAgent ile mobil/masaüstü ayırın. Mobilde SMS butonu, masaüstünde QR gösterin.
QR kodu içine sms: URI'si değil, kendi sitenizde bir HTTPS yönlendirme sayfası URL'i koyun. Android kamera uygulamaları sms: protokolünü tanımaz.
/auth/init çağrısını backend proxy'niz üzerinden yapın. API anahtarı yalnızca sunucu tarafında kalmalıdır.
Doğrulama sonucu imzalı callback ile backend'inize ulaşır, tarayıcıya değil. Bunu kendi arayüzünüze nasıl yansıtacağınız tamamen size kalmış — bu entegrasyonun kapsamı dışında.
Inbound SMS'in göndericisi mobil ağ tarafından set edilir. Tarayıcı kaynaklı hiçbir alan bu zincirde yer almaz.
Her webhook X-Login-Signature taşır. Backend, ham gövdeyi sizin secret'ınızla doğrulayana kadar olayı varsaymaz.
verified geri çağrısı sessionId ve doğrulanan phone'u birlikte, imzanın altında taşır. Kullanıcıyı bu imzalı numarayla giriş yaparsınız; istemci "hangi numara doğrulandı" diyemez, dolayısıyla kendi numarasını doğrulatıp başkasınınkini iddia edemez.
API key, HMAC secret, prefix ve callback URL tek bir kiracıya bağlıdır. Çapraz eşleşme yapısal olarak imkânsız.
İmza Unix zaman damgasına bağlanır; ±5 dakika pencere önerilir. Her OTP tek seferliktir, eşleştiği an ölür.
Süre sunucu tarafında zorlanır: her eşleşme sorgusu expires_at > now ister, pencere dolunca OTP eşleşmeyi bırakır ve süpürülür. Kullanıcı tarafında hiçbir hile süreyi uzatamaz.
Aynı telefon için yeni /auth/init önceki oturumu sessizce failed olarak işaretler — eski kod anında işe yaramaz.
Her dilde örnek kod timingSafeEqual / hash_equals kullanır — kendiniz == ile karşılaştırmayın.
API key ve HMAC secret yalnızca oluşturma veya rotation anında görünür. Sızdığında operatör yerinde rotate edebilir.
Tüm hesap parolaları endüstri standardı Argon2id ile özetlenir — OWASP Parola Saklama kılavuzunun asgari profilini birebir karşılar. Hiçbir parola düz metin ya da geri çevrilebilir biçimde tutulmaz.
Parolalar Argon2id ile özetlenir: m=19 MiB · t=2 · p=1 —
OWASP 2023 asgari profili. Hafıza-zorlu (memory-hard) tasarım, çalınan bir veritabanını
GPU/ASIC ile toplu kırmayı ekonomik olmaktan çıkarır.
Her parola için 16 baytlık benzersiz, CSPRNG üretimi tuz kullanılır; aynı parolalar bile farklı özetlere düşer. Doğrulama sabit zamanlı yapılır — zamanlama yan kanalı yok.
Maliyet parametreleri özetin içine gömülüdür. Standart yükseldiğinde eşiği artırmanız yeterli; mevcut kayıtlar bir sonraki girişte sessizce yeni profile yükseltilir — kimse kilitlenmez, parola sıfırlaması gerekmez.
Kimlik doğrulama katmanının tamamı tek bir denetlenebilir kripto modülü üzerine kuruludur.
OWASP parametreleriyle; PHC formatında, parametreler özetle birlikte saklanır.
İmzalı webhook geri çağrıları aynı modülde üretilir ve sabit zamanlı doğrulanır.
Oturum ve parola sıfırlama token'ları veritabanında yalnızca hash'lenmiş halde tutulur.
OTP'ler, tuzlar ve token'lar crypto.getRandomValues CSPRNG ile üretilir.
timingSafeEqual ile parola ve imza karşılaştırmalarında zamanlama sızıntısı yok.
Reddetme örneklemesiyle (rejection sampling) üretilen kodlarda modulo yanlılığı bulunmaz.
İlk 250 doğrulama ücretsiz. Sonrasında ihtiyacınız kadar kredi alırsınız; her başarılı doğrulama yalnızca 1 kredidir. Kredi başı 0,03 TL (KDV hariç); aşağıdaki tutarlara KDV dahildir.
SaaS'ınız zaten bir form-OTP akışına sahipse, geçişi ortalama 90 dakikada tamamlıyorsunuz. İlk 250 başarılı doğrulama ücretsiz; kredi kartı gerekmez.