JSON Web Belirteçleri (JWT) standardı, doğrulanabilir veri aktarımları için kompakt bir yöntem tanımlar. Her belirteç, veren tarafın mesajın bütünlüğünü kontrol etmesine izin veren bir imza içerir.
Bu makalede, JWT yapısının neler içerdiğini ve kendi jetonlarınızı nasıl oluşturabileceğinizi öğreneceksiniz. JWT’ler, basit ve bağımsız oldukları için API’lerin güvenliğini sağlamanın ve kullanıcı oturumlarının kimliğini doğrulamanın popüler bir yoludur.
JWT’ler Nasıl Çalışır?
Herhangi bir API’deki en yaygın görevlerden biri, kullanıcıların iddia ettikleri kişi olduklarını doğrulamaktır. Kimlik doğrulama, genellikle istemcinin, sunucuya gönderdiği isteklerle birlikte bir API anahtarı içermesini sağlayarak gerçekleştirilir. Anahtar, kullanıcıyı tanımlayan gömülü bilgileri içerir. Bu hala büyük bir soru bırakıyor: Sunucu, anahtarı ilk etapta verdiğini nasıl doğrulayabilir?
JWT’ler, her belirteci imzalamak için bir sır kullanarak bu sorunu kolayca çözer. Sunucu, özel sırrını kullanarak sunulan imzayı yeniden hesaplamaya çalışarak bir belirtecin geçerliliğini kontrol edebilir. Herhangi bir kurcalama, doğrulamanın başarısız olmasına neden olur.
JWT Formatı
JWT’ler üç farklı bileşenden oluşur:
- başlık – Bu, kullanılan imzalama algoritması gibi belirtecin kendisiyle ilgili meta verileri içerir.
- yük – Belirtecin yükü, sisteminizle ilgili herhangi bir rastgele veri olabilir. Kullanıcının kimliğini ve etkileşimde bulunabilecekleri özelliklerin bir listesini içerebilir.
- İmza – İmza, belirtecin bütünlüğünün gelecekte doğrulanmasını sağlar. Yalnızca sunucu tarafından bilinen gizli bir değer kullanılarak başlık ve yük imzalanarak oluşturulur.
Bu üç bileşen, JWT’yi üretmek için periyotlarla birleştirilir:
header.payload.signature
Her parça Base-64 kullanılarak kodlanmıştır. Tam belirteç, programlama ortamlarında kolayca tüketilebilen ve HTTP istekleriyle gönderilebilen bir metin dizisidir.
JWT Oluşturma
JWT oluşturma adımları tüm programlama dillerinde uygulanabilir. Bu örnek PHP’yi kullanıyor ancak süreç kendi sisteminizde benzer olacaktır.
Başlığı oluşturarak başlayın. Bu genellikle iki alan içerir, alg
ve typ
:
alg
– İmzayı oluşturmak için kullanılacak karma algoritması. Bu normalde HMAC SHA256’dır (HS256
).typ
– Oluşturulan belirteç türü. bu olmalıJWT
.
İşte başlığı tanımlayan JSON:
{ "alg": "HS256", "typ": "JWT" }
JSON başlığının daha sonra Base64 ile kodlanması gerekir:
$headerData = ["alg" => "HS256", "typ" => "JWT"]; $header = base64_encode(json_encode($headerData));
Ardından, simgenizin yükünü başka bir JSON nesnesi olarak tanımlayın. Bu uygulamaya özeldir. Örnek, kimliği doğrulanmış kullanıcı hesabının ayrıntılarını ve belirtecin kendisiyle ilgili bilgileri sunar. exp
, iat
ve nbf
belirtecin sona erme süresini ifade etmek için sözleşme tarafından kullanılan, zamanında verilen ve (başlangıç) zamanından önce geçerli olmayan alanlardır. Yükün de Base64 ile kodlanmış olması gerekir.
$payloadData = [ "userId" => 1001, "userName" => "demo", "licensedFeatures" => ["todos", "calendar", "invoicing"], "exp" => (time() + 900), "iat" => time(), "nbf" => time() ]; $payload = base64_encode(json_encode($payloadData));
Geriye sadece imzayı oluşturmak kalıyor. Bunu üretmek için önce başlığı ve yükü bir ile ayrılmış tek bir dizgede birleştirirsiniz. .
karakter:
$headerAndPayload = "$header.$payload";
Ardından, imzalama anahtarınız olarak kullanmak için benzersiz bir sır oluşturmalısınız. Sır, sunucunuzda güvenli bir şekilde saklanmalı ve asla istemcilere gönderilmemelidir. Bu değerin ortaya çıkması, herkesin geçerli belirteçler oluşturmasına izin verir.
// PHP method to generate 32 random characters $secret = bin2hex(openssl_random_pseudo_bytes(16));
Birleştirilmiş başlık ve yük dizesini, başlıkta belirttiğiniz karma algoritmayı kullanarak imzalamak için sırrı kullanarak işlemi tamamlarsınız. Çıktı imzası, diğer bileşenler gibi Base64 ile kodlanmış olmalıdır.
$signature = base64_encode(hash_hmac("sha256", $headerAndPayload, $secret, true));
Artık ayrı metin bileşenleri olarak başlık, veri yükü ve imzaya sahipsiniz. Hepsine birlikte katıl .
müşterinize gönderilecek JWT’yi oluşturmak için ayırıcılar:
$jwt = "$header.$payload.$signature";
Gelen JWT’leri Doğrulama
İstemci uygulaması, belirtecin yükünün kodunu çözerek kullanıcının kullanabileceği özellikleri belirleyebilir. İşte JavaScript’te bir örnek:
const tokenComponents = jwt.split("."); const payload = token[1]; const payloadDecoded = JSON.parse(atob(payload)); // ["todos", "calendar", "invoicing"] console.log(payloadDecoded.licensedFeatures);
Saldırgan, bu verilerin düz metin olduğunu ve değiştirilmesinin kolay göründüğünü fark edebilir. Bir sonraki isteklerinde belirtecin yükünü değiştirerek sunucuyu bir bonus özelliği olduğuna ikna etmeye çalışabilirler:
// Create a new payload component const modifiedPayload = btoa(JSON.stringify({ ...payloadDecoded, licensedFeatures: ["todos", "calendar", "invoicing", "extraPremiumFeature"] })); // Stitch the JWT back together with the original header and signature const newJwt = `${token[0]}.${modifiedPayload}.${token[2]}`
Sunucunun bu saldırılara karşı nasıl savunduğunun cevabı, imzayı oluşturmak için kullanılan yöntemde yatmaktadır. İmza değeri, belirtecin başlığını ve yükünü dikkate alır. Bu örnekte olduğu gibi yükü değiştirmek, imzanın artık geçerli olmadığı anlamına gelir.
Sunucu tarafı kodu, gelen JWT’leri imzalarını yeniden hesaplayarak doğrular. İstemci tarafından gönderilen imza, sunucuda oluşturulan değerle eşleşmezse belirteç üzerinde oynanmıştır.
$tamperedToken = $_POST["apiKey"]; list($header, $payload, $signature) = $tamperedToken; // Determine the signature this token *should* have // when the server's secret is used as the key $expectedSignature = hash_hmac("sha256", "$header.$payload", $secret, true); // The token has been tampered with because its // signature is incorrect for the data it includes if ($signature !== $expectedSignature) { http_response_code(403); } // The signatures match - we generated this // token and can safely trust its data else { $user = fetchUserById($payload["userId"]); }
Bir saldırganın sunucunun sırrına erişmeden geçerli bir belirteç oluşturması imkansızdır. Bu aynı zamanda, sırrın kazara kaybının – veya kasıtlı olarak döndürülmesinin – önceden verilmiş tüm jetonları derhal geçersiz kılacağı anlamına gelir.
Gerçek dünya durumunda, kimlik doğrulama kodunuz, belirtecin yükündeki sona erme ve “önceden değil” zaman damgalarını da incelemelidir. Bunlar, kullanıcının oturumunun hala geçerli olup olmadığını belirlemek için kullanılır.
JWT’ler Ne Zaman Kullanılır?
JWT’ler, sunucuda uygulanması basit, istemcide tüketilmesi ve ağ sınırları arasında iletilmesi basit olduğu için API kimlik doğrulaması için sıklıkla kullanılır. Sadeliklerine rağmen iyi bir güvenlikleri vardır çünkü her belirteç sunucunun gizli anahtarı kullanılarak imzalanır.
JWT’ler durumsuz bir mekanizmadır, bu nedenle sunucunuzda verilen belirteçler hakkında bilgi kaydetmeniz gerekmez. Bir veritabanında arama yapmak yerine, jetonun yükünden bir JWT sunan istemci hakkında bilgi alabilirsiniz. Belirtecin imzasını doğruladıktan sonra bu bilgilere güvenle güvenilebilir.
İki taraf arasında kurcalama riski olmadan bilgi alışverişi yapmanız gerektiğinde JWT’leri kullanmak iyi bir seçimdir. Yine de dikkat edilmesi gereken zayıf noktalar vardır: Sunucunuzun gizli anahtarı sızdırılırsa veya imza doğrulama kodunuz bir hata içeriyorsa tüm sistem tehlikeye girer. Bu nedenle birçok geliştirici, JWT oluşturma ve doğrulamayı uygulamak için açık kaynaklı bir kitaplık kullanmayı tercih eder. Tüm popüler programlama dilleri için seçenekler mevcuttur. Belirteçleri kendiniz doğruladığınızda gözetim riskini ortadan kaldırırlar.
Özet
JWT standardı, yerleşik bütünlük doğrulamasını içeren bir veri değişim biçimidir. JWT’ler, API sunucuları ve istemci uygulamaları arasındaki etkileşimleri güvence altına almak için yaygın olarak kullanılır. Sunucu, imzalarını yeniden üretebiliyorsa, gelen belirteçlere güvenebilir. Bu, belirtecin yükünden elde edilen bilgiler kullanılarak eylemlerin güvenli bir şekilde gerçekleştirilmesine olanak tanır.
JWT’ler uygundur ancak bazı dezavantajları vardır. Bir JWT’nin Base64 kodlu metin gösterimi, bir avuç dolusu yük alanınız varsa hızla büyüyebilir. Müşterinizin her istekte JWT göndermesi gerektiğinde bu kabul edilemez bir ek yük haline gelebilir.
JWT’lerin vatansızlığı da başka bir potansiyel dezavantajdır: bir kez verildikten sonra jetonlar değişmezdir ve süresi dolana kadar olduğu gibi kullanılmalıdır. Bir kullanıcının izinlerini veya lisanslı özelliklerini belirlemek için JWT yüklerini kullanan istemcilerin, atamaları değiştiğinde arka uçtan yeni bir belirteç alması gerekir.