---
title: 'Güvenli Depolama'
source: 'https://academia.sh/tr/kurslar/react-native/guvenli-depolama'
course: 'React Native'
language: tr
updated: '2026-10-21T05:02:54+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Gizli değerlerin neden düz anahtar–değer deposunda tutulmadığını açıklar'
    - 'Oturum kapanınca hesap alt ağacının sökülen olduğunu ölçer'
    - 'Açılışta belirtecin güvenli depodan okunup oturumu kurduğunu gösterir'
    - 'Belirtecin depodan silinmesinin görünüm ağacında görünmediğini ölçer'
---

# Güvenli Depolama

Oturum belirteci, parola ve anahtar gibi gizli değerler düz depoda durmaz; işletim sisteminin korumalı deposuna yazılır. Ders oturum kapanınca hesap alt ağacının sökülen olduğunu, belirtecin depodan silinmesinin ise ağaçta görünmediğini ölçer.

Önceki ders uygulama kapansa da kalan veriyi ele aldı. O verinin taslak gibi sıradan bir metin olması işi kolaylaştırıyordu. Oturum belirteci, parola ya da şifreleme anahtarı sıradan değildir: bunları ele geçiren, kullanıcının yerine geçer. Bu ders gizli değerlerin nerede durduğunu ve oturum kapanınca görünüm ağacında ne olduğunu ele alır.

Kursun sorusu değişmez: **bu güncelleme görünüm ağacındaki düğüme ne yapıyor?** Akıbet korunan, güncellenen, kurulan ya da sökülendir; güncellenen, kurulan ve sökülen düğümlerin toplamı komuttur. Akıbeti elle atamayız, kural verir:

```javascript
// fate.mjs — bir guncellemenin gorunum agacindaki her dugume ne yaptigini siniflandirir
export const FATES = ["korunan", "guncellenen", "kurulan", "sokulen"];

export function el(type, props = {}, children = [], key = null) {
  return { type, props, children, key };
}

function segment(node) {
  return node.key === null ? node.type : `${node.type}[${node.key}]`;
}

function identity(node, index) {
  return node.key === null ? `#${index}` : `key:${node.key}`;
}

function sameProps(a, b) {
  const names = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort();
  return names.every((n) => JSON.stringify(a[n]) === JSON.stringify(b[n]));
}

function whole(node, path, fate, ops) {
  const here = `${path}/${segment(node)}`;
  ops.push({ fate, path: here });
  node.children.forEach((child) => whole(child, here, fate, ops));
}

export function reconcile(prev, next, path = "", ops = []) {
  if (prev === null) {
    whole(next, path, "kurulan", ops);
    return ops;
  }
  if (next === null) {
    whole(prev, path, "sokulen", ops);
    return ops;
  }
  if (prev.type !== next.type || prev.key !== next.key) {
    whole(prev, path, "sokulen", ops);
    whole(next, path, "kurulan", ops);
    return ops;
  }
  const here = `${path}/${segment(next)}`;
  ops.push({ fate: sameProps(prev.props, next.props) ? "korunan" : "guncellenen", path: here });
  const before = new Map(prev.children.map((child, i) => [identity(child, i), child]));
  const matched = new Set();
  next.children.forEach((child, i) => {
    const id = identity(child, i);
    matched.add(id);
    reconcile(before.has(id) ? before.get(id) : null, child, here, ops);
  });
  prev.children.forEach((child, i) => {
    if (!matched.has(identity(child, i))) reconcile(child, null, here, ops);
  });
  return ops;
}

export function printOps(ops) {
  ops.forEach((op) => console.log(`${op.fate}: ${op.path}`));
}

export function countFates(ops) {
  for (const name of FATES) {
    console.log(`${name}: ${ops.filter((op) => op.fate === name).length}`);
  }
  console.log(`komut: ${ops.filter((op) => op.fate !== "korunan").length}`);
}
```

Model, bu akıbetin kuralını kurar; model çerçevenin kendisi değildir. Kural yalnız ağaçları karşılaştırır, gizli değerin nerede durduğunu görmez.

## Gizli Değer Nerede Durur

Düz anahtar–değer deposu uygulamanın veri dizininde, korumasız bir dosyada durur. Yedeğe girebilir, kök yetkisi alınmış bir telefondan okunabilir. Gizli değer için işletim sistemi ayrı bir yer sunar: güvenli anahtar deposu. Değer orada şifreli tutulur, erişim uygulamanın kimliğine ve çoğu zaman telefonun kilit durumuna bağlanır. Her platformun deposu kendi adıyla ve kendi kuralıyla gelir; çerçeve bunların üstüne tek bir yazma ve okuma yüzü koyar.

```swift
// Platform kodu: SecretStore
import Security

func saveToken(_ token: Data) -> Bool {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: "session-token",
        kSecValueData as String: token,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
    ]
    SecItemDelete(query as CFDictionary)
    return SecItemAdd(query as CFDictionary, nil) == errSecSuccess
}
```

Bu parça ölçülmez; model platformun deposunu çalıştırmaz. Dikkat edilecek nokta, yazmanın uygulamanın görünümünden tamamen ayrı bir çağrı olmasıdır: depoya yazan kod ekrana hiçbir şey çizmez.

**UK1.** Model güvenli depoyu bellekteki bir `Map` olarak kurar ve okuma, yazma, silmeyi `Promise` ile döndürür. Şifrelemeyi ve erişim koşullarını modellemez; ölçülen şey depoya yazmanın ya da depodan silmenin ağaçta ne bıraktığıdır.

```javascript
// vault.mjs — guvenli anahtar deposu: bellek ici Map, Promise ile yaz oku sil
const secrets = new Map();

export function saveSecret(key, value) {
  return Promise.resolve().then(() => {
    secrets.set(key, value);
  });
}

export function readSecret(key) {
  return Promise.resolve().then(() => (secrets.has(key) ? secrets.get(key) : null));
}

export function deleteSecret(key) {
  return Promise.resolve().then(() => {
    secrets.delete(key);
  });
}
```

**UK2.** Model uygulamanın ağacını oturum durumundan kurar: belirteç yoksa `Login`, varsa `Account` ve altında `Profile` ile `Orders`. Başlık her iki durumda da vardır. Belirtecin değerinin kendisi ağaca girmez; ağaç yalnız belirtecin var ya da yok olmasına bakar.

```javascript
// app.mjs — uygulamanin gorunum agacini oturum durumundan kurar
import { el } from "./fate.mjs";

export function renderApp(session) {
  const body = session.token === null
    ? el("Login", {})
    : el("Account", {}, [el("Profile", { ad: session.ad }), el("Orders", {})]);
  return el("App", {}, [el("Header", {}, [el("Title", { metin: "Hesabim" })]), body]);
}
```

Çerçevede bu seçim, belirteç durumuna bakan küçük bir ekran kapısıdır.

```jsx
// Platform kodu: AccountGate
function AccountGate({ token }) {
  return token ? <Account /> : <Login />;
}
```

## Oturum Kapanınca

Kullanıcı oturumu kapatır. Durumdaki belirteç silinir ve kapı `Login` ekranına döner.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderApp } from "./app.mjs";

const signedIn = renderApp({ token: "t-1", ad: "Ayse" });
const signedOut = renderApp({ token: null, ad: "" });
const ops = reconcile(signedIn, signedOut);
printOps(ops);
countFates(ops);
```

```text
korunan: /App
korunan: /App/Header
korunan: /App/Header/Title
sokulen: /App/Account
sokulen: /App/Account/Profile
sokulen: /App/Account/Orders
kurulan: /App/Login
korunan: 3
guncellenen: 0
kurulan: 1
sokulen: 3
komut: 4
```

`/App/Account` sökülendir ve onunla birlikte altındaki `Profile` ile `Orders` de sökülür: alt ağaç tek parça gider. Yerine `Login` kurulur. Başlık ve uygulamanın kendisi korunandır. Kullanıcının hesabına ait ekran durumu, kaydırma konumu, yarım yazdığı alan, bu düğümlerle birlikte yok olur. Bu sonuç M10/K02'deki ayrımla örtüşür: sökülenin durumu yok olur; akıbet ömrün yerini değil, güncellemenin düğüme yaptığını sınıflar.

## Açılışta Belirteci Okumak

Uygulama yeniden açıldığında bellekteki durum boştur. Oturumun sürüp sürmediğini yalnız güvenli depo bilir. Açılışta belirteç depodan okunur, durum buna göre kurulur.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderApp } from "./app.mjs";
import { saveSecret, readSecret } from "./vault.mjs";

const opening = renderApp({ token: null, ad: "" });
saveSecret("oturum", "t-1")
  .then(() => readSecret("oturum"))
  .then((token) => {
    const ops = reconcile(opening, renderApp({ token, ad: "Ayse" }));
    printOps(ops);
    countFates(ops);
  });
```

```text
korunan: /App
korunan: /App/Header
korunan: /App/Header/Title
sokulen: /App/Login
kurulan: /App/Account
kurulan: /App/Account/Profile
kurulan: /App/Account/Orders
korunan: 3
guncellenen: 0
kurulan: 3
sokulen: 1
komut: 4
```

Açılış ekranı `Login` ile başlar. Belirteç bulununca `Login` sökülür, `Account` ve altındaki iki düğüm kurulur. Ağaçta görülen, depodan okumanın kendisi değil, okumanın durumu değiştirmesidir. Belirteç bulunamasaydı durum değişmez ve ağaç açılıştaki ağaçla aynı kalırdı.

## Silmek Ağaçta Görünmez

Oturum kapatmak iki ayrı iştir: durumu temizlemek ve belirteci depodan silmek. İlki ağacı değiştirir. İkincisi ağacın dışında olur. Aşağıdaki ölçüm yalnız ikincisini yapar: durum yerinde dururken belirteç depodan silinir.

```javascript
// main.mjs
import { reconcile, countFates } from "./fate.mjs";
import { renderApp } from "./app.mjs";
import { saveSecret, readSecret, deleteSecret } from "./vault.mjs";

const session = { token: "t-1", ad: "Ayse" };
saveSecret("oturum", "t-1")
  .then(() => deleteSecret("oturum"))
  .then(() => readSecret("oturum"))
  .then((left) => {
    console.log("depoda kalan: " + left);
    countFates(reconcile(renderApp(session), renderApp(session)));
  });
```

```text
depoda kalan: null
korunan: 6
guncellenen: 0
kurulan: 0
sokulen: 0
komut: 0
```

Depo boşaldı ama ağaçta hiçbir şey olmadı: komut 0'dır, `Account` hâlâ yerinde durur. Ekran, durumdaki belirtece bakar; depoda ne kaldığına bakmaz. Bu yüzden silme tek başına yetmez ve tek başına görünmez.

## Platform Parçasını Satır Satır Okumak

`saveToken` işlevi dört kararı bir arada taşır. Birincisi, sorgunun sınıfıdır: değer genel bir parola kaydı olarak tanımlanır. İkincisi, kaydın adıdır: oturum belirteci tek bir adla bulunur, bu yüzden okuyan ve silen kod da aynı adı kullanır. Üçüncüsü, değerin kendisidir. Dördüncüsü, erişim koşuludur: değer yalnızca telefon açıkken okunabilir ve başka bir telefona taşınamaz.

Yazmadan önce aynı sorgu ile bir silme çağrısı yapılır. Bunun nedeni, bu depoların aynı adla ikinci bir kayıt eklemeyi reddedebilmesidir; önce silmek, belirteç yenilendiğinde yazmanın başarısız olmasını önler. İşlev son olarak eklemenin başarılı olup olmadığını döner.

Bu parçanın hiçbir satırı ekrana dokunmaz. Yazma başarılı da olsa başarısız da olsa görünüm ağacı aynıdır. Ekrana ulaşan tek şey, uygulamanın bu sonucu durum olarak yazmasıdır: belirteç alındı, oturum açık. Depo ile ağaç arasındaki bu mesafe, bu dersin ölçümlerinin ortak konusudur.

## Belirteç Yenilenince

Belirteçlerin ömrü sınırlıdır; uygulama zaman zaman yeni bir belirteç alır ve depodaki değeri değiştirir. Kullanıcı bunu fark etmemelidir. Ağaç açısından da fark edilmemesi gerekir: oturum sürüyor, ekran aynı kalıyor. Bunu iki yenilemeyle ölçelim. İlkinde yalnızca belirteç değişir. İkincisinde belirteçle birlikte kullanıcının adı da değişir.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderApp } from "./app.mjs";

const before = renderApp({ token: "t-1", ad: "Ayse" });
console.log("yalniz belirtec:");
countFates(reconcile(before, renderApp({ token: "t-2", ad: "Ayse" })));
console.log("belirtec ve ad:");
printOps(
  reconcile(before, renderApp({ token: "t-2", ad: "Zeynep" }))
    .filter((op) => op.fate !== "korunan"),
);
```

```text
yalniz belirtec:
korunan: 6
guncellenen: 0
kurulan: 0
sokulen: 0
komut: 0
belirtec ve ad:
guncellenen: /App/Account/Profile
```

İlk yenilemede ağaç değişmedi: belirteç ağaca yazılmadığı için komut 0'dır. Kullanıcı ağaç açısından hiçbir şey görmez, hesap ekranı olduğu yerde durur. İkinci yenilemede yalnız `Profile` güncellenendir; çünkü değişen özellik, adı gösteren düğümün özelliğidir. `Account` ve altındaki öteki düğümler korunandır.

Bu iki sonuç aynı ilkenin iki yüzüdür. Gizli değer ağaca girmez; bu yüzden değişmesi ağaçta iz bırakmaz. Ağaca giren bilgi, ekranda görünen bilgidir; ve yalnız o değişince bir düğüm güncellenir. Gizli değerin ağaca girmemesi yalnızca bir sızıntı önlemi değildir, aynı zamanda gereksiz komutları da önler.

## Karşı Örnek: Belirteci Ağaca Yazmak

Belirteci kolaylık olsun diye ekran özelliği yapmak akla gelebilir: `Account` düğümünün bir özelliği olarak belirteç taşınır. Bu çalışır, ama iki bedeli vardır. Birincisi, her yenilemede `Account` güncellenen olur; ekranda hiçbir şey değişmediği hâlde bir komut doğar. İkincisi ve daha ağırı, gizli değer artık görünüm ağacının bir parçasıdır. Ağaç hata raporlarında, hata ayıklama çıktılarında ve ekran kayıtlarında dolaşır; gizli değer de onunla dolaşır. Depo değeri korumak için vardır ve ağaca kopyalamak bu korumayı bozar.

## Sınırlayıcı Ölçüm

Akıbet gizli değerin güvenliğini ölçmez. Aynı oturum kapatma iki biçimde yapılır: belirteç depoda bırakılarak ve depodan silinerek. Ağaç iki durumda da aynı değişir.

```javascript
// main.mjs
import { reconcile, countFates } from "./fate.mjs";
import { renderApp } from "./app.mjs";
import { saveSecret, readSecret, deleteSecret } from "./vault.mjs";

function signOut(withDelete) {
  const signedIn = renderApp({ token: "t-1", ad: "Ayse" });
  const signedOut = renderApp({ token: null, ad: "" });
  const clear = withDelete ? deleteSecret("oturum") : Promise.resolve();
  return clear.then(() => readSecret("oturum")).then((left) => {
    console.log(withDelete ? "silerek:" : "silmeden:");
    console.log("depo: " + (left === null ? "bos" : "dolu"));
    countFates(reconcile(signedIn, signedOut));
  });
}

saveSecret("oturum", "t-1")
  .then(() => signOut(false))
  .then(() => signOut(true));
```

```text
silmeden:
depo: dolu
korunan: 3
guncellenen: 0
kurulan: 1
sokulen: 3
komut: 4
silerek:
depo: bos
korunan: 3
guncellenen: 0
kurulan: 1
sokulen: 3
komut: 4
```

İki koşumda da komut sayısı aynıdır: hesap alt ağacı sökülür, `Login` kurulur. Fark yalnız depoda: ilkinde belirteç dolu kalır, ikincisinde boştur. Ağaca bakan biri oturumun gerçekten kapandığını söyleyemez; belirteç depoda duruyorsa uygulama bir sonraki açılışta oturumu yeniden kurar. Akıbet, güncellemenin düğüme yaptığını sınıflar; belirtecin akıbetini sınıflamaz.

## Yaygın Yanılgılar

- "Oturum kapandı, ekran değişti, demek ki belirteç silindi." Ekran durumdan çizilir, depodan değil. Silme ayrı bir çağrıdır ve ayrıca doğrulanır.
- "Gizli değer ekranda göründüğü sürece belleğe girmiştir, depo anlamsızdır." Bellekteki kopya geçicidir; depo değerin uygulama kapanınca nerede kaldığını belirler.
- "Belirteç düz depoda da durabilir, sonuçta küçük bir metin." Boyut güvenliği belirlemez; erişimi koruyan şey deponun kendisidir.
- "Silme başarılıysa kullanıcı oturumdan çıkmıştır." Depodan silmek ile ağaçtan oturum ekranını çıkarmak ayrı işlerdir. Silme ağaçta komut doğurmaz; ekranı değiştiren, belirtecin durumdan kalkmasıdır. İki adım birlikte yapılmazsa depo boşken ekran hesabı göstermeye devam eder, ya da ekran girişe dönmüşken eski belirteç depoda kalır.
- "Belirteç yenilenince ekran da yenilenir." Yenileme ağaçta komut doğurmaz; belirteç ekranda görünmediği için hiçbir düğüm değişmez.
- "Güvenli depo yalnız belirteç içindir." Parola, anahtar ve kullanıcıya ait başka gizli değerler de aynı yere yazılır. Seçimi belirleyen değerin biçimi değil, ifşa edilirse doğuracağı zarardır.
- "Oturum kapatınca yalnız belirteç gider." Ağaçtan hesaba ait bütün ekran gider, ona bağlı yerel görünüm de onunla birlikte. Bir sonraki kullanıcı önceki kullanıcının ekran durumunu görmez; bu istenen bir sonuçtur ve ölçümde alt ağacın tek parça sökülmesiyle görünür.

## Özet

- Bu dersin akıbeti: sökülen. Oturum kapanınca `/App/Account` ile altındaki `Profile` ve `Orders` düğümleri tek parça sökülür, yerine `Login` kurulur.
- Açılışta güvenli depodan okunan belirteç durumu değiştirdiğinde `Login` sökülür ve hesap alt ağacı kurulur.
- Belirtecin depodan silinmesi ağacı değiştirmez: durum yerinde durdukça `Account` düğümü korunandır.
- Aynı oturum kapatma depoyu dolu ya da boş bırakabilir; ağaç iki durumda da aynı değişir, akıbet gizli değerin akıbetini sınıflamaz.
- Gizli değer düz depoda değil, platformun güvenli anahtar deposunda durur.

## Sonraki Adım

Bu derse kadar ağaçtaki değişiklikler durumdan geldi: bir ekranın açılması, bir verinin yüklenmesi, bir oturumun kapanması. Bir de dışarıdan gelen değişiklik vardır: bildirime dokunan kullanıcı uygulamayı belirli bir ekranda açar. Sıradaki ders, `Bildirimler ve Derin Bağlantı`, bir bağlantının ağaca nasıl girdiğini ölçer.
