Bulut Depolamada İmzalı URL: Dosyayı Sunucudan Geçirmeden Vermek
Her dosya indirmesini uygulama sunucusundan geçirmek hem yavaş hem pahalıdır. İmzalı URL bu yükü tamamen kaldırır.
Bir imzalı url, belirli bir dosyaya belirli bir süre boyunca erişim veren, kriptografik olarak imzalanmış geçici adrestir. Depolama servisi imzayı doğrular ve süresi dolmuşsa reddeder. Böylece dosyayı uygulama sunucunuzdan geçirmeden, ama yine de yetki kontrolünü koruyarak servis edebilirsiniz.

Neden sunucudan geçirmek pahalı?
Klasik akışta dosya iki kez ağdan geçer: depolamadan uygulamaya, uygulamadan istemciye. Bu, bant genişliği maliyetini ikiye katlar. Daha kötüsü, 40 MB'lık bir indirme boyunca bir PHP işçisi tamamen meşgul kalır — eşzamanlı on indirme, on işçiyi bloke eder ve site geri kalan istekler için yavaşlar. Bu tür sessiz kalemleri bulut faturasını şişiren görünmez kalemler yazımızda toplamıştık.
İmzanın mantığı
İmzalı URL sihir değildir: adres + son kullanma zamanı, gizli anahtarla HMAC'lenir. Doğrulayan taraf aynı hesabı yapıp karşılaştırır. Kendi dosya sunucunuzda bile aynı deseni kurabilirsiniz.
final class ImzaliBaglanti
{
public function __construct(private string $gizliAnahtar) {}
public function uret(string $yol, int $gecerlilikSaniye = 300): string
{
$bitis = time() + $gecerlilikSaniye;
$imza = $this->imzala($yol, $bitis);
return base_url('dosya/' . ltrim($yol, '/'))
. '?bitis=' . $bitis . '&imza=' . $imza;
}
public function dogrula(string $yol, int $bitis, string $imza): bool
{
if ($bitis < time()) {
return false; // süresi dolmuş
}
// hash_equals: zamanlama saldırısına karşı sabit süreli karşılaştırma
return hash_equals($this->imzala($yol, $bitis), $imza);
}
private function imzala(string $yol, int $bitis): string
{
return hash_hmac('sha256', ltrim($yol, '/') . '|' . $bitis, $this->gizliAnahtar);
}
}Karşılaştırmayı === ile yapmayın. hash_equals, imzayı karakter karakter erken çıkışsız karşılaştırır; aksi hâlde saldırgan yanıt sürelerini ölçerek imzayı adım adım tahmin edebilir.
Yetki kontrolü adresi üretirken yapılır
İmzalı URL'nin sık gözden kaçan tarafı budur: adres üretildikten sonra artık kimlik kontrolü yoktur; adrese sahip olan herkes dosyayı indirir. Bu yüzden üretim anında yetkiyi kesin olarak doğrulamak ve süreyi kısa tutmak gerekir.
public function indirmeBaglantisi(int $dosyaId)
{
$dosya = $this->dosyaModel->find($dosyaId);
if (! $dosya) {
return $this->response->setStatusCode(404)->setJSON(['hata' => 'Dosya yok.']);
}
// IDOR koruması: kayıt gerçekten bu kullanıcının kapsamında mı?
if (! $this->policy->erisebilir(session()->get('user_id'), $dosya)) {
return $this->response->setStatusCode(403)->setJSON(['hata' => 'Yetkiniz yok.']);
}
return $this->response->setJSON([
'url' => $this->imzali->uret($dosya['yol'], 120), // 2 dakika yeter
'bitis' => time() + 120,
]);
}Doğrudan yükleme: aynı desen ters yönde
Yükleme tarafında da aynı yaklaşım geçerlidir. Sunucu yalnızca imzalı bir yükleme adresi üretir; dosya tarayıcıdan doğrudan depolamaya gider. Ancak burada iki ek önlem şarttır: izin verilen içerik tipini ve maksimum boyutu imzanın parçası yapmak. Aksi hâlde imzalı adresi alan biri, oraya istediği türde ve boyutta veri yükleyebilir.
// 1) Sunucudan imzalı yükleme adresi iste
const { url, alanlar } = await (await fetch('/api/v1/dosya/yukleme-izni', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ad: dosya.name, tip: dosya.type, boyut: dosya.size }),
})).json();
// 2) Dosyayı DOĞRUDAN depolamaya gönder — uygulama sunucusu devrede değil
const form = new FormData();
Object.entries(alanlar).forEach(([k, v]) => form.append(k, v));
form.append('file', dosya);
const yanit = await fetch(url, { method: 'POST', body: form });
if (!yanit.ok) throw new Error('Yükleme başarısız');Adres üretimi ucunu herkese açık bırakacaksanız, kötüye kullanımı sınırlamak için hız sınırlama uygulayın.
Önbellek ve CDN uyumu
İmzalı adresler her üretimde değiştiği için CDN önbelleğinde tekrar kullanılamaz. Herkese açık ve sık istenen dosyalarda (ürün görselleri, statik varlıklar) imzalama gereksizdir ve zararlıdır — önbellek stratejileri yazımızdaki ayrım burada da geçerlidir: gizli olan imzalanır, açık olan önbelleklenir. Sır yönetimi tarafında ise imzalama anahtarının kaynak koda girmemesi kritiktir; sırların yönetimi yazımız bu konuyu ele alıyor. Sağlayıcı tarafındaki resmî akış için MDN Content-Disposition belgeleri indirme davranışını netleştirir.
Sonuç
İmzalı URL, uygulama sunucusunu veri taşıma işinden kurtarıp yalnızca karar verme işinde bırakır. Kazanç üç yönlüdür: bant genişliği maliyeti yarıya iner, işçi havuzu büyük indirmelerle tıkanmaz ve indirme hızı depolama servisinin ağına devredilir. Karşılığında tek bir disiplin gerekir — yetkiyi adres üretilirken kesin olarak kontrol edin, süreyi ihtiyacın üzerine çıkarmayın, imzayı sabit süreli karşılaştırma ile doğrulayın ve yükleme adreslerinde tip/boyut sınırını imzanın parçası yapın. Bir sonraki büyük dosya indirme özelliğinde, dosyayı sunucudan geçirmeden önce bu deseni değerlendirin.
Sık Sorulan Sorular
Kullanım senaryosunun gerektirdiği en kısa süre. Tek tıklamalık indirme için 1-2 dakika fazlasıyla yeterlidir. Uzun süreler adresin paylaşılma ve günlüklerde kalma riskini artırır; "her ihtimale karşı" bir saat vermek yaygın ama gereksiz bir alışkanlıktır.
Süresi dolana kadar o dosyaya erişilebilir. Bu yüzden süre kısa tutulur. Ek koruma isteniyorsa imzaya istemci IP adresi veya tek kullanımlık bir jeton eklenebilir, ancak IP tabanlı kısıt mobil ağlarda yanlış pozitif üretebilir.
Zorunlu değil. Birkaç kilobaytlık dosyalarda sunucudan geçirmenin maliyeti ihmal edilebilir ve tek istekte iş biter. İmzalı URL asıl kazancını büyük dosyalarda ve yüksek eşzamanlılıkta gösterir.
O anda dolaşımda olan tüm imzalı adresler anında geçersiz olur. Bu, bir sızıntı durumunda işinize yarayan bir özelliktir; ancak planlı anahtar değişimlerinde kısa süreli hata dalgası yaşamamak için eski anahtarı bir süre daha doğrulamada kabul eden bir geçiş dönemi tanımlayın.
Yorumlar (0)
Bu yazıya henüz yorum yapılmamış. İlk yorumu siz yazın!
Yorum Yaz
Yorumunuz onaylandıktan sonra yayınlanır. Ekibimiz gerekirse konuyla ilgili bir yanıt da paylaşır.