İlerleyici Web Uygulaması Güvenliği Sanatında Ustalaşma
İlerleyici Web Uygulamaları (PWAs), açık web üzerinde uygulama‑benzeri deneyimler sunmanın de‑facto standardı haline geldi. Çevrim‑dışı çalışma, push bildirimleri ve kurulabilirlik gibi temel avantajları, geleneksel web sitelerinin nadiren karşılaştığı yeni saldırı yüzeylerini de beraberinde getiriyor. Bu makale, bir PWA’nın güvenlik yaşam döngüsünü derinlemesine inceliyor; ağ‑seviyesi güçlendirmeyi, çalışma‑zamanı korumalarını ve operasyonel en iyi uygulamaları birleştiriyor. Sonuna geldiğinizde, basit bir haber okuyucudan karmaşık bir e‑ticaret platformuna kadar herhangi bir projeye uygulayabileceğiniz bir kontrol listesine sahip olacaksınız.
TL;DR: PWA’nızı HTTPS ile güvence altına alın, katı CSP uygulayın, servis çalışanlarını sandbox’layın, tüm girdileri doğrulayın ve sürekli izleme rutinini benimseyin.
1. Taşıma Katmanı – İlk Savunma Hattı
1.1 HTTPS’yi Her Yerde Zorunlu Kullanın
Tüm modern tarayıcılar, servis çalışanı kaydı için HTTPS zorunluluğu getirir. Ancak bazı varlıklar (örneğin üçüncü‑taraf analitikler) hâlâ HTTP üzerinden yüklenebilir; bu da karışık‑içerik uyarılarına ve ortadaki adam (MITM) saldırılarına kapı aralar.
Ana adımlar:
- Güvenilir bir TLS sertifikası edinin (Let’s Encrypt, Cloudflare vb.).
- Sunucu yapılandırmasıyla tüm
http://isteklerinihttps://‘a yönlendirin. - HSTS (HTTP Strict Transport Security)’yi etkinleştirerek tarayıcıların belirli bir süre boyunca sadece HTTPS kullanmasını zorlayın.
# Example NGINX snippet
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# TLS settings ...
}
Not: HSTS, sürüş (downgrade) saldırılarını ortadan kaldırır, ancak bir kez ayarlandığında tarayıcılar belirlenen süre boyunca HTTP üzerinden bağlanmayı reddeder; bu yüzden planlaması dikkat gerektirir.
1.2 Sertifika Sabitleme (Opsiyonel)
Bankacılık, sağlık kayıtları gibi son derece hassas PWAlar için Public Key Pinning Extension for HTTP (HPKP) aracılığıyla sertifika sabitlemeyi değerlendirin. HPKP dağıtım riskleri nedeniyle kullanım dışı bırakılıyor olsa da, benzer güvenliği Expect‑CT başlıklarıyla sağlayabilirsiniz.
Expect-CT: max-age=86400, enforce, report-uri="https://example.com/report"
2. Servis Çalışanı Sertleştirme
Servis çalışanları, bir PWA’nın çevrim‑dışı yeteneklerinin kalbidir. Arka planda yükseltilmiş yetkilerle çalışan bu iş parçacığı, saldırganlar için cazip bir hedef oluşturur.
2.1 Kapsamı Sınırlama
Servis çalışanı kaydederken mümkün olan en dar scope değerini belirleyin. Bu, çalışanın hedeflenen alan dışındaki istekleri yakalamasını önler.
navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
.then(reg => console.log('SW registered with scope:', reg.scope));
2.2 Alt Kaynak Bütünlüğü (SRI) ile Doğrulama
Servis çalışanı betiğini bir CDN üzerinden yüklüyorsanız, beklenen hash değeriyle eşleştiğini garantilemek için SRI kullanın.
<script src="https://cdn.example.com/sw.js"
integrity="sha384-abc123..."
crossorigin="anonymous"></script>
2.3 Servis Çalışanları İçin İçerik Güvenliği Politikası
Katı bir CSP, çalışanın kötü amaçlı betik yüklemesini veya istenmeyen origin’lere bağlanmasını engelleyebilir.
Content-Security-Policy: script-src 'self' https://trusted.cdn.com;
connect-src 'self' https://api.example.com;
İpucu: Yeni tarayıcılarda
worker-srcyönergesini kullanarak çalışan betiği kaynaklarını açıkça beyaz listeye ekleyin.
2.4 Durum Yönetimi ve Önbellek Doğrulama
Önbellek girdilerine körü körüne güvenmeyin. Özellikle kimlik doğrulama token’ları veya kişisel veriler için önbellek yanıtının tazeliğini her zaman doğrulayın.
self.addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (url.pathname.startsWith('/api/')) {
// Dinamik veriler için önbelleği atla
event.respondWith(fetch(event.request));
return;
}
// Statik varlıklar için varsayılan cache‑first stratejisi
event.respondWith(
caches.match(event.request).then(cached => cached || fetch(event.request))
);
});
3. Çalışma Zamanı Koruması – CSP, İzinler ve Sandbox
3.1 Tam Özellikli CSP
İyi tasarlanmış bir CSP, Cross‑Site Scripting (XSS) ve Data Injection saldırı risklerini azaltır. Aşağıdaki örnek politika tipik bir PWA için özelleştirilmiştir:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'sha256-XYZ' https://analytics.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com wss://socket.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
script-srcsatırında satır içi betikler için bir hash bulunur; bu sayedeunsafe-inlinekullanılmaz.frame-ancestors 'none'clickjacking’i engeller.connect-srcAPI ve WebSocket uç noktalarını beyaz listeye alır.
3.2 İzinler Politikası (Eski Feature‑Policy)
PWA’nın istemeden miras alabileceği güçlü tarayıcı özelliklerini kısıtlayın.
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=()
3.3 Gömülü İçerik İçin Sandbox Özniteliği
PWA’nız üçüncü‑taraf iframe’ler barındırıyorsa, script çalıştırmayı ve yönlendirmeyi önlemek için sandbox’layın.
<iframe src="https://maps.example.com"
sandbox="allow-scripts allow-same-origin"
loading="lazy"></iframe>
4. Kimlik Doğrulama & Yetkilendirme
4.1 JWT ile Token‑Tabanlı Kimlik Doğrulama
Stateless kimlik doğrulama için JSON Web Token (JWT) kullanın, ancak bunları localStorage yerine Secure, HttpOnly çerezlerde saklayarak XSS çalınmasını önleyin.
Set-Cookie: token=eyJhbGciOi...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600
4.2 Refresh Token Döndürme
Kompromize olmuş bir token’ın zararını sınırlamak için dönen (rotating) refresh token’ları uygulayın.
- İstemci refresh token gönderir.
- Sunucu doğrular ve yeni bir erişim token’ı ve yeni bir refresh token verir.
- Eski refresh token veritabanında geçersiz kılınır.
4.3 CSRF Önleme
Aynı‑site çerezlerine rağmen, durum değiştiren POST istekleri için Anti‑CSRF tokenları kullanın.
<input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
Sunucu tarafında token’ın oturumla eşleştiğini kontrol edin.
5. Güvenli Veri Depolama
PWAlar, IndexedDB, Cache API ve Web Storage üzerinden veri depolayabilir. Her birinin kendine özgü güvenlik hususları vardır.
| Depolama | Uygunluk | Güvenlik İpuçları |
|---|---|---|
| Cache API | Statik varlıklar, çevrim‑dışı yedek | Yalnızca değişmez kaynakları önbellekle. Sürüm‑isimli önbellekler kullanarak eski veriyi temizle. |
| IndexedDB | Yapılandırılmış veri, kullanıcı tercihleri | Hassas alanları istemci‑tarafında Web Crypto API ile şifrele. |
| LocalStorage / SessionStorage | Küçük, hassas olmayan veri | Gizli bilgileri saklamaktan kaçının. Sayfadaki herhangi bir betik bu verilere erişebilir. |
5.1 Örnek: IndexedDB Verisini Şifreleme
async function encryptAndStore(key, value) {
const cryptoKey = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode(value);
const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
cryptoKey,
encoded
);
const db = await openDB('secure-store', 1, {
upgrade(db) { db.createObjectStore('secrets'); }
});
await db.put('secrets', { iv, ciphertext }, key);
}
6. İzleme, Denetleme ve Olay Müdahalesi
Güvenlik tek seferlik bir yapılandırma değildir; devamlı bir döngüdür.
6.1 Otomatik Tarama
- OWASP ZAP veya Burp Suite ile XSS, CSRF ve güvenlik başlığı eksikliklerini tarayın.
- Lighthouse denetimlerini CI/CD boru hatlarına entegre ederek PWA uyumluluğunu zorunlu kılın.
6.2 Çalışma Zamanı Günlüğü
Servis‑worker hatalarını yakalayın ve analiz için güvenli bir uç noktaya gönderin.
self.addEventListener('error', event => {
fetch('https://logs.example.com/collect', {
method: 'POST',
body: JSON.stringify({ message: event.message, stack: event.error.stack })
});
});
6.3 Olay Yanıt Kılavuzu
- Tespit: Anormal trafik veya CSP ihlal raporları tarafından tetiklenen uyarı.
- İzolasyon: Kompromize olmuş JWT’leri iptal edin, API anahtarlarını döndürün.
- Kök Neden: Açık kodu yamalayın, servis‑worker önbelleğini güncelleyin.
- Kurtarma: Yeni sürümü dağıtın, tekrarı izleyin.
- Post‑mortem: Kök nedeni belgeleyin, güvenlik kontrol listesini güncelleyin.
7. Görsel Genel Bakış – Bir PWA’da Güvenlik Katmanları
flowchart TB
subgraph "Transport Layer"
H["\"HTTPS\""]
S["\"HSTS\""]
end
subgraph "Service Worker"
SW["\"Scope Limitation\""]
CS["\"Cache Validation\""]
end
subgraph "Runtime"
CSP["\"Content Security Policy\""]
PP["\"Permissions Policy\""]
SAN["\"Sandboxed iFrames\""]
end
subgraph "Auth & Data"
JWT["\"Secure Cookies\""]
REF["\"Refresh Rotation\""]
ENC["\"IndexedDB Encryption\""]
end
subgraph "Monitoring"
SCAN["\"OWASP ZAP\""]
LOG["\"Runtime Logging\""]
end
H --> SW --> CSP --> JWT --> SCAN
S --> SW
CS --> PP
PP --> ENC
LOG --> SCAN
Bu diyagram, her bir güvenlik kontrolünün bir öncekine nasıl inşa edildiğini ve savunma‑derinliği mimarisini gösterir.
8. Kontrol Listesi – Güvenli bir PWA İçin Hızlı Başvuru
- Tüm içerik HTTPS üzerinden sunulmalı ve HSTS etkinleştirilmeli.
- Servis çalışanları en dar kapsamla (
scope) kaydedilmeli. - CDN üzerinden alınan servis çalışanı betikleri SRI ile korunmalı.
- Katı bir CSP uygulanmalı;
worker-srcve betik hash’leri eklenmeli. - Kullanılmayan tarayıcı özellikleri
Permissions‑Policyile devre dışı bırakılmalı. - Kimlik doğrulama token’ları Secure, HttpOnly çerezlerde saklanmalı; localStorage’da olmamalı.
- Refresh token’lar döndürülmeli ve CSRF token’ları durum‑değiştirici isteklerde doğrulanmalı.
- Hassas veriler IndexedDB’de şifrelenmeli.
- Her PR’da otomatik OWASP ZAP taraması çalıştırılmalı.
- Servis‑worker hatalarının gerçek‑zamanlı günlüğü ayarlanmalı.
- Olay müdahale planı belgelenmiş ve güncel tutulmalı.
9. Sıkça Sorulan Sorular
S1: PWAlar için bir Servis Çalışanı mutlaka gerekli mi?
Hayır. HTTPS, CSP ve güvenli çerezler gibi güvenlik önlemleri bağımsız olarak çalışır. Ancak çalışma‑zamanı saldırıların çoğu servis çalışanında ortaya çıkar; bu yüzden ek sertleştirme önemlidir.
S2: CSP’de unsafe-inline stilleri kullanabilir miyim?
Mümkün olduğunca kaçının. Bunun yerine satır içi stiller için hash ya da nonce kullanın ya da stilleri harici CSS dosyalarına taşıyın.
S3: TLS sertifikalarını ne sıklıkta yenilemeliyim?
Let’s Encrypt 90‑günlük sertifikalar sunar; yenilemeyi otomatikleştirin. Kendinden imzalı ya da ticari sertifikalar için en fazla 1 yıl geçerlilik tavsiye edilir.
10. Sonuç
İlerleyici Web Uygulamaları, yerel ve web deneyimlerini birleştirerek güçlü yetenekler sunar; aynı zamanda saldırı yüzeyini de genişletir. Taşıma güvenliğini katmanlamak, servis‑worker kapsamını daraltmak, katı bir Content Security Policy uygulamak ve sağlam kimlik doğrulama uygulamaları benimsemek, performanstan ödün vermeden PWA’nızı korumanın anahtarıdır.
Unutmayın: güvenlik bir varış noktası değil, bir yolculuktur. Bağımlılıkları güncel tutun, kodunuzu düzenli olarak denetleyin ve yeni ortaya çıkan tehditlerden haberdar olun. Burada paylaşılan uygulamaları izlediğiniz sürece, PWA’nız yaygın web‑tabanlı saldırılara karşı dayanıklı olacaktır.