Wie man hoch geladene Dateien automatisch auf Viren überprüft mit php-clamavlib

5 Ein kleines Beispiel

Nun werden wir ein kleines Skript zum Hochladen von Dateien erstellen, /var/www/upload.php, welches ein HTML Formular zum Hochladen von Dateien beinhaltet. Wenn Du das Formular absendest, wird sich das Skript selbst aufrufen und die Funktionen cl_info(), cl_scanfile(), cl_setlimits(), und clam_get_version() verwenden um die hochgeladene Datei auf Viren zu überprüfen. Wenn die Datei in Ordnung ist, wird sie in das Verzeichnis /var/www/uploads hoch geladen, anderenfalls zeigt das Skript eine Fehlermeldung (die angibt, welcher Virus/Wurm etc. gefunden worden ist) und löscht die Datei auf dem Server.

Zunächst müssen wir das Verzeichnis /var/www/uploads erstellen und es für den Apache Benutzer www-data beschreibbar zu machen:

mkdir /var/www/uploads
chown www-data:www-data /var/www/uploads

Dann erstellen wir die Datei /var/www/upload.php:

vi /var/www/upload.php

<?php
$upload_dir = '/var/www/uploads/';

if($_POST){
  $error = '';
  //print_r($_FILES);
  if($_FILES['file']['size'] == 0 || !is_file($_FILES['file']['tmp_name'])){
     $error .= 'Please select a file for upload!';
  } else {
    cl_setlimits(5, 1000, 200, 0, 10485760);
    if($malware = cl_scanfile($_FILES['file']['tmp_name'])) $error .= 'We have Malware: '.$malware.'<br>ClamAV version: '.clam_get_version();
  }
  if($error == ''){
    rename($_FILES['file']['tmp_name'], $upload_dir.$_FILES['file']['name']);
  }
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>File-Upload</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<form method="post" action="upload.php" name="fileupload" enctype="multipart/form-data">
<table width="100%" border="0" cellspacing="0" cellpadding="2">
  <tr><td><b>File Upload</b></td></tr>
  <tr><td> </td></tr>
  <?php
  if(isset($error)){
    if($error != ''){
  ?>
  <tr><td><?php echo cl_info(); ?></tr>
  <tr><td><b>Error:</b> <?php echo $error; ?></td></tr>
  <?php
    } else {
  ?>
  <tr><td><b>File <?php echo $_FILES['file']['name']; ?> has successfully been uploaded to <?php echo $upload_dir; ?>!</b></td></tr>
  <?php
    }
  }
  ?>
  <tr><td>
    <table width="500" border="0" cellspacing="0" cellpadding="2">
      <tr>
        <td width="126">File:</td>
        <td width="366"><input type="file" name="file" size="30" value="" maxlength="255"></td>
      </tr>
      <tr>
        <td> </td>
        <td><input name="Upload" type="submit" value="Upload"> <input name="Cancel" type="reset" value="Cancel"></td>
      </tr>
    </table>
  </td></tr>
</table>
</form>
</body>
</html>

Es beinhaltet das Formular für die hochgeladene Datei:

[...]
<form method="post" action="upload.php" name="fileupload" enctype="multipart/form-data">
<table width="100%" border="0" cellspacing="0" cellpadding="2">
  <tr><td><b>File Upload</b></td></tr>
  <tr><td> </td></tr>
  <?php
  if(isset($error)){
    if($error != ''){
  ?>
  <tr><td><?php echo cl_info(); ?></tr>
  <tr><td><b>Error:</b> <?php echo $error; ?></td></tr>
  <?php
    } else {
  ?>
  <tr><td><b>File <?php echo $_FILES['file']['name']; ?> has successfully been uploaded to <?php echo $upload_dir; ?>!</b></td></tr>
  <?php
    }
  }
  ?>
  <tr><td>
    <table width="500" border="0" cellspacing="0" cellpadding="2">
      <tr>
        <td width="126">File:</td>
        <td width="366"><input type="file" name="file" size="30" value="" maxlength="255"></td>
      </tr>
      <tr>
        <td> </td>
        <td><input name="Upload" type="submit" value="Upload"> <input name="Cancel" type="reset" value="Cancel"></td>
      </tr>
    </table>
  </td></tr>
</table>
</form>
[...]

Nachdem Du eine Datei ausgewählt und auf Submit geklickt hast, wird sich das Skript selbst aufrufen und (action=“upload.php“) und den PHP Code zu Beginn ausführen:

[...]
if($_POST){
  $error = '';
  //print_r($_FILES);
  if($_FILES['file']['size'] == 0 || !is_file($_FILES['file']['tmp_name'])){
     $error .= 'Please select a file for upload!';
  } else {
    cl_setlimits(5, 1000, 200, 0, 10485760);
    if($malware = cl_scanfile($_FILES['file']['tmp_name'])) $error .= 'We have Malware: '.$malware.'<br>ClamAV version: '.clam_get_version();
  }
  if($error == ''){
    rename($_FILES['file']['tmp_name'], $upload_dir.$_FILES['file']['name']);
  }
}
[...]

Angaben über die hochgeladene Datei sind gespeichert in $_FILES array, also nutzen wir dies um die Datei zu überprüfen (Du kannst die Zeile print_r($_FILES); aktivieren um zu sehen, was im array abgelegt ist).

Ich verwende die cl_setlimits() Funktion um die Limits für die Virenüberprüfung einzurichten, um DOS Angriffe zu verhindern (der Virenüberprüfungsprozess kann alle Systemressourcen aufbrauchen). So sieht die Verwendung aus:

cl_setlimits($maxreclevel, $maxfiles, $maxratio, $archivememlim, $maxfilesize)

  • $maxreclevel: integer value /* maximal recursion level */
  • $maxfiles: integer value /* maximal number of files to be scanned within archive */
  • $maxratio: integer value /* maximal compression ratio */
  • $archivememlim: boolean /* limit memory usage for bzip2 (0/1) */
  • $maxfilesize: long integer /* archived files larger than this value (in bytes) will not be scanned */

Im Grunde definieren diese Werte das Verhalten von ClamAV wenn die Archive (zip files, tar.gz files, bz2 files, etc.) überprüft werden. Wenn Du die cl_setlimits() Funktion nicht verwendest, werden die entsprechenden Werte aus der Datei php.ini genommen.

Die Hauptfunktion ist die cl_scanfile() Funktion, die als Argument den Pfad zur zu überprüfenden Datei übernimmt. Hochgeladene Dateien werden vorübergehend gespeichert bevor sie verarbeitet werden (für gewöhnlich in /tmp; das hängt von Deinen php.ini Einstellungen ab). Diese vorläufige Datei wird gespeichert in $_FILES[‚file‘][‚tmp_name‘] also übergeben wir diese Variable an die cl_scanfile() Funktion. Wenn keine Virus gefunden wird, gibt sie FALSE zurück, sonst wird der Name des Virus‘ angezeigt.

clam_get_version() benötigt keine Parameter. Diese Funktion gibt die Version des installierten ClamAV (wie 0.88.4) zurück.

Letztenendes verwende ich die Funktion cl_info() welche – wie clam_get_version() – keine Parameter benötigt. Sie gibt nähere Informationen über ClamAV an, zum Beispiel ClamAV version 0.88.4 with 85917 virus signatures loaded.

Lass es uns nun testen. Gib http://192.168.0.100/upload.php in Deinem Browser ein. Dies solltest Du nun sehen:

Klicke auf Browse… und wähle eine Datei aus, die Du von Deiner Festplatte hochladen möchtest (eine Datei, die kein Viruas und nicht größer als 2 MB ist – das ist die maximale Standardgröße zum Hochladen, die in Deiner php.ini Datei geändert werden kann):

Der Ladevorgang sollte gelingen und etwas Ähnliches müsstest Du jetzt sehen:

Nun müssen wir einen Virus bekommen um es zu testen. Glücklicherweise gibt es einen Eicar Testvirus, eine Datei, die keinen Schaden anrichtet, aber dessen Signatur von allen Virenscannern erkannt wird, damit Du testen kannst, ob Dein Virenscanner funktioniert. Gehe zu http://www.eicar.org/anti_virus_test_file.htm und lade die Dateien eicar.com, eicar_com.zip, und the eicarcom2.zip files auf Deine Festplatte. Teste dann das Hochladen mit jeder von ihnen:

Wenn alles klappt, sollte php-clamavlib den Virus erkennen und sich weigern ihn hochzuladen:

6 Links

Das könnte dich auch interessieren …