はじめに
僕がインターネット上で稼働するLinuxサーバーを構築する際、ウイルス対策として、オープンソースのClamAVを導入することが多くあります。
特に、不特定ユーザーからファイルをアップロードさせる機能を持つWebサーバーの場合は、悪意を持ったユーザーがウイルスファイルをアップする可能性がゼロではないので、何らかのウイルス対策が必須です。
ここでは、ClamAVを使用した定期ウイルススキャンの設定手順を記載します。
※定期スキャンの実運用におけるCPU・メモリリソース使用に関する工夫や、ウイルス検知時の通知および実際に検知したときの対処方法については、別の記事にまとめます。
※メール送受信時のスキャンについては、ここでは記載しません。
以下、ClamAVのインストールやスキャン実行設定は、rootユーザー(もしくはsudoによるroot権限)で実行します。
また、サーバーOSはCentOS 7を対象としますが、CentOS 6やAmazon Linuxでもほとんど変わらないと思います。
ClamAVについて
ClamAVは、オープンソースのアンチウイルスソフトウェアです。
・ClamAVNet (Official)
https://www.clamav.net/
Wikipediaによれば、もともとメールゲートウェイでE-Mailのウイルススキャンを行うことを主目的として開発されているそうですが、ディスクスキャンを行うこともできます。
PCで使用する一般的なアンチウイルスソフトと同様に、ウイルス定義ファイル(パターンファイル)を基に、ディスク上のファイルを検査し、そのファイルがウイルスかどうかを判定します。
ClamAVのウイルス定義ファイルは、インターネット上の配布サーバーで随時更新・配布されているため、最新のウイルス定義を取得できます。
ウイルスをリアルタイムで検知する常駐監視機能(オンアクセススキャン、リアルタイムスキャン)ももっていますが、ClamAVのオンアクセススキャンには、以下の短所があると考えます。
- ファイルの読み書きのたびにスキャン処理を行うため、各サーバープロセスの処理が遅くなる。また、常時、CPUおよびメモリリソースを使用する。
- (稲葉個人の見解ですが)商用アンチウイルスソフトに比べて、対応できるパターンが少なく、配布も少し遅い。また、ときどき誤検知もある。
このため、ClamAVを使用する際は、オンアクセスキャンではなく、Linuxスケジューラcronを利用した1日1回または2回などの定期スキャンが好ましいと思います。
また、オンアクセススキャンや、より精度の高いスキャンが必要な場合は、トレンドマイクロ社、シマンテック社等の商用アンチウイルスソフトのご利用をおすすめします。
(参考)
・Wikipedia: Clam Antivirus
https://ja.wikipedia.org/wiki/Clam_AntiVirus
・ClamAVでのfanotify有効化
https://oss.sios.com/guest-blog/clamav-fanotify
(2021.4.9追記)
ClamAVのリアルタイムスキャン設定ついては、以下にまとめました。
・ClamAVによるリアルタイムスキャンの設定
https://inaba-serverdesign.jp/blog/20210409/clamav-realtime-scan.html
(2021.4.9追記ここまで)
ClamAVのインストール
EPELリポジトリより、ClamAVをインストールします。
インストール手順
EPELリポジトリを追加していなければ、追加します。
# yum install epel-release ... インストール: epel-release.noarch 0:7-9
必要なときのみ明示的に指定してEPELリポジトリを使用するよう、デフォルトでは無効化します。
# vi /etc/yum.repos.d/epel.repo -- enabled=0 // 1から0に変更 --
ClamAV本体(clamavパッケージ)と、ウイルス定義ファイルおよび定義更新機能(clamav-updateパッケージ)をインストールします。
# yum --enablerepo=epel install clamav clamav-update ... インストール: clamav.x86_64 0:0.99.2-8.el7 clamav-update.x86_64 0:0.99.2-8.el7 依存性関連をインストールしました: clamav-data.noarch 0:0.99.2-8.el7 clamav-filesystem.noarch 0:0.99.2-8.el7 clamav-lib.x86_64 0:0.99.2-8.el7
ちなみに、CentOS 6ではパッケージ名が少し違っていて、clamavとclamav-dbパッケージをインストールします。
# yum --enablerepo=epel install clamav clamav-db ... Installed: clamav.x86_64 0:0.99.2-2.el6 clamav-db.x86_64 0:0.99.2-2.el6
なお、今回はClamAVのデーモン化は行わず、clamdscanコマンドは使用しないので、clamav-scanner, clamav-serverパッケージ(CentOS 6ではclamdパッケージ)はインストールしません。
「ClamAVをデーモン化する、しない」については、後ほど説明します。
ウイルス定義更新設定
ウイルス定義の更新コマンドは /usr/bin/freshclam で、その設定ファイルは、/etc/freshclam.conf ですので、このファイルを開いて確認、変更します。
Example 行がコメントアウトされていることを確認します。
また、ウイルス定義配布サーバーの設定である DatabaseMirror 行で、日本のミラーサーバーを追加登録します。
日本のミラーサーバーからの取得に失敗することもあるので、デフォルトの database.clamav.net も残しておきます。
# vi /etc/freshclam.conf -- #Example // コメントアウトされていることを確認 ... # Uncomment the following line and replace XY with your country # code. See http://www.iana.org/cctld/cctld-whois.htm for the full list. # You can use db.XY.ipv6.clamav.net for IPv6 connections. #DatabaseMirror db.XY.clamav.net DatabaseMirror db.jp.clamav.net // 日本のDBミラーサイトをデフォルトの前に追記 # database.clamav.net is a round-robin record which points to our most # reliable mirrors. It's used as a fall back in case db.XY.clamav.net is # not working. DO NOT TOUCH the following line unless you know what you # are doing. DatabaseMirror database.clamav.net // これはそのまま残す ... --
ウイルス定義の更新
freshclamコマンドで、ウイルス定義を最新バージョンに更新します。
サーバースペックやネットワーク通信速度にもよりますが、初回実行時は数分かかります。
(/etc/freshclam.conf で日本のDBミラーサイトを設定しないと、もっとかかります)
# freshclam ClamAV update process started at Wed Sep 13 15:52:40 2017 Downloading main-58.cdiff [100%] main.cld updated (version: 58, sigs: 4566249, f-level: 60, builder: sigmgr) WARNING: getfile: daily-21724.cdiff not found on db.jp.clamav.net (IP: 203.178.137.175) WARNING: getpatch: Can't download daily-21724.cdiff from db.jp.clamav.net Trying host db.jp.clamav.net (124.35.85.83)... WARNING: getfile: daily-21724.cdiff not found on db.jp.clamav.net (IP: 124.35.85.83) WARNING: getpatch: Can't download daily-21724.cdiff from db.jp.clamav.net Trying host db.jp.clamav.net (27.96.54.66)... WARNING: getfile: daily-21724.cdiff not found on db.jp.clamav.net (IP: 27.96.54.66) WARNING: getpatch: Can't download daily-21724.cdiff from db.jp.clamav.net WARNING: Incremental update failed, trying to download daily.cvd Downloading daily.cvd [100%] daily.cvd updated (version: 23821, sigs: 1742928, f-level: 63, builder: neo) Downloading bytecode-279.cdiff [100%] Downloading bytecode-280.cdiff [100%] (省略) Downloading bytecode-311.cdiff [100%] bytecode.cld updated (version: 311, sigs: 74, f-level: 63, builder: neo) Database updated (6309251 signatures) from db.jp.clamav.net (IP: 218.44.253.75)
ウイルス定義ファイルは /var/lib/clamav に保存されています。
# ls -l /var/lib/clamav/ -rw-r--r-- 1 clamupdate clamupdate 766464 9月 13 15:57 bytecode.cld -rw-r--r-- 1 clamupdate clamupdate 41932290 9月 13 15:56 daily.cvd -rw-r--r-- 1 clamupdate clamupdate 307499008 9月 13 15:52 main.cld -rw------- 1 clamupdate clamupdate 208 9月 13 15:57 mirrors.dat
スキャンのテスト
ためしに、ディレクトリ /var に対してウイルススキャンを実施してみます。
スキャンは、clamscanコマンドを使用します。
--infected オプションで、ウイルス検知したファイルの情報のみ出力します。
--recursive オプションで、指定したディレクトリ配下を再帰的にスキャンします。
なお、--remove オプションを指定しない限り、ウイルス検知したファイルの自動削除は行いません。
# clamscan --infected --recursive /var LibClamAV Warning: cli_scanxz: decompress file size exceeds limits - only scanning 26755072 bytes ----------- SCAN SUMMARY ----------- Known viruses: 6303476 Engine version: 0.99.2 Scanned directories: 159 Scanned files: 218 Infected files: 0 Data scanned: 55.01 MB Data read: 487.43 MB (ratio 0.11:1) Time: 15.436 sec (0 m 15 s)
スキャン結果が「SCAN SUMMARY」として出力されます。
それぞれ、以下を意味します。
- Known viruses: ウイルス定義数
- Engine version: ClamAVのバージョン
- Scanned directories: スキャンしたディレクトリ数
- Scanned files: スキャンしたファイル数
- Infected files: ウイルス検知数
- Data scanned: スキャンしたファイルサイズの合計
- Data read: スキャン走査したデータサイズ(圧縮データの展開分含む?)の合計
- Time: スキャン処理時間
なお、「LibClamAV Warning: cli_scanxz: decompress file size exceeds limits – only scanning 26755072 bytes」というWarningメッセージは、スキャン対象のファイルサイズの上限がデフォルトで25MB程度となっており、これより大きなサイズのファイルはスキップしてスキャンしないことを意味します。
「スキャン対象のファイルサイズ上限値」は、--max-filesizeオプションで指定できます。
上限値をどうするかは、そのサーバーでどれぐらいのサイズのファイルが存在するかによりますが、今回は200MBとします。
同様に、「ファイルの先頭からどれだけ走査するか」は、--max-scansizeオプションで指定します。
これも、--max-filesizeオプションと合わせて200MBとします。
--max-filesize=200M --max-scansize=200M
これらのオプションとデフォルト値は、man clamscanで確認できます。
次に、無害のテスト用ウイルスファイルを設置してスキャンを実施し、ウイルスと検知することを確認します。
# wget http://www.eicar.org/download/eicar.com.txt -O /var/eicar.com.txt # wget http://www.eicar.org/download/eicar_com.zip -O /var/eicar_com.zip # clamscan --max-filesize=200M --max-scansize=200M --infected --recursive /var /var/eicar.com.txt: Eicar-Test-Signature FOUND /var/eicar_com.zip: Eicar-Test-Signature FOUND ----------- SCAN SUMMARY ----------- Known viruses: 6303476 Engine version: 0.99.2 Scanned directories: 162 Scanned files: 238 Infected files: 2 Data scanned: 202.16 MB Data read: 489.11 MB (ratio 0.41:1) Time: 24.318 sec (0 m 24 s)
「/var/www/eicar.com.txt: Eicar-Test-Signature FOUND」のように、ウイルスと検知したファイル名と、ウイルスの種類が出力されます。
また、「Infected files: 2」のように、ウイルスを2件検知したことがわかります。
テストが終わったら、テスト用ウイルスファイルを削除します。
# rm /var/eicar*
定期スキャンの設定
定期スキャンの仕様
今回設定する定期スキャンの仕様は以下のとおりとします。
- 1日一回Webアクセスの少ない早朝の時間帯にサーバーディスクのフルスキャンを行う。
- ウイルススキャン実施直前に、ClamAVのプログラム自身とウイルス定義の更新を行う。
- スキャン対象から除外するディレクトリ、ファイルをリストファイルで指定する。
- ウイルスを検知した場合は、該当ファイルの自動削除は行わず、ウイルス検査結果および該当ファイル名を、あらかじめ指定したメールアドレスに通知する。(*1)
- ウイルスを検知しなかった場合は、スキャン結果をログに記録するのみ。
(*1)通常の無害なファイルをウイルスとみなす誤検知(いわゆるフォールス・ポジティブ)の可能性もあるため、該当ファイルの自動削除は行いません。
ClamAVをデーモン化する?しない?
ClamAVでは、ウイルススキャンを実行するコマンドとして、clamscanとclamdscanの2種類が用意されています。
clamscanコマンドは、実行するたびにウイルス定義を読み込んでから、スキャンを実行します。
ウイルス定義ファイルは全部で500MB~700MBぐらいありますので、ファイルの読み込みには数秒かかります。
この方法だと、例えばメール送受信時のウイルスチェックなど、頻繁にスキャンが発生するとき、毎回数秒の時間がかかってしまい、メール送受信が遅延する可能性があります。
大きなファイルの読み込みを頻繁に行いますから、CPU負荷とディスクIO負荷もかかります。
このように頻繁にウイルススキャンを実行するような用途向けに、ClamAVをデーモン化する機能が用意されています。
clamdというサービスを起動すると、起動時に一度だけウイルス定義を読み込み、デーモンとして常駐します。
(clamscanコマンドではなく)clamdscanコマンドを使用すると、clamdと通信してスキャンを実行するため、毎回ウイルス定義を読み込む必要がなく、その結果、スキャンコマンドの実行時間が短くなります。
サーバーの運用において、ClamAVをデーモン化するか、しないか、については、サーバーのメモリ容量と、ウイルススキャンの実行時間で決めるとよいでしょう。
ClamAVのメモリの使用量については、おそらくウイルス定義ファイルのサイズに比例します。
僕が試した限り、
- デーモン化したとき: clamdデーモンプロセスがメモリを500~700MBぐらい使用する。
- デーモン化しないとき: clamscanコマンドの実行プロセスがメモリを500~700MBぐらい使用する。
という感じで、メモリ使用量はどちらも同じぐらいです。
以下のように、psコマンドでuオプションを使用した場合の6カラム目(RSS)が、そのプロセスが使用しているメモリサイズ(KB)となりますが、clamdもclamscanも、500MB強です。
# ps aux | grep clamd | grep -v grep clamscan 2546 14.9 50.7 785840 514936 ? Ssl 16:56 0:29 clamd.scan -c /etc/clamd.d/scan.conf --pid /var/run/clamd.scan/clamd.pid
# ps aux | grep clamscan | grep -v grep root 2534 93.5 51.9 636312 527648 pts/1 Dl+ 16:55 0:10 clamscan --infected --recursive /
Linuxサーバーのディスク全体に対するウイルススキャンの実行時間は、ファイル数やファイルサイズによりますが、ふつうは10分から30分程度、ファイルサーバーなどファイル数が多い場合だと、1時間から2時間程度だと思います。
メモリが潤沢にあるサーバーであれば、デーモン化してもしなくてもよいのですが、デーモン化するとClamAVが常時500MB~700MB程度メモリを使用するので、メモリが2GB以下の場合、アプリケーションやデータベースなど、そのサーバー本来の機能が使用できるメモリが少なくなってしまいます。
ですので、メモリが少なめのサーバーで、ウイルススキャンの実行頻度が1日1回または2回など少ない場合は、デーモン化せずに、clamscanコマンドを使用したほうがよいでしょう。
なお、「デーモン化してclamdを起動しているのに、(clamdscanコマンドではなく)clamscanコマンドでスキャンを実行する」という運用は、二重にメモリを使用して無駄ですので注意しましょう。
スキャン実行スクリプトの設置
スキャン実行スクリプトを設置します。
なお、このスクリプトの処理の流れや、スキャン除外リストの追加、ウイルス検知時のメール通知など、以下の記事を参考にさせていただきつつアレンジしました。
・アンチウイルスソフト導入(Clam AntiVirus)
https://centossrv.com/clamav-centos7.shtml
まず、スキャン実行スクリプト内で参照する、スキャン除外リストファイル /root/bin/scanvirus_exclude_list.txt を作成します。
1行に1件ずつ記載し、ディレクトリの場合は、末尾を /(スラッシュ)とします。
初期設定としては、実ファイルではないためスキャンしても意味がない /sys/, /proc/, /dev/ を除外します。
※運用開始後、必要に応じて追記します。
# vi /root/bin/scanvirus_exclude_list.txt -- /sys/ /proc/ /dev/ --
続いて、スキャン実行スクリプト /root/bin/scanvirus.sh を設置します。
# vi /root/bin/scanvirus.sh -- #!/bin/sh # ClamAVによるウイルススキャンスクリプト scanvirus.sh # ウイルススキャンを実行し、ウイルスを検知したときのみ、 # 指定した宛先にアラートメールを送信する。 # 誤検知もあり得るため、検知しても駆除(削除)は実施しない。 # # スキャンの実行前には、ClamAVプログラムおよびウイルス定義を # アップデートする。 # # スキャンの除外対象ディレクトリ、ファイルは、${EXCLUDE_LIST_FILE} # ファイルに1行ずつ記載すること。ディレクトリの末尾には、/ をつける。 # EXCLUDE_LIST_FILE=/root/bin/scanvirus_exclude_list.txt LOGFILE=/var/log/scanvirus.log SCAN_RESULT=/var/log/scanresult.txt MAX_FILESIZE=200M MAX_SCANSIZE=200M MAILTO=xxx@example.com export LANG=C echo "===== Scan Virus =====" >> ${LOGFILE} echo "`date` Scan Virus start" >> ${LOGFILE} # 1. ClamAVプログラムのアップデート echo "`date` Update ClamAV start" >> ${LOGFILE} yum -y --enablerepo=epel update clamav 1>> ${LOGFILE} 2>&1 echo "`date` Update ClamAV end" >> ${LOGFILE} # 2. ウイルス定義の更新 echo "`date` Update Database start" >> ${LOGFILE} /usr/bin/freshclam 1>> ${LOGFILE} 2>&1 echo "`date` Update Database end" >> ${LOGFILE} # 3. ウイルススキャンの実施 echo "`date` Do Scan Virus start" >> ${LOGFILE} ## スキャン除外リストの展開 while read LINE do if [ $(echo "${LINE}"|grep \/$) ]; then i=`echo ${LINE}|sed -e 's/^\([^ ]*\)\/$/\1/p' -e d` excludeopt="${excludeopt} --exclude-dir=^${LINE}" else excludeopt="${excludeopt} --exclude=^${LINE}" fi done < ${EXCLUDE_LIST_FILE} echo "excludeopt: ${excludeopt}" >> ${LOGFILE} ## ウイルススキャンの実行 /usr/bin/clamscan \ --max-filesize=${MAX_FILESIZE} --max-scansize=${MAX_SCANSIZE} \ --infected --recursive ${excludeopt} / 1> ${SCAN_RESULT} 2>> ${LOGFILE} ## ウイルスを検知したときのみ、アラートメールで通知する [ ! -z "$(grep FOUND$ ${SCAN_RESULT})" ] && \ cat ${SCAN_RESULT} | mail -s "Virus Found in `hostname`" ${MAILTO} cat ${SCAN_RESULT} >> ${LOGFILE} echo "`date` Do Scan Virus end" >> ${LOGFILE} echo "`date` Scan Virus complete" >> ${LOGFILE} # EOF --
スクリプトの内容について補足します。
「1. ClamAVプログラムのアップデート」
は、yumコマンドでclamavパッケージのアップデートを試みます。
「2. ウイルス定義の更新」
は、スキャン実行の直前に、freshclamコマンドでウイルス定義を最新のものに更新します。
「3. ウイルススキャンの実施」
では、まず、スキャン除外リストファイルを展開して、clamscanコマンドの –exclude-dir オプション(ディレクトリの場合)または –exclude オプション部分の引数を生成します。
続いて、clamscanコマンドでディスク全体(/, ルートディレクトリ以下)のスキャンを実行し、標準出力(=スキャン結果)を /var/log/scanresult.txt に出力します。
スキャン結果に「FOUND」の文字列があれば、ウイルス検知が1件以上存在することを意味するので、その場合は、スキャン結果を MAILTO で指定したメールアドレス宛てに送信します。
スキャン実行時に –remove オプションをつけていないので、ウイルス検知したファイルの自動削除は行いません。
なお、サーバーからインターネットにメールを送信するには、Postfixやsendmail等によるメール送信設定が必要です。
(参考)
・Postfixによるメール送信設定
https://inaba-serverdesign.jp/blog/20160620/postfix_send_mail.html
また、ここではメール送信にmailコマンドを使用していますので、必要に応じてmailxパッケージをインストールしてください。
# yum install mailx
スクリプトに実行権限を付与します。
# chmod 700 /root/bin/scanvirus.sh
ログローテート設定
スクリプト内の各処理開始、終了時刻や、コマンド実行時の標準出力はログファイル /var/log/scanvirus.log に出力します。
このログファイルのローテート設定を行います。
以下は、月次ローテート、圧縮して24世代保存する。
# vi /etc/logrotate.d/scanvirus -- /var/log/scanvirus.log { monthly rotate 24 compress missingok } --
スキャン実行スクリプトのテスト
スキャン実行スクリプトを実行してみます。
# /root/bin/scanvirus.sh
実行中のログやスキャン結果を確認します。
# tail -f /var/log/scanvirus.log ===== Scan Virus ===== Wed Sep 13 16:34:28 JST 2017 Scan Virus start Wed Sep 13 16:34:28 JST 2017 Update ClamAV start Loaded plugins: fastestmirror Loading mirror speeds from cached hostfile * base: ftp.iij.ad.jp * epel: s3-mirror-ap-northeast-1.fedoraproject.org * extras: ftp.iij.ad.jp * updates: ftp.iij.ad.jp No packages marked for update Wed Sep 13 16:34:29 JST 2017 Update ClamAV end Wed Sep 13 16:34:29 JST 2017 Update Database start ClamAV update process started at Wed Sep 13 16:34:29 2017 main.cld is up to date (version: 58, sigs: 4566249, f-level: 60, builder: sigmgr) daily.cvd is up to date (version: 23821, sigs: 1742928, f-level: 63, builder: neo) bytecode.cld is up to date (version: 311, sigs: 74, f-level: 63, builder: neo) Wed Sep 13 16:34:29 JST 2017 Update Database end Wed Sep 13 16:34:29 JST 2017 Do Scan Virus start excludeopt: --exclude-dir=^/sys/ --exclude-dir=^/proc/ --exclude-dir=^/dev/ ----------- SCAN SUMMARY ----------- Known viruses: 6303545 Engine version: 0.99.2 Scanned directories: 4009 Scanned files: 24102 Infected files: 0 Data scanned: 2106.60 MB Data read: 3622.62 MB (ratio 0.58:1) Time: 181.009 sec (3 m 1 s) Wed Sep 13 16:37:30 JST 2017 Do Scan Virus end Wed Sep 13 16:37:30 JST 2017 Scan Virus complete
続いて、無害のテスト用ウイルスファイルを設置したうえで、スキャンスクリプトを実行します。
ウイルスを検知し、スキャン結果が指定した宛先にメールが送信されることを確認します。
# wget http://www.eicar.org/download/eicar.com.txt -O /eicar.com.txt # wget http://www.eicar.org/download/eicar_com.zip -O /eicar_com.zip # /root/bin/scanvirus.sh
メールが正しく届くことと、メールのサブジェクト、本文を確認します。
メールのサブジェクトは、「Virus Found in <ホスト名>」。
メール本文は以下のような感じです。
/eicar.com.txt: Eicar-Test-Signature FOUND /eicar_com.zip: Eicar-Test-Signature FOUND ----------- SCAN SUMMARY ----------- Known viruses: 6303545 Engine version: 0.99.2 Scanned directories: 4009 Scanned files: 24102 Infected files: 2 Data scanned: 2106.61 MB Data read: 3622.62 MB (ratio 0.58:1) Time: 177.938 sec (2 m 57 s)
テストが終わったら、テスト用ウイルスファイルを削除します。
# rm /eicar*
スキャンの定期実行設定
スキャン実行スクリプトを定期実行するよう、cronエントリーを登録します。
rootユーザーで実行するため、rootユーザーのcronに登録します。
スキャン処理はサーバーに大きな負荷をかける処理ですので、サーバー本来の機能に影響が少ない時間帯に実施するのがよいでしょう。
以下は、毎日5時に実行する場合の設定です。
# crontab -e -- # Scan Virus 0 5 * * * /root/bin/scanvirus.sh > /dev/null --
念のため、ためしに時刻を3分後などに設定して、実際にcronからスクリプトを実行させてみるとよいでしょう。
以上で、定期ウイルススキャンの設定はひとまず完了となります。
設定後数日は、定期スキャン全体に要する時間、サーバーのCPU負荷や実メモリ使用量、スワップ領域の使用量の増加などを注意深く確認しましょう。
まとめ
オープンソースのアンチウイルスソフトClamAVを使用した、CentOS 7サーバーの定期ウイルススキャンの設定方法を記載しました。
次の記事では、定期ウイルススキャンの実運用において、CPU・メモリリソース使用に関する工夫や、ウイルス検知時の通知および実際に検知したときの対処方法について記載します。