---
title: 'Tarayıcıda Kimlik Doğrulama'
source: 'https://academia.sh/tr/kurslar/frontend-mimarisi/tarayicida-kimlik-dogrulama'
course: 'Uygulama Mimarisi: Yönlendirme, Durum ve Veri'
language: tr
updated: '2026-08-17T18:09:20+00:00'
license: 'CC BY-SA 4.0'
---

# Tarayıcıda Kimlik Doğrulama

Kimlik doğrulama ile yetkilendirmenin ayrımı, oturum çerezi ile taşıyıcı belirtecin karşılaştırılması, belirteç gövdesinin okunabilirliği, üç saklama seçeneğinin risk–fayda çözümlemesi ve çerez niteliklerinin işlevi.

Ölçüm giriş formu artık değerini tutuyor, kurallarını iki tarafta aynı biçimde uyguluyor ve
hatasını herkesin algılayabileceği biçimde sunuyor. Geriye formun sorduğu bir soru kaldı:
bu ölçümü kim giriyor? Kuzey Yamaç kayıtlarına herkes yazamaz; gözlemcinin önce tanınması
gerekir.

Bu ders kimlik akışının **istemci tarafını** ele alır: sunucu gözlemciyi tanıdıktan sonra
verdiği kimlik kanıtı tarayıcıda nerede durur, hangi istekle birlikte gider ve bu kararın
hangi riskleri açıp hangilerini kapattığı. Kapsam bilinçli olarak dardır — istemci
güvenliğinin bütünü, içerik güvenlik ilkesi ve kaynaklar arası paylaşım dahil, Frontend
Kalitesi kursunun güvenlik konusunda ele alınır. Burada yalnız kimlik akışının kendisi
vardır.

## Kimlik Doğrulama ile Yetkilendirme Ayrı Katmanlardır

**Kimlik doğrulama (authentication)**, "sen kimsin" sorusunun yanıtıdır. Gözlemci
kullanıcı adı ve parolasını verir, sunucu bunu doğrular ve bir kimlik kanıtı üretir.

**Yetkilendirme (authorization)**, "bunu yapabilir misin" sorusunun yanıtıdır. Tanınmış bir
gözlemcinin KY-01 istasyonuna ölçüm yazma hakkı olabilir, KY-02'ye olmayabilir.

İkisinin ayrı tutulması bir söz oyunu değildir. Yetkilendirme kararı **her zaman sunucuda**
verilir; istemcinin yaptığı, kullanıcının erişemeyeceği bir düğmeyi göstermemektir. Bu
görsel eleme bir güvenlik denetimi değil, bir kullanışlılık iyileştirmesidir: düğmeyi
gizlemek, isteğin başka yollarla kurulmasını engellemez.

## İki Taşıma Biçimi

Kimlik kanıtının istekle birlikte gitmesinin iki yolu vardır.

**Oturum çerezi**, sunucunun ürettiği rastgele bir tanımlayıcıyı taşır. Tanımlayıcının
kendisi bir anlam taşımaz; sunucu onu kendi oturum kayıtlarında arar ve karşılığındaki
kullanıcıyı bulur. Çerez, tarayıcı tarafından **kendiliğinden** gönderilir; uygulama kodu
her isteğe bir şey eklemez.

**Taşıyıcı belirteç (bearer token)**, kullanıcı bilgisini kendi içinde taşıyan imzalı bir
dizgidir. JWT bu biçimin yaygın bir örneğidir. Sunucu her istekte kayıt aramak zorunda
kalmaz, imzayı doğrulayıp gövdedeki iddialara bakar. Belirteç bir başlıkla elle gönderilir;
tarayıcı bunu kendiliğinden yapmaz.

Ayrımın iki pratik sonucu vardır. Kendiliğinden gönderilme, oturum çerezini **kaynaklar
arası istek sahteciliğine (CSRF)** açık kılar: başka bir sayfadan tetiklenen bir istek de
çerezi yanında götürür. Elle gönderilme, taşıyıcı belirteci bu riskten uzak tutar ama
belirtecin bir yerde saklanmasını zorunlu kılar — ve saklandığı yer yeni bir risk açar.
Bu ödünleşim dersin çekirdeğidir.

Kendi içinde bilgi taşımanın ikinci sonucu **geri alınamazlıktır**. Oturum kaydı sunucuda
silinince oturum o an biter. İmzalı bir belirteç ise süresi dolana kadar geçerli kalır;
iptal edilmesi için sunucunun ayrıca bir geçersizler listesi tutması gerekir — ki bu, kayıt
tutmama kazancını büyük ölçüde geri verir. Uygulamada bu, belirteçlerin **kısa ömürlü**
tutulmasıyla dengelenir.

## Belirteç Gövdesi Gizli Değildir

Belirteç imzalıdır; bu, içeriğinin **değiştirilemeyeceği** anlamına gelir, gizli olduğu
anlamına gelmez. Aradaki fark, belirtecin içine ne konacağı ve istemcinin onunla ne
yapabileceği sorularını doğrudan belirler.

```js
// belirtec-okuma.mjs — belirtecin istemcide ne kadar okunabilir oldugu
import { createHmac, timingSafeEqual } from "node:crypto";

const b64 = (v) => Buffer.from(typeof v === "string" ? v : JSON.stringify(v))
  .toString("base64url");

// --- Sunucu tarafi: belirteci uretir ve imzalar -----------------------------
const GIZLI = "yalnız-sunucuda-duran-anahtar";
const SIMDI = 1768348800;                     // 2026-01-14T12:00:00Z, sinama icin sabit

function belirtecUret(iddialar, gizli) {
  const govde = `${b64({ alg: "HS256", typ: "JWT" })}.${b64(iddialar)}`;
  const imza = createHmac("sha256", gizli).update(govde).digest("base64url");
  return `${govde}.${imza}`;
}

const belirtec = belirtecUret({
  sub: "gozlemci-3", rol: "yazar", istasyon: "KY-01",
  iat: SIMDI, exp: SIMDI + 900,               // 15 dakika
}, GIZLI);

console.log("belirteç:", belirtec);

// --- Istemci tarafi: govdeyi imzayi dogrulamadan okur -----------------------
function govdeyiOku(belirtec) {
  const parcalar = belirtec.split(".");
  if (parcalar.length !== 3) return null;
  try { return JSON.parse(Buffer.from(parcalar[1], "base64url").toString("utf8")); }
  catch { return null; }
}

const iddialar = govdeyiOku(belirtec);
console.log("istemcinin okuduğu gövde:", JSON.stringify(iddialar));

// Sure denetimi bir kullanislilik hesabidir, bir yetki karari degildir.
const PAY = 30;                               // saat kaymasi payi (saniye)
const suresiDoldu = (i, simdi) => simdi >= i.exp - PAY;
for (const simdi of [SIMDI, SIMDI + 600, SIMDI + 880, SIMDI + 1000]) {
  console.log(
    `t=${String(simdi - SIMDI).padStart(4)}s  kalan=${String(iddialar.exp - simdi).padStart(4)}s`,
    ` yenilensin mi: ${suresiDoldu(iddialar, simdi) ? "evet" : "hayır"}`);
}

// --- Sunucu tarafi: imza dogrulamasi ---------------------------------------
function imzaGecerliMi(belirtec, gizli) {
  const [b, g, imza] = belirtec.split(".");
  const beklenen = createHmac("sha256", gizli).update(`${b}.${g}`).digest("base64url");
  const a = Buffer.from(imza), c = Buffer.from(beklenen);
  return a.length === c.length && timingSafeEqual(a, c);
}

// Govdesi degistirilmis bir belirtec: rol "yazar" yerine "yonetici".
const [bas, , eskiImza] = belirtec.split(".");
const degisik = `${bas}.${b64({ ...iddialar, rol: "yonetici" })}.${eskiImza}`;

console.log("\nözgün belirteç, sunucu doğrulaması :", imzaGecerliMi(belirtec, GIZLI));
console.log("gövdesi değiştirilmiş, sunucu       :", imzaGecerliMi(degisik, GIZLI));
console.log("gövdesi değiştirilmiş, istemci okur :",
  JSON.stringify(govdeyiOku(degisik).rol));
```

```
belirteç: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJnb3psZW1jaS0zIiwicm9sIjoieWF6YXIiLCJpc3Rhc3lvbiI6IktZLTAxIiwiaWF0IjoxNzY4MzQ4ODAwLCJleHAiOjE3NjgzNDk3MDB9.gwTdVAyLlHGq0DNaEXcRIsRnVA24TMTg5Q4ylPoN0aY
istemcinin okuduğu gövde: {"sub":"gozlemci-3","rol":"yazar","istasyon":"KY-01","iat":1768348800,"exp":1768349700}
t=   0s  kalan= 900s  yenilensin mi: hayır
t= 600s  kalan= 300s  yenilensin mi: hayır
t= 880s  kalan=  20s  yenilensin mi: evet
t=1000s  kalan=-100s  yenilensin mi: evet

özgün belirteç, sunucu doğrulaması : true
gövdesi değiştirilmiş, sunucu       : false
gövdesi değiştirilmiş, istemci okur : "yonetici"
```

Çıktı üç kural veriyor.

**Gövde herkesin okuyabileceği bir metindir.** Kodlama bir şifreleme değildir; belirteci
eline geçiren herkes içindekini okur. Bu yüzden gövdeye kullanıcının kimliği ve
yetki adları dışında bir şey — kişisel bilgi, iç sistem kimlikleri, gizli değer —
konmaz.

**İmza değişikliği yakalar ama yalnız sunucuda.** Değiştirilmiş belirteç sunucu
doğrulamasından geçmedi; imza gövdeyle uyuşmuyor. Aynı belirtecin gövdesini istemci
sorunsuz okuyor ve rolü "yonetici" görüyor. Yani **istemcinin okuduğu rol bir iddia
değildir, yalnızca bir gösterimdir**. Arayüz bu bilgiyle menü çizebilir; erişim kararı
veremez.

**Süre denetimi bir kullanışlılık hesabıdır.** İstemci `exp` alanına bakıp belirteci
süresi dolmadan yenileyebilir; böylece kullanıcı 401 yanıtıyla karşılaşmaz. Ama bu denetim
bir yetki kararı değildir: istemcinin saati yanlış olabilir, gövde değiştirilmiş olabilir.
Örnekteki otuz saniyelik pay, saat kaymasına karşı konur ve kararı erkene çeker. Kararı
veren yine sunucudur.

## Belirteç Deposu: Üç Seçenek

Belirtecin nerede saklanacağı üç seçeneğe indirgenir ve üçü farklı riskleri açar. Tabloda
"betik çalıştırılırsa" ifadesi, sayfada uygulamaya ait olmayan bir betiğin çalıştığı
durumu — siteler arası betik çalıştırma, XSS — anlatır.

| Ölçüt | Bellekte değişken | Web Storage | `HttpOnly` çerez |
|---|---|---|---|
| Betik çalıştırılırsa okunur mu | Evet (aynı çalışma bağlamında) | Evet, doğrudan | Hayır, betikten erişilemez |
| Sahtecilik (CSRF) riski | Yok, elle gönderilir | Yok, elle gönderilir | Var; nitelikler ve belirteçle daraltılır |
| Sayfa yenilenince | Kaybolur | Kalır | Kalır |
| Sekmeler arasında | Paylaşılmaz | Paylaşılır | Paylaşılır |
| Alt alan adlarına sızma | Yok | Kaynak başına ayrıdır | `Domain` yazılırsa olur |
| Sunucu tarafında iptal | Ömür kısaysa kolay | Ömür kısaysa kolay | Oturum kaydıyla anında |

Tablodan çıkan tek bir "doğru seçenek" yoktur; iki yaygın ve savunulabilir düzen vardır.

**Erişim belirteci bellekte, yenileme `HttpOnly` çerezde.** Kısa ömürlü erişim belirteci
hiçbir kalıcı depoya yazılmaz; sayfa yenilendiğinde kaybolur ve çerezle yapılan bir
yenileme isteğiyle yeniden alınır. Betik çalıştırılırsa erişim belirteci okunabilir ama
ömrü dakikalarla sınırlıdır; yenileme belirtecine hiç erişilemez.

**Her şey `HttpOnly` çerezde, oturum kaydı sunucuda.** Betikten hiçbir kimlik değeri
okunamaz ve iptal anında yapılabilir. Karşılığında sahtecilik riski üstlenilir ve
niteliklerle daraltılır.

Kaçınılması gereken düzen, **yenileme belirtecinin Web Storage'da tutulmasıdır**: uzun
ömürlü bir kimlik kanıtı, betikten okunabilen bir yerde durur. Kısa ömürlü erişim
belirtecinin Web Storage'da tutulması ise bir ödünleşimdir — sayfa yenilenmesine dayanma
kazancı karşılığında okunabilirlik riski alınır.

Depolama seçiminin sınırı şudur: **betik çalıştırılabiliyorsa depo neredeyse önemsizdir.**
Belirteç `HttpOnly` çerezde olsa bile, sayfada çalışan bir betik kullanıcının adına istek
gönderebilir. Depolama kararı riski daraltır, ortadan kaldırmaz; asıl savunma, betiğin hiç
çalıştırılamamasıdır ve o savunma Frontend Kalitesi kursunun konusudur.

## Çerez Niteliklerinin İşlevi

Çerez kullanan düzenlerde dört nitelik doğrudan güvenlik işlevi taşır ve dördü de sunucunun
yazdığı başlıkta bildirilir.

`HttpOnly`, çerezin betikten okunmasını engeller. Bu nitelik yazılmamışsa çerez, Web
Storage'dan farksız biçimde okunabilir hâle gelir.

`Secure`, çerezin yalnız şifreli bağlantıda gönderilmesini sağlar. Yerel geliştirme
adresleri dışında istisnası yoktur.

`SameSite`, çerezin başka bir siteden tetiklenen isteklerde gönderilip gönderilmeyeceğini
belirler. `Strict` hiçbir dış bağlamda göndermez ve dış bağlantıyla gelen kullanıcının
oturumsuz görünmesine yol açar; `Lax` üst düzey gezinmelerde gönderir, gömülü isteklerde
göndermez; `None` her durumda gönderir ve yalnız `Secure` ile birlikte kullanılabilir.
Sahtecilik riskini asıl daraltan nitelik budur, ama tek başına yeterli sayılmaz: durum
değiştiren istekler ayrıca bir sahtecilik belirteciyle korunur.

`Path` ve `Domain`, çerezin gönderileceği yolları ve alan adlarını belirler. `Domain`
yazmak çerezi bütün alt alan adlarına açar; bir alt alan adı ele geçtiğinde oturumun da
etkilenmesi demektir. Yazılmadığında çerez yalnız kendi ana bilgisayar adına gider ki
çoğu durumda istenen budur. Çerez adına konan `__Host-` öneki bu daraltmayı kural hâline
getirir: bu önekli bir çerez ancak `Secure` ile, `Domain` yazılmadan ve kök yolla kabul
edilir.

## İstemcinin Kimlik Durumu

Uygulamanın "oturum açık mı" sorusuna verdiği yanıt da bir durum parçasıdır ve Durum
Yönetimi konusundaki ayrımlara uyar. Bu durum, belirtecin kendisinden değil,
**belirtecin varlığı ve sunucunun yanıtlarından** türetilir.

Uygulama açılışında kimlik durumu bilinmez. Bellekte belirteç tutan bir düzende sayfa
yenilendiğinde elde hiçbir şey yoktur; oturumun sürüp sürmediğini öğrenmenin tek yolu
sunucuya sormaktır. Bu, kimlik durumunun dördüncü bir değeri olduğu anlamına gelir:
`bilinmiyor`. Bu değer olmadan yazılan arayüzler, açılışta bir an için oturum kapalı
görünür ve kullanıcıyı giriş ekranına atar.

Rota koruma da bu duruma bağlanır. Yönlendirme konusundaki rota koruma kuralı istemci
tarafında **görünürlüğü** yönetir; korunan bir rotanın verisi yine sunucudan 401 alarak
korunur. İstemci koruması atlanabilir; sunucu koruması atlanamaz.

## Özet

- Kimlik doğrulama "kimsin", yetkilendirme "bunu yapabilir misin" sorusudur; yetki kararı
  her zaman sunucuda verilir, istemci yalnız görünürlüğü yönetir.
- Oturum çerezi tarayıcı tarafından kendiliğinden gönderilir ve sahteciliğe açıktır;
  taşıyıcı belirteç elle gönderilir ve saklanmak zorundadır.
- Belirtecin imzalı olması içeriğinin değiştirilemez olduğunu söyler, gizli olduğunu değil;
  gövde herkesçe okunabilir ve istemcinin okuduğu rol bir yetki kanıtı değildir.
- Süre denetimi istemcide bir kullanışlılık hesabıdır; saat kayması payıyla erkene çekilir
  ama kararı sunucu verir.
- Üç saklama seçeneği farklı riskler açar; savunulabilir iki düzen, erişim belirtecini
  bellekte yenilemeyi `HttpOnly` çerezde tutmak ya da her şeyi çerezde tutup sahteciliğe
  karşı ayrıca korunmaktır.
- `HttpOnly`, `Secure`, `SameSite` ve `Domain` nitelikleri riski daraltır; sayfada betik
  çalıştırılabiliyorsa hiçbir depolama seçeneği tek başına korumaz.

## Sonraki Adım

Bu ders belirtecin kısa ömürlü olmasını bir savunma olarak sundu ama kısa ömrün bir bedeli
var: on beş dakikada bir oturumun düşmesi. Gözlemci ölçüm formunu doldururken belirtecin
süresi dolarsa gönderim 401 ile döner ve yazdığı her şey tehlikeye girer. Sonraki ders bu
bedeli ödemeden kısa ömrü korumanın yolunu kurar: kullanıcı fark etmeden yapılan yenileme,
aynı anda düşen birden çok isteğin tek bir yenilemede toplanması ve oturumun her yerde
aynı anda kapanması.
