1 puan yazan GN⁺ 4 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • Birçok CLI, dizüstü bilgisayardaki yerel tarayıcıda hızlıca tamamlanan localhost OAuth yönlendirmesini varsayılan olarak kullanır; ancak SSH, konteyner ve WSL gibi geliştirme ortamlarında bu varsayım bozulur ve giriş akışı durur
  • Mevcut yöntemde CLI, 127.0.0.1 üzerinde geçici bir HTTP sunucusu açar, tarayıcıyı kimlik doğrulama URL’sine gönderir ve ardından kimlik sağlayıcı authorization code’u yerel callback’e geri döndürür
  • 2019’da standartlaştırılan RFC 8628 Device Authorization Grant, token isteyen CLI ile kullanıcının kimlik doğruladığı tarayıcı cihazını ayırarak port bind etme ve yerel tarayıcı bağımlılığını ortadan kaldırır
  • Device flow, device_code, user_code, verification_uri, interval alır ve /token uç noktasını periyodik olarak poll eder; authorization_pending, slow_down, access_denied, expired_token gibi standart durumları işler
  • Yeni bir CLI geliştiriliyorsa varsayılan olarak device flow kullanılmalı, uç noktalar .well-known/openid-configuration ile keşfedilmeli ve refresh token ~/.config altındaki bir JSON dosyasında değil, OS keychain içinde saklanmalıdır

localhost yönlendirmesinin varsaydıkları

  • Yaygın CLI giriş yöntemi, yerel HTTP sunucusunun ve sistem tarayıcısının aynı makinede olduğu varsayımıyla çalışır
    • CLI, 127.0.0.1 üzerindeki belirli bir porta HTTP sunucusu bind eder
    • Sistem tarayıcısını OAuth authorization endpoint’ine açar ve redirect_uri=http://127.0.0.1:<port>/callback ekler
    • Kullanıcı giriş yaptığında kimlik sağlayıcı authorization code’u loopback URL’ye 302 ile yönlendirir
    • CLI içindeki küçük HTTP sunucusu code’u okuyup token endpoint’te token ile değiştirir
    • Çoğu durumda PKCE eklenir ve ardından “bu sekmeyi kapatabilirsiniz” sayfası gösterilir
  • gcloud auth login, wrangler login, eski vercel login ve çeşitli üretici CLI’ları bu yöntemi kullanır
    • Wrangler 8976 portunu kullanır
    • gcloud 8085 kullanır
    • Claude Code her çalıştırmada geçici bir port seçer
  • RFC 8252, yerel uygulamalarda tarayıcı mevcutsa bu deseni önerir, ancak ana makinede tarayıcı olmadığında ne yapılacağını ele almaz

Kullanıcıların localhost adımını çoğu zaman fark etmemesinin nedeni

  • localhost callback çok kısa sürdüğü için kullanıcıların çoğu bunu görmez
  • CLI’nin yazdırdığı URL uzundur ve redirect URI bunun query string’i içinde yer alır
  • Kullanıcılar giriş ve onayı kimlik sağlayıcının gerçek alan adında yapar
  • Kimlik sağlayıcı daha sonra tarayıcıyı localhost callback’e gönderir, CLI code’u okur ve ardından daha cilalı bir “signed in” sayfasına geçilir
  • Dışarıdan bakınca “web sitesinde giriş yaptım, CLI de doğrulandı” gibi görünür; ama gerçekte akışı ayakta tutan şey yerel HTTP sunucusu ile tarayıcının birlikte var olmasıdır

SSH, konteyner ve WSL’de kırılan nokta

  • Tüm akış, CLI’nin çalıştığı makine ile tarayıcının çalıştığı makinenin aynı olduğu varsayımına dayanır
  • SSH oturumunda uzak ana makinede tarayıcı yoktur; xdg-open başarısız olabilir ya da X forwarding ortamında görünmeyen bir uzak tarayıcı açılabilir
    • Callback portu dizüstüne tünellenebilir, ancak kimlik sağlayıcıya kayıtlı redirect URI’nin tünelden geçen bu porta izin vermesi gerekir
  • Konteynerlerde tarayıcı yoktur ve birçok imajda xdg-open veya open da bulunmaz
    • Callback portu -p ile açığa çıkarılabilir, fakat bunun için CLI’nin hangi portu kullanacağını bilmek gerekir
    • Cloudflare CLI’da bu nedenle engellenen kullanıcıların issue kayıtları birikmiştir
  • WSL’de tarayıcı Windows üzerinde açılırken loopback sunucusu Linux üzerinde çalışır
    • WSL2’nin port yönlendirmesi çoğu zaman işe yarasa da her zaman güvenilir değildir
  • Paylaşılan makinelerde aynı makinedeki başka süreçler /proc/net/tcp üzerinden dinlenen portu bulabilir veya bilinen portu önce bind etmek için yarışabilir
    • PKCE, code exchange’i korur; fakat redirect’in kendisindeki authenticated session’ı korumaz

fallback’in varlığı bile tasarım sorununu gösteriyor

  • Loopback akışını varsayılan sunan CLI’lar, bozulma ihtimaline karşı fallback de sağlar
  • gcloud’da --no-launch-browser seçeneği vardır
  • Wrangler takılır ve kabul görmüş geçici çözüm, ikinci bir terminalde localhost URL’sine doğrudan curl atmaktır
  • Anthropic’in claude aracı “Paste code here if prompted” çıktısını verip bekler
  • Bu fallback’ler fiilen manuel bir device flow anlamına gelir; yani CLI’nin gerçekte kullanıldığı ortamlarda varsayılan akış çalışmadığı için vardır

RFC 8628 Device Authorization Grant

  • RFC 8628, 2019’da “input-constrained devices” için yayımlanan OAuth 2.0 Device Authorization Grant standardıdır
    • TV’ler, konsollar ve CLI’lar hedef kullanım alanları arasındadır
    • Temel fikir, token isteyen cihaz ile kullanıcının kimlik doğruladığı cihazı birbirinden ayırmaktır
  • CLI, kimlik sağlayıcının device_authorization_endpoint uç noktasına POST isteği gönderir
    • Örnek istekte client_id=my-cli&scope=openid+offline_access gönderilir
  • Kimlik sağlayıcı aşağıdaki değerleri içeren bir JSON döndürür
    • device_code
    • user_code
    • verification_uri
    • verification_uri_complete
    • expires_in
    • interval
  • CLI URL’yi ve kısa kodu ekrana yazdırır; mümkünse verification_uri_complete için QR da gösterir
  • Kullanıcı istediği cihazda URL’yi açar, giriş yapar, istenen scope ve client name’i görür, ardından bunun CLI’de gösterilen kısa kodla eşleştiğini doğrulayıp onay verir

Polling ve standart durum işleme

  • CLI, token endpoint’i interval saniyede bir poll eder
  • Grant type olarak urn:ietf:params:oauth:grant-type:device_code kullanılır
  • RFC 8628 section 3.5 şu durumları tanımlar
    • authorization_pending: kullanıcının onayı bekleniyor
    • slow_down: kimlik sağlayıcı polling aralığının düşürülmesini istiyor; şartname interval’in en az 5 saniye artırılmasını söyler
    • access_denied: kullanıcı isteği reddetti
    • expired_token: çok uzun beklendiği için token süresi doldu
  • Device flow’da CLI bir porta bind etmez ve çalıştığı ana makinede tarayıcı bulunduğunu varsaymaz
  • Aynı giriş yöntemi dizüstünde, konteynerde ve insan onayı bekleyen bir CI job içinde çalışabilir

Polling maliyeti ve uç nokta keşfi

  • Varsayılan polling aralığı 5 saniyedir
  • Kimlik doğrulamaların çoğu 1 dakika içinde tamamlandığı için tipik bir girişte /token uç noktasına yaklaşık 10 kez poll yapılıp durulur
  • Sunucu slow_down ile aralığı artırabilir ve düzgün yazılmış istemcilerin buna uyması gerekir
  • Her bekleyen giriş için stateful bir endpoint’e WebSocket veya SSE bağlantısı açık tutmakla karşılaştırıldığında, /token üzerinde stateless polling daha basit ve daha ucuzdur
  • Kimlik sağlayıcı OpenID Connect Discovery destekliyorsa CLI, .well-known/openid-configuration üzerinden device_authorization_endpoint ve token_endpoint bilgilerini alarak URL’leri sabit kodlamaktan kaçınabilir

device flow’un phishing riski

  • Device flow’da saldırgan, gerçek kimlik sağlayıcının device_authorization_endpoint uç noktasını çağırıp user_code ve device_code aldıktan sonra kurbanı bu kodu girmeye ikna eden bir saldırı düzenleyebilir
  • Kurban gerçek URL’de, gerçek kodla giriş yapıp gerçek consent screen’i onaylayabilir
  • Saldırgan ise kendi oluşturduğu device_code ile /token uç noktasını poll ederek access token’ı alır
  • Rus tehdit aktörleri Ağustos 2024’ten beri M365 tenant’larını hedefleyen bu kampanyayı yürütüyor
    • Microsoft Threat Intelligence bunu Storm-2372 olarak izliyor
    • Volexity, bunu APT29/Midnight Blizzard olarak ilişkilendiriyor
    • Kamu, savunma ve STK tenant’ları birden fazla kıtada etkilendi

phishing savunması kimlik sağlayıcının sorumluluğunda

  • Phishing savunması CLI tarafında değil, kimlik sağlayıcı tarafında yapılmalıdır
  • Gerekli azaltım önlemleri şunlardır
    • kısa user_code son kullanma süresi
    • verification page üzerinde client name ve istek kaynağının belirgin şekilde gösterilmesi
    • code girme denemelerine rate limiting uygulanması
    • kurbanın bağlantıya tıklaması yerine kodu elle girmesini teşvik etmek için verification_uri_complete değerinin gösterilmemesi
    • yüksek değerli tenant’larda, bilinen ağ veya cihaz değilse device code flow’un conditional access policy ile engellenmesi
  • CLI’nin görevi şartnameye uymak ve kestirme yollar oluşturmamaktır
  • Device flow, yerel attack surface’i sosyal attack surface’e dönüştürür; ancak daha fazla ortamda çalışan bir akış sunmak ve kimlik sağlayıcının mitigation’larından yararlanmak daha doğru yaklaşımdır

Go uygulama örneğinde temel akış

  • Tüm uygulama Go’da yalnızca net/http kullanılarak yaklaşık 30 satıra sığar
  • Uygulama akışı şöyledir
    • client_id ve scope ile DeviceAuthorizationEndpoint için http.PostForm çağrısı yapılır
    • Yanıt JSON’undan DeviceCode, UserCode, VerificationURIComplete, Interval alanları decode edilir
    • Kullanıcıya VerificationURIComplete ve UserCode yazdırılır
    • TokenEndpoint için device_code, client_id ve device grant type içeren tekrar eden POST istekleri gönderilir
    • authorization_pending ise beklemeye devam edilir
    • slow_down ise interval 5 saniye artırılır
    • Hata yoksa access_token ve refresh_token döndürülür
    • Diğer hatalar başarısızlık olarak işlenir
  • Keycloak realm’inde “OAuth 2.0 Device Authorization Grant” yeteneği açılırsa veya bu grant’i destekleyen OpenID sertifikalı bir sağlayıcı kullanılırsa device-flow login çalışır

Yeni CLI’lar için varsayılan olması gereken yöntem

  • Varsayılan olarak device flow kullanılmalıdır
  • Uç noktalar .well-known/openid-configuration ile keşfedilmeli, URL’ler sabit kodlanmamalıdır
  • interval ve slow_down kurallarına mutlaka uyulmalıdır
  • Refresh token, ~/.config altındaki JSON dosyasında değil OS keychain içinde saklanmalıdır
  • Hızlı dizüstü girişleri için loopback yolu sunulmak isteniyorsa bu, --web bayrağının arkasında olmalı; varsayılan olmamalıdır

Zaten geçiş yapan CLI’lar ve geride kalan araçlar

  • Device flow’u varsayılan kullanan CLI’lar var
    • gh auth login, baştan beri device flow kullanıyor ve açık kaynak dünyasında en temiz referans uygulamalardan biri sayılıyor
    • aws sso login, IAM Identity Center için device flow’u uçtan uca çalıştırıyor
    • vercel login, Eylül 2025’te RFC 8628’e geçti ve e-posta tabanlı girişiyle önceki --oob bayrağının yerini aldı
    • Stripe CLI, doğrudan RFC 8628 kullanmasa da kullanıcı deneyimi iyi tasarlanmış bir pairing-code flow uyguluyor
  • Hâlâ loopback flow’u varsayılan tutup üstüne paste-the-code fallback ekleyen araçlar da var
    • Google gcloud
    • Cloudflare wrangler
    • Anthropic claude
  • CLI, dizüstü dışındaki her ortamda manuel paste-the-code fallback gerektiriyorsa, o fallback’i doğrudan varsayılan akış olarak sunmak daha mantıklıdır

1 yorum

 
GN⁺ 4 시간 전
Lobste.rs görüşleri
  • İfade biraz özensiz ama ilginç. Cihaz kodu/bağlantısı 1 dakikada bir değiştirilirse, phishing için kötüye kullanılma ihtimali de azalabilir gibi görünüyor
    Bir kez kullanıldıktan sonra rotasyonu durdurup ilgili oturumu IP veya tarayıcıya bağlamak yeterli olur

    • Bu yöntem, yazıda söylendiği kadar büyük bir fayda sağlamıyor. Kullanıcı geldiğinde akışı başlatıp hemen meşru sağlayıcıya yönlendiren bir phishing landing page yapmak oldukça kolay
      Microsoft gibi kullanıcının kodu elle girdiği sağlayıcılarda, landing page bir yönerge gösterip kodu panoya kopyalayarak phishing’e düşmeyi daha da kolaylaştırabilir
  • Güzel bir yazı; herkesin RFC 8628 tarafına geçmesi gerektiğine katılıyorum
    Uzak geliştirme makinesinde CLI OAuth sürecini fazla sık yaşadığım için, xdg-open çağrılarını yakalayıp portları otomatik forward ederek kötü kullanıcı deneyimini gizleyen kişisel bir araç yazdım: https://github.com/phinze/bankshot

  • İlginç. Kısa süre önce tam da “eski” kimlik doğrulama yöntemi olan RFC 8252’yi uyguladım ama “yeni” yöntem olan RFC 8268’i bilmiyordum
    Ana kullanım senaryom Google sunucu kimlik doğrulaması olduğu için burada bir bilgi boşluğu oluşmuş gibi görünüyor. RFC 8268 akışı sandığım belgede şöyle açıkça yazıyor

    Alternatives

    If you are writing an app for a platform such as Android, iOS, macOS, Linux, or Windows (including the Universal Windows Platform), that has access to the browser and full input capabilities, use the OAuth 2.0 flow for mobile and desktop applications. (You should use that flow even if your app is a command-line tool without a graphical interface.)
    Bu yüzden doğrudan RFC 8252 akışını okuyup uyguladım. Aracım gerçekten bir CLI ama kullanım senaryosu yalnızca yerel olduğu için SSH veya container ortamlarını hesaba katmadım
    Ayrıca RFC 8268 akışında Google yalnızca sınırlı OAuth 2.0 scope’larına izin verdiğinden, bu bazı uygulamalar için belirleyici bir kısıt olabilir

    • Küçük bir düzeltme: orijinal numarayı tekrar kontrol ettim, RFC 8628’miş
      Google’ın scope kısıtlaması, OIDC’nin karmaşık şekilde ortaya çıktığı nokta. İdeal olarak Google’ın erişim token’ına tıkıştırması yerine bir ID token döndürmesi gerekir, ama bu Google’ın OAuth yapılandırma meselesi; 8628’in kendine özgü bir özelliği değil
      OAuth’nun bitmeyen karmaşıklığı buradan geliyor. Standart, yetkilendirme yapısını nasıl kurulup taşınacağı konusunda çerçeveyi iyi tanımlıyor, ama bunun neyi temsil etmesi gerektiği konusunda bilinçli olarak sessiz kalıyor. “Çoğu” sağlayıcının uzlaştığı ortak HTTP endpoint kümesini elde etmek için bile OIDC’nin icadı ve yıllar gerekmişti
  • Bir başka hack de sunucudaki xdg-open çağrısını dizüstüne forward etmek. Kişisel altyapım için bunu yapan küçük bir araç yazdım: https://github.com/zimbatm/subportal/

  • Bu iki yaklaşım birleştirilemez mi? localhost URL’sine redirect edip hello geri döndürmesini sağlarsın; istemci hello alamazsa CLI’de URL’yi yazdırırsın
    Aynı anda, sunucunun gönderdiği helloya yanıt gelmezse tarayıcıda bir kod gösterip “giriş yapmaya çalışanın siz olduğunu doğrulayın” gibi bir mesaj gösterebilirsin. Google’daki gibi telefonda seçilecek sayılar göstererek bunu daha da kolaylaştırmak mümkün

    cli -> server/auth?r=localhost&fallback_choices=10,20,30  
    server -> localhost/hello
    
    Case 1: hello request received, go to redirect URI on localhost  
    Case 2: server has not received a hello reply, client has not received a hello request
    - CLI displays a/the webpage url and prompts for selecting a fallback_choice
    - Webpage displays a number say `20` from choices
      - Warn in the webpage not to share this code
    - User enters/selects it on the CLI
      - solves the token copy/paste problem if choices  
    

    Bunun avantajı, 2. durumda bile insanların bağlantıya tıklamayı kolay bulmasına rağmen OTP/kod paylaşımını nispeten daha az yapması ve saldırganın saldırı sırasında sosyal mühendislikle sürekli devrede kalmak zorunda olması

  • Yerel makinede düzgün çalıştığında etkileşim gerekmiyor; bu yüzden varsayılanın tarayıcı tabanlı akış olmasını isterdim

    • Bu akış da iyi çalıştığı durumlarda tarayıcı tabanlı işliyor. Sadece başarısız olduğunda daha iyi bir fallback yol sunuyor