All checks were successful
Deploy / deploy (push) Successful in 17s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
40 lines
6.1 KiB
Markdown
40 lines
6.1 KiB
Markdown
# Tur 5 — hedefli güvenlik denetimi (`gece/0922-entegrasyon`)
|
||
|
||
Kapsam: `git diff 9bd448b..HEAD` içindeki `?kaynak=` allowlist genişletmesi, ödeme/kredi yüzeyine dokunan satırlar, URAP atıf şartının kod yolları. Salt okuma yapıldı; worktree'ye dokunulmadı.
|
||
|
||
## Özet (5 madde)
|
||
|
||
1. **Kritik bulgu yok.** Ödeme çekirdeği (`src/app/api/**`, `src/lib/credits.ts`, `src/lib/odeme.ts`, `src/lib/iyzico.ts`, `src/features/odeme/odeme-actions.ts`, `src/lib/auth.ts`, `src/lib/session.ts`) bu dalda **hiç değişmemiş** — `git diff --stat 9bd448b..HEAD` bu yollar için boş döner.
|
||
2. `KAYNAKLAR` allowlist'i **gerçekten kapalı**: `KAYNAKLAR.find((k) => k === ham) ?? "diger"` sabit literal dizisine tam eşitlik arar, bilinmeyen değer `"diger"`e düşer. 10 yeni değerin hepsi sabit snake_case; kişisel veri ya da enjeksiyon yükü taşımıyor.
|
||
3. `?kaynak=` **ödeme akışına taşınmıyor**: `/paket` sayfası yalnızca `hata` parametresini okur (`src/app/paket/page.tsx:20`), `odeme-actions.ts` içinde `kaynak` hiç geçmez, sipariş kaydına ve iyzico alanlarına girmez. Tek cümlelik cevap: taşınmıyor.
|
||
4. Bir **düşük** bulgu var: allowlist yalnızca *özel olayın* özelliğini korur; Rybbit'in otomatik pageview'i ham query string'i zaten olduğu gibi saklar, yani "serbest metin analitiğe sızmasın" yorumu eksik doğru (B-1).
|
||
5. URAP atıf şartı kodda korunuyor: sayının görüldüğü tek yüzey ile atıf linkinin tek yüzeyi **aynı `ilkSayfa` koşuluna** bağlı; linksiz sayı yolu bulunamadı (detay aşağıda).
|
||
|
||
## Bulgular
|
||
|
||
| Yer | Sorun | Somut senaryo | Önem | Düzeltme | Kesinlik |
|
||
|---|---|---|---|---|---|
|
||
| `src/features/odeme/components/paket-gorunum-olayi.tsx:13-15` (yorum) | Yorum "Serbest metin analitiğe sızmasın" diyor; allowlist bunu yalnız `paket_goruntulendi.kaynak` özelliği için sağlıyor. Rybbit script'i her pageview'de ham `querystring` alanını saklıyor. | Saldırgan `kolaytercih.com/paket?kaynak=<istediği metin>` linkini paylaşır; kurban tıklar; metin Rybbit panelinin `querystring` kırılımında görünür. Kod yürütme yok, yalnız panel kirliliği/yanıltma. Doğrulama: Rybbit `querystring` kırılımında `?kaynak=nav`, `?kaynak=kilit` satırları ham biçimde duruyor (site 1, tüm zaman). | düşük | Kod değişikliği gerekmez; yorumu "olay özelliği kapalıdır, ham query string ayrıca pageview'de saklanır" diye düzelt. | DOĞRULANDI |
|
||
| `src/lib/analitik.ts:10-12` (bu dalda değil — mevcut durum) | Dosyanın başındaki KURAL "öğrencinin ham başarı sıralaması analitiğe GÖNDERİLMEZ, her zaman `siraKovasi()` ile bantlanır" diyor. Özel olaylar için doğru, ama `/?sira=14000&tur=say` gibi URL'lerde ham sıra pageview'in `querystring` alanında saklanıyor. | Rybbit panelinde `querystring` kırılımı açılır; `?sira=14000&tur=say`, `?sira=55&tur=say`, `?sira=581000&tur=ea&sihirbaz=1` satırları ham sıralamayı gösterir. Oturum/kullanıcı satırıyla birleşince tekil öğrenciye bağlanabilir (Rybbit trait'lerinde ad/e-posta da var). **Bu dalın getirdiği bir şey değil**, aynı mekanizmanın önceden var olan sonucu. | orta | Kod tarafı: sıra formu URL'e `sira` yazıyorsa değeri bantlı tutmak ya da form gönderimini query'siz yapmak; alternatif: Rybbit tarafında query string toplamayı kapatmak. Karar `[BİLAL]`. | DOĞRULANDI |
|
||
|
||
## Kapsam sorularına kısa cevaplar
|
||
|
||
**1. Allowlist kapalı mı?** Evet — `paket-gorunum-olayi.tsx:43-46`. Dedup anahtarı da sanitize edilmiş `kaynak`tan türetiliyor (`olayBirKez(..., kaynak)`), ham değer sessionStorage anahtarına da girmiyor. Yeni 10 değerin hepsi (`fiyat_paket`, `fiyat_kredi`, `kosullar`, `tercih_degisti`, `tercih_degisti_yetersiz`, `danisman_rozet`, `danisman_kredi_bitti`, `danisman_kredi_az`, `odeme_geri`, `odeme_hata`) yüzey adı; kişisel veri yok.
|
||
|
||
**2. Ödeme/kredi yüzeyi.** `odeme-kromu.tsx:45`, `odeme-sonuc-karti.tsx:141`, `sohbet-client.tsx:351/538/546`, `tercih-degisti-modali.tsx:283/335`, `src/app/page.tsx:543/573`, `src/app/kosullar/page.tsx:55` — hepsi **yalnızca `href` string'i**. Kredi düşümü, sipariş durumu, yetki kontrolü, fiyat/ürün belirleme hiç değişmedi. `sihirbaz-adimlar.tsx`'teki tek yeni satır mount'ta `olayBirKez("sihirbaz_adim", { adim: 1 }, "adim1")`; sabit değer, kişisel veri yok. `program-tablosu.tsx` / `rapor-listesi.tsx` değişiklikleri erişilebilirlik (risk etiketini `sr-only`dan çıkarma) — güvenlik etkisi yok.
|
||
|
||
**3. URAP atıf şartı (kod yolları).** URAP'ı tüketen tek yer `src/features/katalog/components/universite-icerik.tsx`; başka hiçbir bileşen, metadata, JSON-LD ya da OG görseli sayıyı almıyor (`grep -rn "urap\|URAP" src/` → yalnız `lib/urap-siralama.ts`, `lib/katalog.ts` tipi, `universite-icerik.tsx`, `scripts/veri-kalite.ts`).
|
||
- Sayının çizildiği tek yer: kart, `universite-icerik.tsx:363-371` — `ilkSayfa` dalının (satır 308) içinde.
|
||
- Atıf linkinin çizildiği tek yer: `UrapKaynakSatiri`, `universite-icerik.tsx:129-156` — çağrısı `satır 441: {ilkSayfa ? <UrapKaynakSatiri uni={uni} /> : null}`.
|
||
- İkisi de aynı koşula bağlı olduğu için "sayı var, link yok" sayfası üretilemiyor; `/universite/[slug]/sayfa/[no]` (2+) ne sayıyı ne linki gösteriyor. `uniSayfaMetadata` ve `opengraph-image.tsx` URAP'a hiç dokunmuyor.
|
||
- **Kalan kırılganlık (bulgu değil, not):** `src/lib/katalog.ts:402` artık `urap`'ı `UniDetay` nesnesine iliştiriyor. Yarın biri `UniDetay`'i bir istemci bileşenine ya da yeni bir kart/JSON-LD'ye verirse sayı linksiz bir yüzeye çıkabilir. `scripts/veri-kalite.ts` içindeki URAP kontrolleri veri bütünlüğünü denetliyor ama "her gösterim yanında link var mı" sorusunu denetlemiyor. Bu tip kurallar yorumla korunuyor (`katalog.ts:229-231`), testle değil.
|
||
|
||
## Metin × kod uyumsuzlukları
|
||
|
||
- `paket-gorunum-olayi.tsx:13` yorumu ile gerçek saklama arasındaki fark (yukarıda B-1).
|
||
- `analitik.ts:10-12` KURAL'ı ile `querystring` alanında duran ham sıra arasındaki fark (yukarıda, mevcut durum).
|
||
|
||
## Bilal'den istenen
|
||
|
||
1. Ham `?sira=` değerinin Rybbit `querystring` alanında saklanması sürsün mü, yoksa kapatılsın mı — karar senin (5 dk).
|