- Konu sahibi
- #1
Zararlı dosya taramasını, yüklenen dosya kullanıcıya açılmadan önce çalışan bir kabul kapısı olarak ekleyin. Dosya önce erişimi kısıtlı geçici veya karantina alanında tutulur; tür, boyut ve tarama sonucu doğrulanır. Yalnız açıkça başarılı tarama sonucu dosyayı sonraki aşamaya geçirir. Zaman aşımı veya tanınmayan yanıt temiz sonucu sayılmaz.
Bu işlem genel dosya yükleme doğrulamasından ayrıdır: aşağıdaki örnek ClamAV clamd servisine gerçek dosya baytlarının aktarılmasını ve yanıtın karara çevrilmesini gösterir. Tarama, kimlik/CSRF, tür, boyut ve indirme yetkisi kontrollerinin yerine geçmez. İstemci JavaScript’i bu kapının güvenilir uygulama noktası değildir.
clamd güncel imza veritabanıyla çalışmalı; StreamMaxLength, MaxFileSize ve MaxScanSize politikanızla uyumlu olmalıdır. Limit nedeniyle atlanan içeriğin sessiz başarı sayılmaması için AlertExceedsMax davranışını yapılandırıp sınayın; kısıtlanan dosyayı yayımlamayın. TCP protokolü şifreleme veya kimlik doğrulama sağlamaz; örnekte aynı sunucunun loopback adresi kullanılır. Portu dış ağa açmayın. Daha yüksek hacimde sınırlı işçi ve karantina kuyruğu planlayın.
INSTREAM komutu n öneki ve satır sonuyla gönderilir. Her veri parçasının önünde dört baytlık büyük uçlu uzunluk bulunur; sıfır uzunluk akışı bitirir. Kod kısmi yazmaları tamamlar, boyutu sınırlar ve okuma/yazma beklemelerine kalan bütçeyi uygular. Yerel dosya I/O’su ve tüm HTTP isteği için ayrıca uygulama kaynak sınırları gerekir; bu tek işlev sunucunun toplam kapasitesini yönetmez.
Bu işlem genel dosya yükleme doğrulamasından ayrıdır: aşağıdaki örnek ClamAV clamd servisine gerçek dosya baytlarının aktarılmasını ve yanıtın karara çevrilmesini gösterir. Tarama, kimlik/CSRF, tür, boyut ve indirme yetkisi kontrollerinin yerine geçmez. İstemci JavaScript’i bu kapının güvenilir uygulama noktası değildir.
Tarama kapısının sözleşmesi
Çağıran uygulama, yalnız kendi ürettiği sunucu yolunu tarama işlevine verir; kullanıcıdan gelen dosya yolu kabul edilmez. Karantina web kökü dışında olmalı, dosya tarama ile kabul arasında değiştirilmemelidir. Tarama sonrası başka içerik işleniyorsa yayımlanan baytların hâlâ onaylanan dosyaya ait olduğunu doğrulayın.clamd güncel imza veritabanıyla çalışmalı; StreamMaxLength, MaxFileSize ve MaxScanSize politikanızla uyumlu olmalıdır. Limit nedeniyle atlanan içeriğin sessiz başarı sayılmaması için AlertExceedsMax davranışını yapılandırıp sınayın; kısıtlanan dosyayı yayımlamayın. TCP protokolü şifreleme veya kimlik doğrulama sağlamaz; örnekte aynı sunucunun loopback adresi kullanılır. Portu dış ağa açmayın. Daha yüksek hacimde sınırlı işçi ve karantina kuyruğu planlayın.
| Tarama sonucu | Dosyanın durumu | Sonraki adım |
|---|---|---|
| CLEAN | Tarama tamamlandı, tespit yok | Diğer kontroller geçtiyse kontrollü kabul |
| MALWARE | Tespit var | Erişimi kapalı tut, inceleme politikasını uygula |
| ERROR | Tamamlanma doğrulanamadı | Yayımlama, sınırlı yeniden deneme veya ret |
PHP ile tamamlanmış tarama işlevi
Bu parça tüm yükleme uç noktası değildir; önceden doğrulanmış, uygulamanın sahip olduğu özel dosya için PHP8 tarama adaptörüdür. Dosyayı taşımaz veya silmez. Ön koşul PHP stream desteği ve 127.0.0.1:3310 üzerinde çalışan yerel clamd servisidir:
PHP:
<?php
function scanLocalUpload(string $path): string
{
$input = @fopen($path, 'rb');
if ($input === false) return 'ERROR';
$socket = false;
try {
$stat = fstat($input);
$limit = 10 * 1024 * 1024;
if (!$stat || $stat['size'] <= 0 || $stat['size'] > $limit) return 'ERROR';
$socket = @stream_socket_client('tcp://127.0.0.1:3310', $errno, $error, 3);
if ($socket === false) return 'ERROR';
$deadline = microtime(true) + 10;
$budget = static function () use ($socket, $deadline): bool {
$left = $deadline - microtime(true);
if ($left < 0.001) return false;
return stream_set_timeout($socket, (int)$left,
(int)(($left - (int)$left) * 1000000));
};
$send = static function (string $data) use ($socket, $budget): bool {
for ($offset = 0; $offset < strlen($data);) {
if (!$budget()) return false;
$n = @fwrite($socket, substr($data, $offset));
if ($n === false || $n === 0) return false;
$offset += $n;
}
return true;
};
if (!$send("nINSTREAM
")) return 'ERROR';
$total = 0;
while (!feof($input)) {
$chunk = fread($input, 65536);
if ($chunk === false || ($chunk === '' && !feof($input))) return 'ERROR';
if ($chunk === '') break;
$total += strlen($chunk);
if ($total > $limit || !$send(pack('N', strlen($chunk)) . $chunk)) return 'ERROR';
}
if (!$send(pack('N', 0)) || !$budget()) return 'ERROR';
$reply = fgets($socket, 4096);
if (stream_get_meta_data($socket)['timed_out']) return 'ERROR';
if ($reply === "stream: OK
") return 'CLEAN';
if (is_string($reply) && str_contains($reply, 'Heuristics.Limits.Exceeded')) return 'ERROR';
if (is_string($reply) && preg_match('/^stream: .+ FOUND
$/D', $reply)) return 'MALWARE';
return 'ERROR';
} finally {
fclose($input);
if (is_resource($socket)) fclose($socket);
}
}
INSTREAM komutu n öneki ve satır sonuyla gönderilir. Her veri parçasının önünde dört baytlık büyük uçlu uzunluk bulunur; sıfır uzunluk akışı bitirir. Kod kısmi yazmaları tamamlar, boyutu sınırlar ve okuma/yazma beklemelerine kalan bütçeyi uygular. Yerel dosya I/O’su ve tüm HTTP isteği için ayrıca uygulama kaynak sınırları gerekir; bu tek işlev sunucunun toplam kapasitesini yönetmez.
Entegrasyonu doğrulama sırası
- Yetkili deneme ortamında ön kontrolleri geçmiş küçük bir örnek dosya için işlevi çağırın; CLEAN sonrası kabul kararını ayrıca uygulayın.
- Güvenilir EICAR test dosyasını yalnız tarama adaptöründe sınayın. Yükleme tür listesi metin dosyasını daha önce reddediyorsa bu, antivirüsün çalıştığını göstermez.
- Daemon erişilemezken ve sınır aşımında ERROR geldiğini, dosyanın erişime açılmadığını doğrulayın. Gerçek üretim servisini test için durdurmayın.