ClamAVによるリアルタイムスキャンの設定
(2023.12.12追記)
ClamAV 1.0 のリアルタイムスキャン設定について、新しい記事を書きました。
RHEL 9系での設定については、そちらを参照するとよいと思います。
・ClamAVによるリアルタイムスキャンの設定(ClamAV 1.0版)
https://inaba-serverdesign.jp/blog/20231122/clamav-realtime-scan-v10.html
(2023.12.12追記ここまで)
- はじめに
- ClamAVのリアルタイムスキャン機能
- ClamAVのインストール
- ウイルスデータベースの取得と更新設定
- clamdの設定と動作確認
- リアルタイムスキャンの設定と動作確認
- リアルタイムスキャンの検知漏れ問題と対策
- まとめ
1. はじめに
サーバーのウイルス対策として、以前、ClamAVによる定期ウイルススキャンの設定という記事を書きました。
今回は、ClamAVによるリアルタイムスキャンの設定にトライしてみます。
長編です。
OSはCentOS 7、ClamAVのバージョンは2021年4月時点のEPEL版では最新の 0.103.1 とします。
サーバーは低スペックのAWS EC2の t2.micro(2vCPU、メモリ1GB)を使用したので、スキャンなどの実行時間は遅いです。
以下、ClamAVのインストールやスキャン実行設定は、rootユーザー(もしくはsudoによるroot権限)で実行します。
2. ClamAVのリアルタイムスキャン機能
ClamAVでは、リアルタイムスキャン機能を「On-Access Scanning」といっています。
リアルタイムスキャン機能は、当初はウイルススキャナデーモンの clamd に含まれていましたが、バージョン 0.102.0 で、clamonacc という新しいアプリケーションに分離されました。
この変更については、ClamAV blog の以下の記事にて詳しく説明されています。
・Understanding and transitioning to ClamAV’s new On-Access scanner – ClamAV blog
https://blog.clamav.net/2019/09/understanding-and-transitioning-to.html
公式ドキュメントはこちら。
・On-Access Scanning – ClamAV Documentation
https://www.clamav.net/documents/on-access-scanning
かんたんにいうと、
「clamonaccは、カーネルのfanotify通知機能によりファイルシステムの変化を検知し、clamdにウイルススキャン判定を依頼する。」
「clamonaccは、ファイルへのアクセスをブロックすることもできる。」
ということですね。
3. ClamAVのインストール
事前準備として、bzipファイルも検索できるよう、bzlib.hをインストールします。
# yum install bzip2-devel -- インストール: bzip2-devel.x86_64 0:1.0.6-13.el7 --
もしEPELリポジトリがインストールされていなければ、インストールします。
# yum install epel-release -- インストール: epel-release.noarch 0:7-11 --
EPELリポジトリより、ClamAV本体(clamavパッケージ)、ウイルススキャナデーモン (clamd)と、ウイルスデータベース更新機能(clamav-updateパッケージ)をインストールします。
# yum --enablerepo=epel install clamav clamd clamav-update -- 依存性関連をインストールしました: clamav-filesystem.noarch 0:0.103.1-3.el7 clamav-lib.x86_64 0:0.103.1-3.el7 libprelude.x86_64 0:5.2.0-2.el7 libtool-ltdl.x86_64 0:2.4.2-22.el7_3 pcre2.x86_64 0:10.23-2.el7 --
リアルタイムスキャンに使用する clamonacc は、clamavパッケージに含まれています。
# rpm -ql clamav -- /usr/bin/clambc /usr/bin/clamconf /usr/bin/clamdscan /usr/bin/clamdtop /usr/bin/clamscan /usr/bin/clamsubmit /usr/bin/sigtool /usr/lib/systemd/system/clamav-clamonacc.service /usr/lib/systemd/system/clamonacc.service --
4. ウイルスデータベースの取得と更新設定
ウイルススキャンを実施する前に、ウイルスデータベースを取得、更新する設定を行います。
- 4-1. ウイルスデータベース更新設定
- 4-2. ウイルスデータベースの取得
4-1. ウイルスデータベース更新設定
ウイルスデータベースの更新コマンドは /usr/bin/freshclam です。
freshclam の設定ファイル /etc/freshclam.conf を変更します。
- Example 行がコメントアウトされていることを確認。
- (お好みで)ログファイルは /var/log/freshclam.log、LogSyslog no でログはSyslogを使用せず、LogTimeで時刻を記録するようにします。
- DatabaseMirror 行で、ウイルスデータベース配布サーバーとして日本のミラーサーバー db.jp.clamav.net を追加登録します。日本のミラーサーバーからの取得に失敗することもあるので、デフォルトの database.clamav.net も残しておきます。
ClamAV関連の設定ファイルでは、DatabaseMirror 行のように、複数指定する場合には、カンマ区切りやスペース区切りで複数記載するのではなく、同じパラメータ名を複数行で記載するのがポイントです。
# vim /etc/freshclam.conf -- #Example // コメントアウトされていることを確認 ... UpdateLogFile /var/log/freshclam.log // ログはsyslogではなく/var/log/freshclam.logに書き出す ... LogTime yes // コメントアウトを外す(ログ記録時に時刻を記録) #LogSyslog yes LogSyslog no // syslogは無効とする。 ... DatabaseMirror db.jp.clamav.net // 日本のDBミラーサイトをデフォルトの前に追記 DatabaseMirror database.clamav.net ... --
ウイルスデータベースの自動更新については、clamav-updateパッケージによってインストールされた /etc/cron.d/clamav-update と、そこから呼び出される /usr/share/clamav/freshclam-sleep によって定期的に実行されます。
# view /etc/cron.d/clamav-update -- ## Adjust this line... MAILTO=root ## It is ok to execute it as root; freshclam drops privileges and becomes ## user 'clamupdate' as soon as possible 0 */3 * * * root /usr/share/clamav/freshclam-sleep > /dev/null --
念のため、/etc/sysconfig/freshclam を確認します。
FRESHCLAM_DELAY はコメントアウトされているはずですが、コメントアウトされずに、disabled-warn もしくは disabled となっていれば、自動更新が実行されないので、コメントアウトします。
# vim /etc/sysconfig/freshclam -- # FRESHCLAM_DELAY=disabled-warn --
4-2. ウイルスデータベースの取得
freshclamコマンドで、最新バージョンのウイルスデータベースを取得します。
サーバースペックやネットワーク通信速度にもよりますが、初回実行時は数十秒から数分かかります。
time コマンドで処理時間を計測してみます。
# time freshclam -- ClamAV update process started at Wed Apr 7 17:00:42 2021 daily database available for download (remote version: 26132) Time: 4.9s, ETA: 0.0s [========================>] 100.76MiB/100.76MiB Testing database: '/var/lib/clamav/tmp.bd35aa2c15/clamav-64725235c861396c0a59e10ae2f19b49.tmp-daily.cvd' ... Database test passed. daily.cvd updated (version: 26132, sigs: 3968913, f-level: 63, builder: raynman) main database available for download (remote version: 59) Time: 4.6s, ETA: 0.0s [========================>] 112.40MiB/112.40MiB Testing database: '/var/lib/clamav/tmp.bd35aa2c15/clamav-0208cc0c49453cf0ca8c862fee98b9f8.tmp-main.cvd' ... Database test passed. main.cvd updated (version: 59, sigs: 4564902, f-level: 60, builder: sigmgr) bytecode database available for download (remote version: 333) Time: 0.1s, ETA: 0.0s [========================>] 286.79KiB/286.79KiB Testing database: '/var/lib/clamav/tmp.bd35aa2c15/clamav-b1dcf145c0ebd415026f6bde81e6ce2f.tmp-bytecode.cvd' ... Database test passed. bytecode.cvd updated (version: 333, sigs: 92, f-level: 63, builder: awillia2) real 0m29.370s user 0m19.060s sys 0m0.997s --
5. clamdの設定と動作確認
clamdは、ウイルスデータベースをあらかじめ読み込んで動作するウイルススキャナデーモンです。
リアルタイムスキャン機能の clamonacc は、clamd と連携して動作するため、まずは clamd の設定を行います。
- 5-1. clamdの設定
- 5-2. clamdの起動
- 5-3. スキャンの動作確認
5-1. clamdの設定
clamdの設定ファイル /etc/clamd.d/scan.conf を変更します。
- Example 行がコメントアウトされていることを確認します。
- (お好みで)LogSyslog no, Logfile /var/log/clamd.scan でログはSyslogを使用せずログファイルに書き出し、LogTime yes で時刻を記録するようにします。
- TCPSocket 3310, TCPAddr 127.0.0.1 で、TCPSocketで起動するようにします。
- ExcludePath で、スキャン除外パスを指定します。このサーバーでは、/swap.img をスワップファイルとして使用しているので、除外対象パスに追加しています。
- root権限でスキャンするよう、User 行をコメントアウトします。
# vim /etc/clamd.d/scan.conf -- #Example // コメントアウトする LogFile /var/log/clamd.scan // ログはsyslogではなく/var/log/clamd.scanに書き出す。コメントアウトを外す。 LogTime yes // コメントアウトを外す(ログ記録時に時刻を記録) #LogSyslog yes LogSyslog no // syslogは無効とする。 TCPSocket 3310 // コメントアウトを外す TCPAddr 127.0.0.1 // コメントアウトを外す ExcludePath ^/proc/ // スキャン除外パス ExcludePath ^/sys/ ExcludePath ^/swap.img #User clamscan // コメントアウトする --
なお、TCPSocket の代わりに LocalSocket を使用する方法もありますが、LocalSocket を使用した場合は、clamonacc の起動時に、以下のメッセージのとおり「curl のバージョンが低い」ということで起動に失敗します。
4月 07 17:07:26 centos7 clamonacc[30192]: ERROR: Clamonacc: Version of curl is too low to use fdpassing. Please use tcp socket streaming instead
curl をバージョンアップすれば解決するかもしれませんが、ここではあまりこだわらずに TCPSocket を使用することにします。
また、ウイルスデータベースの更新設定で、データベースを更新したときに clamd に通知する設定を行います。
NotifyClamd で、clamd の設定ファイル /etc/clamd.d/scan.conf を指定します。
# vim /etc/freshclam.conf -- #NotifyClamd /path/to/clamd.conf NotifyClamd /etc/clamd.d/scan.conf --
5-2. clamdの起動
clamd を起動しつつ、自動起動設定を行います。
数分時間がかかるので、time コマンドで処理時間を計測してみます。
# time systemctl enable --now clamd@scan -- Created symlink from /etc/systemd/system/multi-user.target.wants/clamd@scan.service to /usr/lib/systemd/system/clamd@.service. real 1m1.204s user 0m0.014s sys 0m0.007s -- # systemctl status clamd@scan -- ● clamd@scan.service - clamd scanner (scan) daemon Loaded: loaded (/usr/lib/systemd/system/clamd@.service; enabled; vendor preset: disabled) Active: active (running) since 水 2021-04-07 18:31:22 JST; 19s ago Docs: man:clamd(8) man:clamd.conf(5) https://www.clamav.net/documents/ Process: 9034 ExecStart=/usr/sbin/clamd -c /etc/clamd.d/%i.conf (code=exited, status=0/SUCCESS) Main PID: 9035 (clamd) CGroup: /system.slice/system-clamd.slice/clamd@scan.service mq9035 /usr/sbin/clamd -c /etc/clamd.d/scan.conf 4月 07 18:30:21 <hostname> systemd[1]: Starting clamd scanner (scan) daem.... 4月 07 18:31:22 <hostname> systemd[1]: Started clamd scanner (scan) daemon. Hint: Some lines were ellipsized, use -l to show in full --
5-3. スキャンの動作確認
clamdscan コマンドで、ウイルススキャンが正しく動作することを確認します。
ここでは、/var/www ディレクトリ以下をスキャンします。
# time clamdscan /var/www -- /var/www: OK ----------- SCAN SUMMARY ----------- Infected files: 0 Time: 0.271 sec (0 m 0 s) Start Date: 2021:04:07 19:06:57 End Date: 2021:04:07 19:06:57 real 0m0.358s user 0m0.000s sys 0m0.010s --
/var/www ディレクトリ以下にほとんどファイルがないこともあり、1秒もかからずに完了します。
ちなみに、clamdscan コマンドではなくて、clamd を利用せずにスキャンする clamscan コマンドを使用すると、以下のように1分半ぐらいかかります。
ウイルスデータベースの読み込み、展開にそれだけ時間がかかるということですね。
# time clamscan --infected /var/www -- ----------- SCAN SUMMARY ----------- Known viruses: 8518553 Engine version: 0.103.1 Scanned directories: 1 Scanned files: 0 Infected files: 0 Data scanned: 0.00 MB Data read: 0.00 MB (ratio 0.00:1) Time: 96.649 sec (1 m 36 s) Start Date: 2021:04:07 19:07:44 End Date: 2021:04:07 19:09:21 real 1m36.814s user 0m18.993s sys 0m1.653s --
続いて、検証用のウイルスファイルをダウンロードし、clamdscanコマンドが正しく検知することを確認します。
# wget https://secure.eicar.org/eicar.com.txt -O /var/www/html/eicar.com.txt # wget https://secure.eicar.org/eicar_com.zip -O /var/www/html/eicar_com.zip # time clamdscan /var/www -- /var/www/html/eicar_com.zip: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND ----------- SCAN SUMMARY ----------- Infected files: 2 Time: 0.320 sec (0 m 0 s) Start Date: 2021:04:07 19:12:59 End Date: 2021:04:07 19:12:59 real 0m0.348s user 0m0.007s sys 0m0.000s --
「Infected files: 2」ということで、正しく検知できました。
「/var/www/html/eicar_com.zip Win.Test.EICAR_HDB-1 FOUND」のように、検知したファイル名と、ウイルス名が記録されました。
clamdのログでも、ウイルス検知が記録されたことを確認します。
# less /var/log/clamd.scan -- Wed Apr 7 19:12:59 2021 -> /var/www/html/eicar_com.zip: Win.Test.EICAR_HDB-1 FOUND Wed Apr 7 19:12:59 2021 -> /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND --
この検証用のウイルスファイルは、リアルタイムスキャンの動作確認でも使用するため、削除せずに残しておきます。
6. リアルタイムスキャンの設定と動作確認
- 6-1. リアルタイムスキャンの方針
- 6-2. fanotifyをサポートしていることの確認
- 6-3. ウイルス検知時に実行するスクリプトの設置
- 6-4. リアルタイムスキャンの設定
- 6-5. リアルタイムスキャンの起動
- 6-6. リアルタイムスキャンの動作確認
- 6-7. ウイルス検知時に実行するスクリプトの修正と動作確認
- 6-8. リアルタイムスキャンの設定について補足
6-1. リアルタイムスキャンの方針
リアルタイムスキャンの方針は以下とします。
- ウイルスを検知したときは、即時、メールで通知する。
- スキャン対象ディレクトリは、Webディレクトリの /var/www と作業ユーザーがファイルをアップロードする可能性がある /home とする。
6-2. fanotifyをサポートしていることの確認
稼働中のサーバーのカーネルが fanotify をサポートしていることを確認します。
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
の2行が確認できればOKです。
# ls /boot/config* -- /boot/config-3.10.0-1062.12.1.el7.x86_64 -- # cat /boot/config-3.10.0-1062.12.1.el7.x86_64 | grep FANOTIFY -- CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y --
6-3. ウイルス検知時に実行するスクリプトの設置
せっかくリアルタイムスキャン機能を導入するのですから、ウイルスを検知したときはすぐに通知してほしいですよね。
(すぐに通知しなくてもよいなら、リアルタイムスキャンではなくて、数時間おきの定期スキャンで十分なはずです。)
clamd では、ウイルスを検知したときに実行するコマンドを指定することができます。
ここでは、検知したときにメールで通知するスクリプト /root/bin/foundvirus.sh を用意し、ウイルス検知時に実行するよう設定します。
メールの件名には、サーバーのホスト名を含めます。
$CLAM_VIRUSEVENT_VIRUSNAME で検知したウイルス名
$CLAM_VIRUSEVENT_FILENAME で検知したファイル名
を取得できるので、それをメール本文に含めるのがポイントです。
※この機能により、通知だけではなく「検知したファイルを削除/移動する」といった処理も可能です。
※別途、サーバーからインターネットにメールを送信できるよう設定する必要があります。
# vim /root/bin/foundvirus.sh -- #!/bin/bash # ClamAVによるリアルタイムスキャンでウイルス検出時に # 実行するスクリプト foundvirus.sh # MAILTO=<通知先メールアドレス> export LANG=C # メッセージの生成 message="Virus Found: $CLAM_VIRUSEVENT_VIRUSNAME in $CLAM_VIRUSEVENT_FILENAME" # メッセージをメール送信 echo "$message"| mail -s "Virus Found in `hostname`" $MAILTO # EOF --
実行権限の付与と、文法チェックの実施。
# chmod 700 /root/bin/foundvirus.sh # /bin/bash -n /root/bin/foundvirus.sh
6-4. リアルタイムスキャンの設定
clamonacc 専用の設定ファイルは用意されていないため、clamd の設定ファイル /etc/clamd.d/scan.conf で設定します。
- VirusEvent で、ウイルス検知時にメール通知するスクリプトを指定する。
- OnAccessIncludePath で、オンラインスキャン対象ディレクトリを /var/www, /home に限定する。
- OnAccessExtraScanning yes で、ファイル作成、移動時のスキャンを実施する。これを有効にしないと、ファイルにアクセスがあったときのみのスキャンとなる。
- OnAccessExcludeRootUID yes で、rootユーザーによるプロセスはスキャンを実施しないようにする。そうしないと、clamdscanもしくはclamscanコマンドをrootユーザーで実行する際にも、コマンドによるスキャンアクセスにリアルタイムスキャンが反応してしまい、二重に検知・通知してしまう。
- OnAccessPrevention yes とすれば、ウイルス検知したファイルへのアクセスをブロックすることができる。ClamAVはウイルスデータベースのバグにより誤検知(false positive)することがあるので、今回は設定しない。
※リアルタイムスキャンの設定については、「6-8. リアルタイムスキャンの設定について補足」で補足します。
# vim /etc/clamd.d/scan.conf -- VirusEvent /root/bin/foundvirus.sh OnAccessIncludePath /var/www OnAccessIncludePath /home OnAccessExtraScanning yes OnAccessExcludeRootUID yes --
6-5. リアルタイムスキャンの起動
clamdを再起動して反映します。
# systemctl restart clamd@scan
clamonacc を起動しつつ自動起動設定を行い、正しく起動したことを確認します。
# systemctl enable --now clamonacc -- Created symlink from /etc/systemd/system/multi-user.target.wants/clamav-clamonacc.service to /usr/lib/systemd/system/clamav-clamonacc.service. -- # systemctl status clamonacc -l -- ● clamav-clamonacc.service - ClamAV On-Access Scanner Loaded: loaded (/usr/lib/systemd/system/clamav-clamonacc.service; disabled; vendor preset: disabled) Active: active (running) since 木 2021-04-08 12:14:52 JST; 5s ago Docs: man:clamonacc(8) man:clamd.conf(5) https://www.clamav.net/documents Main PID: 4188 (clamonacc) CGroup: /system.slice/clamav-clamonacc.service mq4188 /usr/sbin/clamonacc -F --config-file=/etc/clamd.d/scan.conf 4月 08 12:14:52 <hostname> systemd[1]: Started ClamAV On-Access Scanner. 4月 08 12:14:53 <hostname> clamonacc[4188]: ClamInotif: watching '/var/www' (and all sub-directories) 4月 08 12:14:53 <hostname> clamonacc[4188]: ClamInotif: watching '/home' (and all sub-directories) 4月 08 12:14:53 <hostname> clamonacc[4188]: ClamInotif: extra scanning on inotify events enabled --
/var/log/messages には、clamonacc のログが記録されており、監視対象ディレクトリとOnAccessExtraScanning が正しく認識されたことがわかります。
# less /var/log/messages -- Apr 8 12:14:53 <hostname> clamonacc: ClamInotif: watching '/var/www' (and all sub-directories) Apr 8 12:14:53 <hostname> clamonacc: ClamInotif: watching '/home' (and all sub-directories) Apr 8 12:14:53 <hostname> clamonacc: ClamInotif: extra scanning on inotify events enabled --
6-6. リアルタイムスキャンの動作確認
先ほどの検証用のウイルスファイルをコピーしてみて、正しく検知することを確認します。
# cp /var/www/html/eicar.com.txt /var/www/html/eicar.com-cp1.txt
ログを確認します。
コピー元ファイルへのアクセスと、コピー先ファイルの生成で、2件記録されました。
# less /var/log/clamd.scan -- Thu Apr 8 12:41:04 2021 -> instream(127.0.0.1@34448): Win.Test.EICAR_HDB-1 FOUND Thu Apr 8 12:41:04 2021 -> instream(127.0.0.1@34450): Win.Test.EICAR_HDB-1 FOUND --
/var/log/messages でも記録されたことを確認します。
# less /var/log/messages -- Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND --
通知メールを確認します。
2通届いていました。
Subject: Virus Found in <hostname> Virus Found: Win.Test.EICAR_HDB-1 in instream(127.0.0.1@34448)
Subject: Virus Found in <hostname> Virus Found: Win.Test.EICAR_HDB-1 in instream(127.0.0.1@34450)
残念ながら、メールでは、ファイル名の部分が「instream(127.0.0.1@xxxxx)」となっており、ウイルスと判定されたファイル名がわかりません。
これでは、通知の意味がありませんね。
これはおそらく、
- clamonacc は、ストリーミングでファイルの内容を clamd に送って検査を依頼し、ファイル名をclamdに通知しない。
- /etc/clamd.d/scan.conf の VirusEvent で指定したコマンドは、clamd が実行するため、ファイル名がわからない。
ということだと思います。
clamonacc がコマンドを実行できる VirusEvent に相当する設定があればよいのですが。
この辺は、clamonacc を clamd から分離した実装の不完全なところと思われますし、そもそも clamd と clamonacc が同じ設定ファイルを使用するのがおかしいような気がします。
今後の改善を期待します。
6-7. ウイルス検知時に実行するスクリプトの修正と動作確認
ウイルス検知時に、検知したファイル名がわからないと、通知の意味がありません。
先ほどの動作確認から、実は /var/log/messages には、検知したファイル名が記録されていることがわかります。
# less /var/log/messages -- Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND --
これを利用して、ウイルス検知時に実行するスクリプトでは、/var/log/messages を grep して、ファイル名を取得することにします。
# vim /root/bin/foundvirus.sh -- #!/bin/bash # ClamAVによるリアルタイムスキャンでウイルス検出時に # 実行するスクリプト foundvirus.sh # MAILTO=<通知先メールアドレス> export LANG=C # メッセージの生成 sleep 2 message=`grep clamonacc /var/log/messages | grep FOUND` # メッセージが空でなければメール送信 if [ -n "$message" ]; then echo "$message"| mail -s "Virus Found in `hostname`" $MAILTO fi # EOF --
メッセージ生成部分の
message=`grep clamonacc /var/log/messages | grep FOUND`
は、/var/log/messages のうち、clamonacc と FOUND を両方とも含む行をピックアップします。
その前の sleep 2 は、ログ書き出しが遅れるかもしれないことを考慮していますが、なくてもよいかもしれません。
この方法ですと、/var/log/messages に記録されている以前のウイルス検知ログも合わせてピックアップ&通知されるのでちょっとカッコ悪いのですが、通知されないよりは、されたほうがよいはずなので、よしとします。
また、以前のウイルス検知ログを再確認できるのも、悪いことではないでしょう。
これで、再度、検証用ウイルスファイルをコピーしてみて、正しく検知することを確認します。
# cp /var/www/html/eicar.com.txt /var/www/html/eicar.com-cp2.txt
通知メールを確認すると、1通届いていました。
Subject: Virus Found in <hostname> Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND Apr 8 12:56:51 <hostname> clamonacc: /var/www/html/eicar.com-cp2.txt: Win.Test.EICAR_HDB-1 FOUND
意図したとおりに動作し、通知メールで検知したファイル名がわかるようになりました。
ただし、先ほどはコピー元とコピー先の分の2通届きましたが、今回はなぜか1通です。
念のため、/var/log/messages を確認したところ、やはり1行しか記録されていませんでした。
コピー元ファイルは、すでに検知済みだからかもしれません。
# less /var/log/messages -- Apr 8 12:56:51 <hostname> clamonacc: /var/www/html/eicar.com-cp2.txt: Win.Test.EICAR_HDB-1 FOUND --
6-8. リアルタイムスキャンの設定について補足
/etc/clamd.d/scan.conf におけるリアルタイムスキャンの設定について補足します。
「ディスク全体 (/) をリアルタイムスキャン対象としたい」という要望もあるかと思いますが、現在の clamonacc の仕様ではむずかしいです。
まず、スキャン対象パスを指定する OnAccessIncludePath では、ルートディレクトリ (/) を指定できません。
スキャン対象マウントパスを指定する OnAccessMountPath では、ルートディレクトリ (/) を指定できますが、そうすると、ファイル作成、移動時のスキャンを実施する(OnAccessExtraScanning yes)設定が不可となり、正しく検知できなくなります。
代わりに、
OnAccessIncludePath /usr
OnAccessIncludePath /etc
OnAccessIncludePath /var
OnAccessIncludePath /home
OnAccessIncludePath /opt
のように、上位ディレクトリを列挙することで、ディスク全体のスキャンに近いことが実現できますが、広範囲のファイルシステムの変化を監視する分、システムに負荷がかかりそうです。
このあたりの設定、制限については、公式ドキュメントに説明があるのでそちらを参照してください。
・On-Access Scanning – ClamAV Documentation
https://www.clamav.net/documents/on-access-scanning
7. リアルタイムスキャンの検知漏れ問題と対策
- 7-1. リアルタイムスキャンの検知漏れ問題
- 7-2. サーバー全体のウイルススキャン方針
- 7-3. clamdscanによる定期スキャンの設定
- 7-4. ウイルス検知時に実行するスクリプトの修正
- 7-5. 定期スキャンとリアルタイムスキャンの動作確認
- 7-6. リアルタイムスキャンの動作確認
- 7-7. 定期スキャンのスケジュール実行設定と動作確認
- 7-8. 検証用ウイルスファイルの削除
7-1. リアルタイムスキャンの検知漏れ問題
ここまで設定したサーバー環境で、検証用ウイルスファイルを使用して、
- wgetコマンドで検証用ウイルスファイルをダウンロード
- 他のサーバーからscpコマンドで検証用ウイルスファイルをPUT
- サーバー上で検証用ウイルスファイルをコピー
など、いろいろ操作してみたのですが、ときどき、検知されないことがわかりました。
すでに検知済みのファイルパスとは別のディレクトリ、ファイル名としても、検知されないことがあります。
「メールで通知されない」のではなくて、ログにも記録されていません。
clamd, clamoncc の設定がよくないのかもしれませんし、サーバーの低スペックが影響しているのかもしれませんが、いろいろ調査、設定変更してみても、結局、この検知漏れの問題は解消できませんでした。
「全く検知しない」のではなく「検知したりしなかったりする」というのが困りますね。
7-2. サーバー全体のウイルススキャン方針
「リアルタイムスキャンの検知漏れ問題」の対策を考えます。
大前提として、「侵入したウイルスをできるだけすみやかに検知する」ということで、リアルタイムスキャンはそのまま採用しつつ、clamdscan コマンドでも定期的にスキャンを実施することにします。
リアルタイムスキャンの方針。
- ウイルスを検知したときは、即時、メールで通知する。
- スキャン対象ディレクトリは、Webディレクトリの /var/www と作業ユーザーがファイルをアップロードする可能性がある /home とする。
clamdscan コマンドによる定期スキャンの方針。
- 3時間おきなど、定期的にディスク全体 (/) のスキャンを実施する。
- スキャン終了後、ウイルス検知があったときはメールで通知する。
定期スキャンの対象ディレクトリをディスク全体として、リアルタイムスキャンで対象外としているディレクトリのスキャンを保管することにします。
7-3. clamdscanによる定期スキャンの設定
定期スキャン実行スクリプトを設置します。
メール本文には、ウイルス検知情報と clamdscan の実行結果を含めます。
メールの件名には、リアルタイムスキャンによるウイルス検知通知メールとの違いがわかるように「clamdscan」を含めます。
# vim /root/bin/scanvirus.sh -- #!/bin/bash # ClamAVによるウイルススキャンスクリプト scanvirus.sh # clamd が起動していることを前提とする。 # SCAN_DIR=/ SCAN_RESULT=/var/log/scanresult.txt MAILTO=<通知先メールアドレス> export LANG=C echo "===== Scan Virus =====" echo "`date` Scan Virus start" # ウイルススキャンの実行 /bin/clamdscan ${SCAN_DIR} 1> ${SCAN_RESULT} # ウイルスを検知したときのみ、メールで通知する if [ ! -z "$(grep FOUND$ ${SCAN_RESULT})" ]; then cat ${SCAN_RESULT} | mail -s "clamdscan: Virus Found in `hostname`" ${MAILTO} fi cat ${SCAN_RESULT} echo "`date` Scan Virus end" # EOF --
実行権限の付与と、文法チェックの実施。
# chmod 700 /root/bin/scanvirus.sh # /bin/sh -n /root/bin/scanvirus.sh
7-4. ウイルス検知時に実行するスクリプトの修正
/etc/clamd.d/scan.conf の VirusEvent で指定したコマンドは、リアルタイムスキャンだけではなく、clamdscan コマンドでウイルスを検知したときも実行されます。
先ほど、定期スキャン実行スクリプト内でメール通知の設定を行ったので、ウイルス検知時に実行するスクリプト /root/bin/foundvirus.sh では、リアルタイムスキャンの場合(= ファイル名部分が instream で始まる場合)のみメールを送信するよう工夫します。
※定期スキャン実行によるウイルス検知時も、リアルタイムスキャンによるウイルス検知時も VirusEvent で指定したコマンドによる通知で問題ない、ということであれば、この設定と、定期スキャン実行内のメール送信は不要です。その辺はお好みで。
# vim /root/bin/foundvirus.sh -- #!/bin/bash # ClamAVによるリアルタイムスキャンでウイルス検知時に # 実行するスクリプト foundvirus.sh # MAILTO=<通知先メールアドレス> export LANG=C # メッセージの生成 sleep 2 message=`grep clamonacc /var/log/messages | grep FOUND` # リアルタイムスキャンで、メッセージが空でなければメール送信 if [[ $CLAM_VIRUSEVENT_FILENAME =~ ^instream.* && -n "$message" ]]; then echo "$message"| mail -s "Virus Found in `hostname`" $MAILTO fi # EOF --
7-5. 定期スキャンとリアルタイムスキャンの動作確認
定期スキャン実行スクリプトを実行してみます。
# /root/bin/scanvirus.sh -- ===== Scan Virus ===== Thu Apr 8 17:34:43 JST 2021 Scan Virus start /var/www/html/eicar_com.zip: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com-cp2.txt: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND ----------- SCAN SUMMARY ----------- Infected files: 4 Time: 748.542 sec (12 m 28 s) Start Date: 2021:04:08 17:34:43 End Date: 2021:04:08 17:47:11 Thu Apr 8 17:47:11 JST 2021 Scan Virus end --
正しく検証用ウイルスファイルを検知し、メールで通知されたことを確認します。
VirusEvent で指定されている /root/bin/foundvirus.sh によるメール通知がないことも確認します。
Subject: clamdscan: Virus Found in <hostname> /var/www/html/eicar_com.zip: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com-cp2.txt: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND ----------- SCAN SUMMARY ----------- Infected files: 4 Time: 748.542 sec (12 m 28 s) Start Date: 2021:04:08 17:34:43 End Date: 2021:04:08 17:47:11
clamd のログも確認します。
# less /var/log/clamd.scan -- Thu Apr 8 17:40:39 2021 -> /var/www/html/eicar_com.zip: Win.Test.EICAR_HDB-1 FOUND Thu Apr 8 17:40:43 2021 -> /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND Thu Apr 8 17:40:45 2021 -> /var/www/html/eicar.com-cp2.txt: Win.Test.EICAR_HDB-1 FOUND Thu Apr 8 17:40:49 2021 -> /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND --
ここでもし、
「-> WARNING: Directory recursion limit reached, skipping <ディレクトリパス>」
のようなメッセージが出力されていれば、スキャンするディレクトリ階層数の上限(デフォルト15)に引っ掛かっているので増やします。
僕の環境では、snapd のディレクトリ /var/lib/snapd がこの制限にひっかかっていました。
# vim /etc/clamd.d/scan.conf -- # Maximum depth directories are scanned at. # Default: 15 MaxDirectoryRecursion 20 --
clamd を再起動して反映します。
# systemctl restart clamd@scan
再度定期スキャンを実行して、ディレクトリ階層のエラーが出ないことを確認します。
# /root/bin/scanvirus.sh # less /var/log/clamd.scan
7-6. リアルタイムスキャンの動作確認
リアルタイムスキャンのウイルス検知時実行スクリプトを修正したので、念のため、リアルタイムスキャンでウイルスを検知したときに、正しくメールで通知されたことを確認します。
検証用ウイルスファイルをコピーしてみます。
# cp /var/www/html/eicar.com.txt /var/www/html/eicar.com-cp3.txt
通知メールを確認します。
Subject: Virus Found in <hostname> Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND Apr 8 12:41:04 <hostname> clamonacc: /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND Apr 8 12:56:51 <hostname> clamonacc: /var/www/html/eicar.com-cp2.txt: Win.Test.EICAR_HDB-1 FOUND Apr 8 17:56:58 <hostname> clamonacc: /var/www/html/eicar.com-cp3.txt: Win.Test.EICAR_HDB-1 FOUND
/var/www/html/eicar.com-cp3.txt が検知されたことがわかります。
7-7. 定期スキャンのスケジュール実行設定と動作確認
3時間おきに定期スキャンを実行するよう、cron にエントリーを登録します。
実行ログは /var/log/scanvirus.log に保存します。
# crontab -e -- # Scan Virus 5 */3 * * * /root/bin/scanvirus.sh >> /var/log/scanvirus.log --
cron にエントリーを登録したときは、2,3分後に実行される時刻も設定して、必ず cron からの実行を確認しましょう。
コマンド単体では正しく動作するのに、環境変数などの問題でエラーとなることはよくあります。
また、ログファイルに正しく記録されたことも確認します。
# less /var/log/scanvirus.log -- ===== Scan Virus ===== Thu Apr 8 18:37:01 JST 2021 Scan Virus start /var/www/html/eicar_com.zip: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com-cp1.txt: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com-cp2.txt: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com-cp3.txt: Win.Test.EICAR_HDB-1 FOUND /var/www/html/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND ----------- SCAN SUMMARY ----------- Infected files: 5 Time: 748.768 sec (12 m 28 s) Start Date: 2021:04:08 18:37:01 End Date: 2021:04:08 18:49:30 Thu Apr 8 18:49:30 JST 2021 Scan Virus end --
ログローテート設定も忘れずに。
# vim /etc/logrotate.d/scanvirus.log -- /var/log/scanvirus.log { monthly rotate 12 compress missingok } --
7-8. 検証用ウイルスファイルの削除
最後に、検証用ウイルスファイルを削除します。
# rm /var/www/html/eicar*
8. まとめ
ClamAVによるリアルタイムスキャンの設定にトライしてみました。
僕が試した限りでは、検証用ウイルスファイルのダウンロード、アップロード、コピー時にウイルスをリアルタイムで検知しないことがあったため、リアルタイムスキャン とclamdscan コマンドによる定期スキャンを併用することにしてみました。
少し泥臭いのですが、
「リアルタイムスキャンは対象ディレクトリを絞り、定期スキャンでディスク全体のフルスキャンを実施」
という方針は悪くないと思います。
他の環境では全く問題なくリアルタイムスキャンが動作するのかもしれませんが、肝心なときに検知しないと意味がありませんので、いろいろなパターン、シナリオで検証することをおすすめします。
なお、今回の検証環境では、clamd がメモリを1GBぐらい使用していました。
ClamAVを使用する環境では、CPUを1コア、メモリは1~2GBぐらい余計に用意すると安心できそうです。
また、ディスク性能がよくないサーバーだと、スキャンに時間がかかりますし、スキャン中はスキャン以外の処理も極端に遅くなる可能性があるので注意しましょう。
ClamAVは無償で使用できるすばらしいソフトウェアですが、構築は簡単ではないですし、、たまに誤検知もあり、運用の手間がかかります。
予算が許すのであれば、TrendMicro Deep Security (Workload Security) などの有償ソフトウェアを導入したほうがよいと思います。
もちろん、有償ソフトウェアでも誤検知はあり得ますが。
(関連記事)
・ClamAVによるリアルタイムスキャンの設定(ClamAV 1.0版)
https://inaba-serverdesign.jp/blog/20231122/clamav-realtime-scan-v10.html
・ClamAVによる定期ウイルススキャンの設定
https://inaba-serverdesign.jp/blog/20170913/clamav_scan_virus_install.html
・ClamAVによる定期ウイルススキャンの運用における工夫
https://inaba-serverdesign.jp/blog/20170919/clamav_scan_virus_manage.html