Linux管理・運用の基本
システム管理者のための実践ガイド
システム管理者のための実践ガイド
Gitサーバーが開発者向けなら、Webサーバーは不特定多数のユーザーに向けた窓口です。悪意のあるユーザーが、脆弱性を突くためのスクリプトや、マルウェアを仕込んだPDFをアップロードしてくるリスクは常に存在します。
「アップロード後に深夜の定期スキャンで消せばいい」という考えは危険です。ファイルが置かれた瞬間に実行されたり、他のユーザーにダウンロードされたりするからです。
今回は、アプリケーションの裏側でClamAVを呼び出し、「汚染ファイルは保存すらさせない」ためのリアルタイム連携を構築します。
Webアプリにおけるアンチウイルス連携の鉄則は、「検査に合格するまで、Web公開ディレクトリ(Document Root)にファイルを置かない」ことです。
Web公開ディレクトリ(/var/www/html等)の外に、Webアプリ権限(www-data等)だけがアクセスできる一時領域を作成します。
sudo mkdir -p /var/www/uploads_tmp
sudo chown www-data:www-data /var/www/uploads_tmp
sudo chmod 700 /var/www/uploads_tmp
ファイル名のサニタイズとMIMEチェックを組み合わせた、堅牢な実装例です。
<?php
// 1. 基本的なバリデーション
$tmp_file = $_FILES['upload_file']['tmp_name'];
if (!is_uploaded_file($tmp_file)) exit("無効なリクエストです");
// 2. MIMEタイプチェック(ClamAVで防げない不正ファイル対策)
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $tmp_file);
$allowed = ['image/jpeg', 'image/png', 'application/pdf'];
if (!in_array($mime, $allowed)) {
unlink($tmp_file);
exit("許可されていないファイル形式です");
}
// 3. ClamAVスキャン実行
// escapeshellarg でコマンドインジェクションを防止
exec("clamdscan --no-summary --quiet " . escapeshellarg($tmp_file), $output, $retval);
if ($retval === 0) {
// クリーンな場合:ファイル名をサニタイズして保存
$safe_name = preg_replace("/[^a-zA-Z0-9._-]/", "_", basename($_FILES['upload_file']['name']));
$destination = "/var/www/html/storage/" . uniqid() . "_" . $safe_name;
if (move_uploaded_file($tmp_file, $destination)) {
echo "アップロード成功!";
}
} elseif ($retval === 1) {
// ウイルス検知時
unlink($tmp_file);
error_log("VIRUS DETECTED: " . $_FILES['upload_file']['name']);
exit("セキュリティリスクが検知されたため、保存を拒否しました");
} else {
// clamd未起動などのシステムエラー
error_log("ClamAV system error. Exit code: " . $retval);
unlink($tmp_file);
exit("システムエラーが発生しました。時間を置いて再度お試しください");
}
?>
スキャンに時間がかかると、WebサーバーやPHP-FPMのタイムアウト設定に引っかかる場合があります。
解決方法:
nginx の proxy_read_timeout や PHPの max_execution_time を適切に調整する。exec() による外部プロセス起動はコストがかかります。
解決方法:
/var/run/clamav/clamd.ctl)経由で直接 clamd と通信するライブラリ(PHPなら ClamAV-Client 等)を使用すると、さらに高速・低負荷になります。第6回では、Webサーバーの最前線における「多層防御」について解説しました。
これで、Webアプリケーションの信頼性を支える強固なアップロード機能が実現できました。
しかし、運用を続けていると「正当なファイルなのにウイルスと誤認される(誤検知)」や、逆に「検知したことをすぐに知りたい」という場面に必ず遭遇します。
次回は「便利編」として、検知結果を Slackへリアルタイム通知 する方法や、誤検知(ホワイトリスト)へのスマートな対応について解説します。
ご覧いただきありがとうございました。