File Upload Güvenliği

File Upload Güvenliği (Detaylı Anlatım ve Güvenli Uygulama Teknikleri)
File Upload Güvenliği, web uygulamalarının kullanıcılar tarafından yüklenen dosyaları güvenli bir şekilde işlemesini sağlamak için alınması gereken önlemleri kapsar. Güvensiz dosya yükleme mekanizmaları, sunucunun ele geçirilmesine, veri sızıntısına ve hizmet kesintilerine yol açabilir.

Dosya Yükleme Zafiyetleri Nelerdir?
Kötü Amaçlı Dosya Yükleme: PHP, ASP, JSP gibi çalıştırılabilir dosyaların yüklenmesi

MIME Tipi Sahteciliği: Content-Type header'ının manipüle edilmesi

Çift Uzantı Saldırısı: image.jpg.php gibi dosya adları

Null Byte Enjeksiyonu: image.php%00.jpg ile uzantı atlatma

Dosya Boyutu Saldırıları: Çok büyük dosyalarla DoS saldırısı

Path Traversal: ../../../etc/passwd ile dizin atlama

XSS ve HTML Enjeksiyonu: SVG, HTML dosyaları ile

Zip Slip: Arşiv dosyaları ile dizin atlama

Güvenli Dosya Yükleme İçin Uygulama Teknikleri:
1. Dosya Türü Doğrulama (File Type Validation)
Yanlış Yaklaşım:

python
# SADECE uzantı kontrolü (güvensiz)
if not filename.endswith('.jpg'):
raise Exception("Geçersiz dosya türü")
Doğru Yaklaşım:

python
import imghdr
import magic

def validate_file_type(file_content, filename):
# 1. Magic bytes ile dosya imzasını kontrol et
mime = magic.from_buffer(file_content[:1024], mime=True)

# 2. İzin verilen MIME tipleri
ALLOWED_MIMES = [
'image/jpeg', 'image/png', 'image/gif',
'image/webp', 'application/pdf'
]

if mime not in ALLOWED_MIMES:
raise Exception(f"Geçersiz dosya türü: {mime}")

# 3. Ek kontrol - görsel dosyalar için
if mime.startswith('image/'):
try:
import PIL.Image
img = PIL.Image.open(io.BytesIO(file_content))
img.verify() # Bozuk dosya kontrolü
except:
raise Exception("Geçersiz görsel dosyası")

return mime
2. Dosya Adı Güvenliği
Kötü Uygulama:

Kullanıcı dosya adını doğrudan kullanma

Özel karakterleri filtrelememe

Güvenli Uygulama:

python
import uuid
import os
import re

def safe_filename(original_filename):
# 1. Benzersiz ID oluştur
unique_id = uuid.uuid4().hex

# 2. Orijinal uzantıyı al (güvenli şekilde)
extension = os.path.splitext(original_filename)[1].lower()

# 3. Sadece güvenli uzantılara izin ver
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.pdf', '.webp'}
if extension not in ALLOWED_EXTENSIONS:
raise Exception("Geçersiz dosya uzantısı")

# 4. Yeni dosya adı oluştur (tahmin edilemez)
return f"{unique_id}{extension}"

# Kullanıcının orijinal adını ayrı bir alanda sakla (isteğe bağlı)
original_name = request.files['file'].filename
safe_name = safe_filename(original_name)
3. Dosya Boyutu Sınırlaması
python
# Flask örneği
app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024 # 5MB

# Manuel kontrol
def validate_file_size(file_content):
MAX_SIZE = 5 * 1024 * 1024 # 5MB
if len(file_content) > MAX_SIZE:
raise Exception("Dosya boyutu 5MB'ı geçemez")

# ZIP bomb kontrolü (sıkıştırılmış dosya)
if file_content.startswith(b'PK'): # ZIP dosyası
import zipfile
with zipfile.ZipFile(io.BytesIO(file_content)) as zf:
total_size = sum(info.file_size for info in zf.infolist())
if total_size > 100 * 1024 * 1024: # 100MB
raise Exception("ZIP dosyası çok büyük")
4. Dosya İçeriği Temizleme (Sanitization)
python
import io
from PIL import Image

def sanitize_image(file_content):
try:
# 1. Görseli yeniden oluştur (metadata temizleme)
img = Image.open(io.BytesIO(file_content))

# 2. Görseli yeniden kaydet (EXIF metadata temizle)
output = io.BytesIO()
img.save(output, format=img.format)

# 3. Boyut kontrolü
if img.width > 4000 or img.height > 4000:
raise Exception("Görsel boyutları çok büyük")

return output.getvalue()

except Exception as e:
raise Exception(f"Görsel işlenemedi: {str(e)}")
5. Güvenli Depolama
Kötü Uygulama:

python
# Dosyayı web root altında saklama
file.save('/var/www/html/uploads/' + filename)
Güvenli Uygulama:

python
import os

def save_file_safely(file_content, safe_filename):
# 1. Web root dışında sakla
UPLOAD_DIR = '/var/data/uploads/'

# 2. Tarih bazlı alt dizin oluştur
import datetime
date_path = datetime.datetime.now().strftime('%Y/%m/%d')
full_path = os.path.join(UPLOAD_DIR, date_path)
os.makedirs(full_path, exist_ok=True)

# 3. Dosyayı kaydet
file_path = os.path.join(full_path, safe_filename)
with open(file_path, 'wb') as f:
f.write(file_content)

# 4. Dosya izinlerini sıkılaştır
os.chmod(file_path, 0o644) # Sadece okuma izni

return file_path
6. İndirme Mekanizması Güvenliği
Kötü Uygulama:

python
# Doğrudan dosya sunma
return send_file('/var/data/uploads/' + filename)
Güvenli Uygulama:

python
from flask import send_file, abort

def download_file(file_id, current_user):
# 1. Dosyayı veritabanından getir
file_record = File.objects.get(id=file_id)

# 2. Yetkilendirme kontrolü
if file_record.user_id != current_user.id:
abort(403)

# 3. Dosya yolunu güvenli şekilde oluştur
file_path = os.path.join(UPLOAD_DIR, file_record.stored_path)

# 4. Path traversal kontrolü
real_path = os.path.realpath(file_path)
if not real_path.startswith(os.path.realpath(UPLOAD_DIR)):
abort(403)

# 5. Dosyayı stream et
return send_file(real_path,
as_attachment=True,
download_name=file_record.original_name)
7. Virüs Taraması
python
import subprocess

def scan_file(file_path):
# ClamAV ile tarama
try:
result = subprocess.run(
['clamscan', file_path],
capture_output=True,
timeout=30
)
if b'FOUND' in result.stdout:
raise Exception("Virüs tespit edildi")
return True
except subprocess.TimeoutExpired:
raise Exception("Virüs taraması zaman aşımına uğradı")
8. Rate Limiting ve Kaynak Koruması
python
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)

@app.route('/upload', methods=['POST'])
@limiter.limit("10 per minute") # Dakikada 10 dosya
def upload_file():
# Upload işlemi
pass
Dosya Yükleme Güvenliği Kontrol Listesi:
A. Yükleme Aşaması:
Dosya uzantısı beyaz listesi kullanılıyor

MIME tipi kontrolü (magic bytes) yapılıyor

Dosya boyutu sınırlandırılmış

Dosya adı rastgele ve tahmin edilemez

Zararlı içerik temizlenmiş

Virüs taraması yapılmış

Rate limiting uygulanmış

B. Depolama Aşaması:
Dosyalar web root dışında saklanıyor

Dosya izinleri sıkılaştırılmış

Tarih bazlı dizin yapısı kullanılıyor

Şifreli depolama (opsiyonel)

C. Erişim Aşaması:
Yetkilendirme kontrolü yapılıyor

Path traversal engellenmiş

İndirme logları tutuluyor

Dosya türüne göre content-type doğru ayarlanıyor

D. İzleme ve Log:
Tüm yükleme ve indirme işlemleri loglanıyor

Anormal aktiviteler izleniyor

Hata mesajları bilgi sızdırmıyor

Sık Yapılan Hatalar ve Çözümleri:
Hata Risk Çözüm
Sadece uzantı kontrolü MIME sahteciliği Magic bytes kontrolü ekle
Kullanıcı dosya adını kullanma Path traversal Rastgele yeniden adlandır
Web root altında saklama Doğrudan erişim Web root dışında sakla
Content-Type header'ına güvenme MIME sahteciliği Gerçek dosya içeriğini kontrol et
Hata mesajlarını gösterme Bilgi sızıntısı Genel hata mesajları göster
Virüs taraması yapmama Zararlı dosya ClamAV veya benzeri kullan
Yetkilendirme kontrolü atlama IDOR Her dosya için yetki kontrolü yap

🔒 Bu içeriği görmek için giriş yapın

 
Yanıt yazmak için giriş yapmalısınız
Forum özelliklerini kullanmak ve Level 2 üyelik satın almak için hesabınıza giriş yapın.
133,687Konular
3,289,036Mesajlar
324,410Kullanıcılar
Feyzoooo1234Son Üye
Üst Alt