Application Security

Modern Web Güvenliğini Sağlama: SPAs ve Mobil İstemciler İçin OAuth2 PKCE Uygulama

Yıllar boyunca yetkilendirme kodu akışı, web uygulamalarını güvence altına almak için altın standarttı. Ancak Tek Sayfa Uygulamaları (SPA'lar) ve yerel mobil istemciler benzersiz bir zorluk getirdi: bunlar "kamusal istemcilerdir". Geleneksel sunucu taraflı uygulamaların aksine, bu istemciler bir istemci sırrını güvenli bir şekilde saklayamazlar. Bu güvenlik açığı, kötü niyetli aktörlerin yetkilendirme kodlarını ele geçirip yasal kullanıcıları taklit etmesine olanak tanıyan, yetkilendirme kodu ele geçirme olarak bilinen bir tehdit kapısını araladı.

Sektörün yanıtı, RFC 7636'da tanımlanan PKCE'nin (Kod Değişimi İçin Kanıt Anahtarı) tanıtılmasıydı. PKCE, bir istemci sırrı gerektirmeden güvenlik katmanı ekleyerek kamusal istemciler için OAuth2'nin zorunlu standardı haline geldi. Bu yazı, PKCE'nin mekaniklerini ve güvenli bir şekilde nasıl uygulanacağını ara seviyeden ileri seviye geliştiricilere adım adım anlatacaktır.

Neden PKCE Kamusal İstemciler İçin Pazarlık Konusu Değildir

Koda dalmadan önce, tehdit modelini anlamak hayati önem taşır. PKCE olmadan standart bir yetkilendirme kodu akışında süreç şu şekilde işler:

  1. İstemci, kullanıcıyı Yetkilendirme Sunucusuna yönlendirir.
  2. Kullanıcı kimlik doğrulamasını tamamlar ve izin verir.
  3. Yetkilendirme Sunucusu, bir yetkilendirme kodu ile istemciye geri yönlendirme yapar.
  4. İstemci, istemci kimliği ve sırrını kullanarak kodu bir erişim jetonuyla değiştirir.

SPA'larda veya mobil uygulamalarda sırrı tutacak bir arka uç (backend) yoktur. Bir saldırgan yetkilendirme kodunu ele geçirebilirse (XSS, kötü amaçlı yazılım veya ağ dinleme yoluyla), bu kodu kullanarak bir erişim jetonu talep edebilir ve böylece kullanıcının oturumunu devralabilir. PKCE, yetkilendirme kodunu, başlangıçtaki istem sırasında istemcinin bildiği tek bir kriptografik anahtara bağlayarak bu sorunu çözer.

PKCE İş Akışı Açıklaması

PKCE akışı iki bileşen getirir: code_verifier ve code_challenge.

  • Kod Doğrulayıcı (Code Verifier): İstemci tarafından oluşturulan yüksek entropili kriptografik rastgele bir dizedir.
  • Kod Meydan Okuması (Code Challenge): Doğrulayıcının dönüştürülmüş bir versiyonudur ve başlangıçtaki oturum açma isteği sırasında Yetkilendirme Sunucusuna gönderilir.

İstemci daha sonra kodu bir jetonla değiştirdiğinde, orijinal code_verifier'ı gönderir. Yetkilendirme Sunucusu bu doğrulayıcıyı dönüştürür ve daha önce aldığı code_challenge ile karşılaştırır. Eğer eşleşirlerse, jeton verilir.

Uygulama: Kod Doğrulayıcı ve Meydan Okumasının Oluşturulması

Meydan okumayı oluşturmanın en güvenli yöntemi S256 dönüşümünü kullanmaktır. Bu, kod doğrulayıcısının SHA-256 karma değerini alıp sonucun URL'ye güvenli Base64 kodlamasını yapmayı içerir.

İşte bir tarayıcı ortamında bu değerleri oluşturmak için pratik bir JavaScript uygulaması:

function generateRandomString(length) {
  const array = new Uint32Array(length / 2);
  window.crypto.getRandomValues(array);
  return Array.from(array, dec => ('0' + dec.toString(16)).slice(-2)).join('');
}

async function createVerifier() {
  // 43 ile 128 karakter arasında rastgele bir dize oluştur
  const verifier = generateRandomString(32);
  return verifier;
}

async function createChallenge(verifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const hash = await window.crypto.subtle.digest('SHA-256', data);
  
  // Base64 URL Kodlu dizeye dönüştür
  const base64encoded = btoa(String.fromCharCode(...new Uint8Array(hash)));
  return base64encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}

Yetkilendirme İsteğinin Yürütülmesi

code_verifier ve code_challenge hazır olduğunda, kullanıcıyı Yetkilendirme Sunucusuna yönlendirmeniz gerekir. Burada kritik eklenenler code_challenge ve code_challenge_method=S256 parametreleridir.

const params = new URLSearchParams({
  client_id: 'YOUR_CLIENT_ID',
  redirect_uri: 'http://localhost:3000/callback',
  response_type: 'code',
  scope: 'openid profile email',
  code_challenge: codeChallenge,
  code_challenge_method: 'S256'
});

window.location.href = `https://auth-server.com/authorize?${params}`;

Jeton Değişiminin İşlenmesi

Kullanıcı erişimi onayladıktan sonra, URL sorgu dizgisinde bir yetkilendirme kodu ile redirect_uri'nize geri yönlendirilir. Son adım, bu kodu bir erişim jetonuyla değiştirmektir. Kritik olan nokta, akışın başında oluşturduğunuz code_verifier'ı göndermeniz gerektiğidir.

const tokenResponse = await fetch('https://auth-server.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'authorization_code',
    code: authorizationCode, // URL sorgu parametrelerinden
    redirect_uri: 'http://localhost:3000/callback',
    client_id: 'YOUR_CLIENT_ID',
    code_verifier: codeVerifier // Orijinal rastgele dize
  })
});

const tokens = await tokenResponse.json();

Sonuç

SPA'lar veya mobil uygulamalar geliştiren geliştiriciler için PKCE uygulamak artık isteğe bağlı değildir. Sadece birkaç satır kriptografik mantık ekleyerek kullanıcılarınızı yetkilendirme kodu ele geçirme saldırılarına karşı korursunuz. İlk kurulum, durumun dikkatli bir şekilde yönetilmesini ve code_verifier'ın güvenli bir şekilde saklanmasını gerektirse de, uygulama güvenliğine sağladığı uzun vadeli faydalar büyüktür. Ekosistem daha sıkı güvenlik standartlarına doğru ilerledikçe, PKCE'yi benimsemek uygulamalarınızın sağlam, uyumlu ve kullanıcı tarafından güvenilen kalmasını sağlar.

Share: