Ana Karargâh Neler Yapıyoruz?
Hikayemizin Perde Arkası Beyin Kıvılcımları Bağlantıya Geçin

Güvenli File Upload: MIME Türü Doğrulama ve Antivirüs Taraması

Merhaba değerli okuyucular! Bugün, web uygulamalarında sıkça karşılaşılan ve önemli güvenlik riskleri taşıyan dosya yükleme işlemlerini ele alacağız. Özellikle MIME türü doğrulama ve antivirüs taraması gibi kritik güvenlik önlemlerine odaklanacağız. Bu tekniklerin nasıl uygulanacağını ve neden önemli olduklarını detaylıca inceleyeceğiz. Hazırsanız, güvenli dosya yüklemenin inceliklerine dalalım!

Dosya Yükleme Riskleri

Güvensiz dosya yükleme işlemleri aşağıdaki riskleri taşıyabilir:

  • Zararlı yazılımların sisteme bulaşması
  • Sunucu tarafı betik çalıştırma (örn. PHP shell)
  • Dosya sistemi saldırıları
  • Depolama alanı tüketimi
  • Hassas verilerin ifşası

MIME Türü Doğrulama

MIME (Multipurpose Internet Mail Extensions) türü, bir dosyanın içerik türünü belirtir. MIME türü doğrulama, yüklenen dosyanın iddia ettiği türde olduğunu kontrol etmeye yarar.

MIME Türü Doğrulama Örneği (Node.js):


const fileType = require('file-type');
const fs = require('fs');

async function validateMIMEType(filePath, allowedTypes) {
    const buffer = await fs.promises.readFile(filePath);
    const type = await fileType.fromBuffer(buffer);

    if (!type || !allowedTypes.includes(type.mime)) {
        throw new Error('Geçersiz dosya türü');
    }

    return type.mime;
}

// Kullanım
try {
    const mime = await validateMIMEType('/path/to/file.jpg', ['image/jpeg', 'image/png']);
    console.log('Dosya türü geçerli:', mime);
} catch (error) {
    console.error('Hata:', error.message);
}

Antivirüs Taraması

Antivirüs taraması, yüklenen dosyaların zararlı yazılım içermediğinden emin olmak için kritik öneme sahiptir.

Antivirüs Tarama Örneği (Node.js ve ClamAV):


const NodeClam = require('clamscan');

async function scanFile(filePath) {
    const clamscan = await new NodeClam().init({
        clamdscan: {
            socket: '/var/run/clamav/clamd.ctl',
        },
    });

    try {
        const {isInfected, viruses} = await clamscan.scanFile(filePath);
        if (isInfected) {
            throw new Error(`Dosya virüslü: ${viruses.join(', ')}`);
        }
        return 'Dosya temiz';
    } catch (error) {
        throw new Error(`Tarama hatası: ${error.message}`);
    }
}

// Kullanım
scanFile('/path/to/file.jpg')
    .then(result => console.log(result))
    .catch(error => console.error('Hata:', error.message));

Güvenli Dosya Yükleme Best Practices

1. Dosya Uzantısını ve MIME Türünü Doğrulayın

Hem dosya uzantısını hem de MIME türünü kontrol edin.


function validateFile(file, allowedExtensions, allowedMimeTypes) {
    const extension = file.name.split('.').pop().toLowerCase();
    if (!allowedExtensions.includes(extension)) {
        throw new Error('Geçersiz dosya uzantısı');
    }

    if (!allowedMimeTypes.includes(file.type)) {
        throw new Error('Geçersiz MIME türü');
    }

    return true;
}

2. Dosya Boyutunu Sınırlayın

Yüklenebilecek maksimum dosya boyutunu belirleyin.


const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB

if (file.size > MAX_FILE_SIZE) {
    throw new Error('Dosya boyutu çok büyük');
}

3. Dosya İsimlerini Yeniden Oluşturun

Güvenli ve benzersiz dosya isimleri oluşturun.


const crypto = require('crypto');
const path = require('path');

function generateSafeFilename(originalFilename) {
    const extension = path.extname(originalFilename);
    const safeFilename = crypto.randomBytes(16).toString('hex');
    return `${safeFilename}${extension}`;
}

4. Dosyaları Güvenli Bir Konuma Kaydedin

Yüklenen dosyaları web kök dizininin dışında saklayın.


const UPLOAD_DIR = '/secure/upload/directory';

// Dosya yükleme işlemi

5. Yüklenen Dosyaların İçeriğini İşleyin

Gerektiğinde, yüklenen dosyaların içeriğini işleyin (örn. resimleri yeniden boyutlandırma).

6. Rate Limiting Uygulayın

Kısa sürede çok sayıda dosya yüklenmesini engelleyin.


const rateLimit = require("express-rate-limit");

const uploadLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 dakika
    max: 5 // Her IP için 15 dakikada maksimum 5 yükleme
});

app.post('/upload', uploadLimiter, (req, res) => {
    // Dosya yükleme işlemi
});

Güvenli Dosya Yükleme Sınıfı

Tüm bu güvenlik önlemlerini bir araya getiren bir sınıf örneği:


const fileType = require('file-type');
const fs = require('fs').promises;
const path = require('path');
const crypto = require('crypto');
const NodeClam = require('clamscan');

class SecureFileUploader {
    constructor(options) {
        this.allowedExtensions = options.allowedExtensions || [];
        this.allowedMimeTypes = options.allowedMimeTypes || [];
        this.maxFileSize = options.maxFileSize || 5 * 1024 * 1024; // 5MB default
        this.uploadDir = options.uploadDir || '/secure/upload/directory';
    }

    async uploadFile(file) {
        await this.validateFile(file);
        const safeFilename = this.generateSafeFilename(file.name);
        const filePath = path.join(this.uploadDir, safeFilename);
        
        await fs.writeFile(filePath, file.data);
        await this.scanFile(filePath);

        return safeFilename;
    }

    async validateFile(file) {
        // Uzantı kontrolü
        const extension = path.extname(file.name).toLowerCase().slice(1);
        if (!this.allowedExtensions.includes(extension)) {
            throw new Error('Geçersiz dosya uzantısı');
        }

        // MIME türü kontrolü
        const type = await fileType.fromBuffer(file.data);
        if (!type || !this.allowedMimeTypes.includes(type.mime)) {
            throw new Error('Geçersiz MIME türü');
        }

        // Boyut kontrolü
        if (file.data.length > this.maxFileSize) {
            throw new Error('Dosya boyutu çok büyük');
        }
    }

    generateSafeFilename(originalFilename) {
        const extension = path.extname(originalFilename);
        const safeFilename = crypto.randomBytes(16).toString('hex');
        return `${safeFilename}${extension}`;
    }

    async scanFile(filePath) {
        const clamscan = await new NodeClam().init({
            clamdscan: {
                socket: '/var/run/clamav/clamd.ctl',
            },
        });

        const {isInfected, viruses} = await clamscan.scanFile(filePath);
        if (isInfected) {
            await fs.unlink(filePath); // Virüslü dosyayı sil
            throw new Error(`Dosya virüslü: ${viruses.join(', ')}`);
        }
    }
}

// Kullanım örneği
const uploader = new SecureFileUploader({
    allowedExtensions: ['jpg', 'png', 'pdf'],
    allowedMimeTypes: ['image/jpeg', 'image/png', 'application/pdf'],
    maxFileSize: 10 * 1024 * 1024, // 10MB
    uploadDir: '/secure/uploads'
});

async function handleFileUpload(file) {
    try {
        const filename = await uploader.uploadFile(file);
        console.log(`Dosya başarıyla yüklendi: ${filename}`);
    } catch (error) {
        console.error('Dosya yükleme hatası:', error.message);
    }
}

Güvenli dosya yükleme, web uygulamalarının güvenliği için kritik öneme sahiptir. MIME türü doğrulama ve antivirüs taraması gibi teknikler, potansiyel tehditleri önemli ölçüde azaltır. Ancak, bu önlemlerin yanı sıra, düzenli güvenlik güncellemeleri, kullanıcı eğitimi ve sıkı erişim kontrolü gibi ek güvenlik pratiklerini de uygulamak önemlidir.

Unutmayın ki, güvenlik sürekli bir süreçtir. Yeni tehditler ortaya çıktıkça, güvenlik önlemlerinizi güncellemek ve geliştirmek gerekecektir.

Siz dosya yükleme işlemlerini nasıl güvence altına alıyorsunuz? Karşılaştığınız zorluklar veya paylaşmak istediğiniz ek öneriler var mı? Yorumlarınızı bekliyorum!

Güvenli kodlamalar ve güvenli dosya yüklemeleri dilerim!