Özet
Özet
Görüntü yüklemeleri sadece resim değildir. Bir JPEG, EXIF yorumlarında bir PHP web shell taşıyabilir ve MIME kontrollerini, uzantı kontrollerini ve hatta getimagesize() kontrolünü geçebilir. Eğer bu dosya bir şekilde çalıştırılabilir bir yere ulaşırsa – yanlış yapılandırılmış bir public/uploads, bir .htaccess ayarı, birbirine bağlı LFI – uzaktan kod çalıştırmanız mümkün olabilir.
laravel-at/laravel-image-sanitize, yüklenen görüntülerde yük işaretlerini (, phar) tarayan küçük bir middleware'dir ve şüpheli olan her şeyi Intervention Image aracılığıyla yeniden kodlar, yükleme sürecinde kontrolcünüz dosyayı görmeden önce yük işaretlerini temizler.
composer require laravel-at/laravel-image-sanitize
Bu, doğrulamanın bir yerine geçmez. Yine de neden buna ihtiyacınız olduğunu ve nasıl çalıştığını açıklayalım.
Sorun: sadece görüntü olmayan görüntüler
Sorun: sadece görüntü olmayan görüntüler
Geçerli bir görüntü dosyası, bilinen bir başlığın doğal verileridir. O başlığın sonuna keyfi metin eklemenizi engelleyen bir şey yoktur. Görüntü yine de tarayıcıda düzgün render edilir - görüntü kod çözücüler sonraki gereksiz verileri dikkate almaz.
Bu, "GIFAR" / poliglot numarasının klasik örneğidir, 2026'da hâlâ geçerlidir:
exiftool -Comment='' shell.jpg
Bu dosya:
Gerçek bir JPEG başlığı vardır.
file shell.jpgJPEG image datader.getimagesize()kontrolünü geçer. PHP başlığı okur, yorumu değil.$request->file('avatar')->isValid()ve'image'doğrulama kurallarını geçer.etiketlerinde normal olarak render edilir.EXIF verilerinde çalışan bir PHP yükü içerir.
Eğer bir saldırgan bu dosyayı bir .php uzantısıyla ulaşılabilir bir yere yazdırabilirse - ayrı bir yol geçiş açığı, yanlış yapılandırılmış bir yeniden adlandırma veya .jpg.php dosyasını çalıştıran bir sunucu aracılığıyla - kod çalıştırma elde edebilir. Birçok gerçek dünyadaki ihlal, tam olarak bu: "ilişiksiz" bir yükleme hatası ve esnek bir depolama yolu.
Neden MIME ve uzantı kontrolleri yeterli değil
Neden MIME ve uzantı kontrolleri yeterli değil
Laravel standart doğrulaması:
$request->validate([
'avatar' => 'required|image|mimes:jpg,png,gif|max:2048',
]);
Bu kapsayıcıyı değil, içeriği kontrol eder. mimes: dosya uzantısına ve bir büyücü byte kontrolüne bakar. image ise bir resim olarak kod çözüldüğünü doğrular. Hiçbiri, geçerli görüntü verisi ile birlikte dosya içinde başka nelerin olduğunu incelemez.
MIME sniffing, "Bu teknik olarak bir görüntü mü?" sorusunu sorar. "Bu görüntü gömülü kod içermiyor mu?" şeklinde bir soruya yanıt vermez. Bu iki farklı sorudur ve çoğu yükleme akışı yalnızca birincisini sorar.
Çözüm: tespit et ve yeniden kodla
Çözüm: tespit et ve yeniden kodla
laravel-image-sanitize, ikinci soruyu soran bir katman ekler. Akış dört adımdan oluşur:
MIME türü ile filtrele. Middleware, yalnızca izin verilen dosyaları (geçerli olarak varsayılan olarak JPEG, PNG, GIF, BMP, WebP) denetler.
Yük işaretlerini tarayın. Dosya içeriği, yapılandırılmış desenlere göre kontrol edilir - varsayılan olarak
vepharkontrol edilir.Eşleşme durumunda yeniden kodlayın. Bir işaretçi bulunursa, görüntü sıfırdan çözülüp yeniden kodlanır. Çözüm yalnızca piksel verisini okur; gerçek görüntü akışı dışındaki her şey yeniden kodlamada düşer.
Kontrolcü çalışmadan önce değiştirin. Yeniden yazılan baytlar orijinal yükleme içeriğinin yerine geçer. Kontrolcünüz, doğrulama kurallarınız, depolama mantığınız - hiçbirisi değişmez.
Temel anlayış: gerçek bir görüntü kod çözücü, EXIF yorumunu çalıştırılabilir olarak okumaz. Yeniden kodlama, dosyayı yalnızca piksel verilerinden yeniden inşa eder, bu nedenle görüntü akışının sonundaki her şey - PHP yükünüz - çıktıda yer almaz.
Middleware kullanımı
Middleware kullanımı
Bunu doğrudan yükleme yollarına ekleyin:
use App\Http\Controllers\FileController;
use LaravelAt\ImageSanitize\ImageSanitizeMiddleware;
Route::post('/files', [FileController::class, 'upload'])
->name('file.upload')
->middleware(ImageSanitizeMiddleware::class);
Ya da bootstrap/app.php içinde okunabilir bir takma ad kaydedin (Laravel 12/13):
use Illuminate\Foundation\Configuration\Middleware;
use LaravelAt\ImageSanitize\ImageSanitizeMiddleware;
->withMiddleware(function (Middleware $middleware): void {
$middleware->alias([
'image-sanitize' => ImageSanitizeMiddleware::class,
]);
})
Route::post('/files', [FileController::class, ])
->name()
->middleware();
Middleware dışında doğrudan kullanım
Middleware dışında doğrudan kullanım
Bir işte, API istemcisinde veya CLI ithalatında ham görüntü baytları ile mi işlem yapıyorsunuz? Sanitizer'ı doğrudan çağırın:
if (ImageSanitize::detect($contents)) {
$contents = (string) ImageSanitize::sanitize($contents);
}
detect(), desen taramasını çalıştırır; sanitize() yeniden kodlama işlemini yapar. Dosyanın bir HTTP rotasından geçmediği durumlar için yararlıdır.
Yapılandırma
Yapılandırma
Varsayılanları değiştirmek istediğinizde yapılandırmayı yayınlayabilirsiniz:
php artisan vendor:publish --tag=image-sanitize-config
Varsayılanlar:
return [
'allowed_mime_types' => [
'image/jpeg',
'image/png',
'image/gif',
'image/bmp',
'image/webp',
],
'patterns' => [
'',
'phar',
],
'driver' => \Intervention\Image\Drivers\Gd\Driver::class,
'quality' => 100,
'auto_orientation' => true,
'decode_animation' => true,
'strip_metadata' => true,
];
Birkaç not:
quality => 100ayarı, JPEG yeniden kodlamasının kayıpsız olmasını sağlar; daha küçük dosyalar istiyorsanız bunu düşürün.strip_metadata => trueayarı, yeniden kodlamada EXIF verilerini kaldırarak gizlilik açısından da kazanç sağlar (telefon yüklemelerinden GPS koordinatlarının sızmasını önler).decode_animation => trueayarı, animasyonlu GIF/WebP'yi tek bir çerçeveye düzleştirmek yerine doğru bir şekilde işler.SVG, izin verilenler listesinde yoktur. SVG, aktif içerik taşıyabilir (
, olaya yanıt veren işleyiciler) ve raster yeniden kodlamasıyla çözmesine göre farklı bir tehdit modeli gerektirir. Kendi sanitizasyonunuz olmadan bunu eklemeyin.
Bu nedir yapmaz
Bu nedir yapmaz
Bu paket:
mimes:/imagedoğrulama kurallarının yerini almaz - onları koruyun.Yetkilendirme, hız sınırlama veya virüs taraması yapmaz.
Yüklemeleri halka açık, çalıştırılabilir bir dizinde depolamanızı güvenli hale getirmez. Yüklenmiş dosyaları
public/çalıştırılabilir yolların dışına yerleştirin.SVG, PDF veya görüntü dışındaki yüklemeleri kapsamaz.
Bu, belirli bir boşluğu kapatan bir katmandır: aksi takdirde geçerli görüntü baytları içinde gizlenen kod. Bunu uygun depolama izolasyonu ile (yüklenen dosyaların çalıştırılamayan disklerde depolanması, imzalı URL'lerle veya bir kontrolcü aracılığıyla sunulması - doğrudan web kökü erişimi olmadan) birleştirerek, poliglot dosyanın geçmesini anlamlı şekilde azaltmış olabilirsiniz.
Gereksinimler: Laravel ^12.0 | ^13.0, PHP ^8.3, MIT lisanslı.
SSS (Sık Sorulan Sorular)
SSS (Sık Sorulan Sorular)
Bu, Laravel'in image doğrulama kuralının yerini alır mı? Hayır. Her ikisini de çalıştırın. Doğrulama, dosyanın yapı açısından geçerli bir resim olduğunu doğrular; temizleyici, gömülü yük işaretlerini kontrol eder ve bulursa yeniden kodlar. Farklı hata modlarını kapsar.
Yeniden kodlama resimlerimi bozar mı? Kalite varsayılan olarak 100'dür, bu nedenle JPEG kaybı minimaldir. PNG/GIF/WebP yeniden kodlaması, tipik kullanım için kayıpsızdır. Daha küçük çıktıya ihtiyacınız varsa, yapılandırmadaki quality değerini düşürün.
Neden SVG desteklenmiyor? SVG XML'dir ve bazı render etme bağlamlarında çalışan etiketleri veya olaya yanıt veren işleyiciler içerebilir. Raster bir görüntü yeniden kodlama işlemi, işaretleme dillerini "temizleme" anlamına gelmez - SVG, kendi temizleyicisine (örneğin, script/event-handler düğümlerini silme) ihtiyaç duyar ve bu, burada dışarıda kalır.
Bu, her yükleme tabanlı saldırıyı durdurur mu? Tek bir paket her şeyi yapmaz. Bu, özel olarak "görüntü baytları içinde gömülü PHP/PHAR" boşluğunu kapar. Bunu depolama izolasyonu, sıkı MIME/uzantı doğrulaması ve yükleme dizinlerinden PHP çalıştırmamayı birleştirerek destekleyin.
Tartışmaya katıl
Tartışmaya katıl
Gördüğünüz en kötü yükleme tabanlı istismar, bir depolama yanlış yapılandırması ile nasıl zincirlenmişti?
quality => 100varsayılan olarak - akıllıca, yoksa varsayılan olarak dosya boyutumunu optimize etmelimi? Aşağıda fikirlerinizi paylaşın.SVG hijyeni için ihtiyacınız olduğunu düşündüğünüz bir durumu yaşadınız mı? Bunu göndermeyi engelleyen neydi?
Kaynaklar
Kaynaklar
Kaynak: Orijinal Makale


