背景
手軽にファイルアップロード機能を実装するときにCarrierwaveをよく使うんですが、
ひょんなことから、アップロードされたファイルのウイルスチェックをする必要がでてきたので、
チェックするまでの手順を、ClamAVのインストールとチェック方法を主にまとめます。
ClamAVインストール手順
- ClamAVインストール
- ウイルス更新の設定ファイル修正
- ウイルスのパターンファイル更新
- ウイルスチェックの設定ファイル修正
- デーモン起動
上記手順のコマンド
$ sudo su - $ yum remove -y clam* $ yum install -y clamav clamav-scanner-sysvinit clamav-update # 2. ウイルス更新の設定ファイル修正 $ sed -i -e "s/Example/#Example/" /etc/freshclam.conf $ sed -i -e "s:#DatabaseDirectory /var/lib/clamav:DatabaseDirectory /var/lib/clamav:" /etc/freshclam.conf $ sed -i -e "s:#UpdateLogFile /var/log/freshclam.log:UpdateLogFile /var/log/freshclam.log:" /etc/freshclam.conf $ sed -i -e "s/#DatabaseOwner clamupdate/DatabaseOwner clamupdate/" /etc/freshclam.conf # 3. ウイルスのパターンファイル更新 $ freshclam # 4. ウイルスチェックの設定ファイル修正 $ sed -i -e "s/Example/#Example/" /etc/clamd.d/scan.conf $ sed -i -e "s:#LocalSocket /var/run/clamd.scan/clamd.sock:LocalSocket /var/run/clamd.scan/clamd.sock:" /etc/clamd.d/scan.conf $ sed -i -e "s/#FixStaleSocket yes/FixStaleSocket yes/" /etc/clamd.d/scan.conf $ sed -i -e "s/#TCPSocket 3310/TCPSocket 3310/" /etc/clamd.d/scan.conf $ sed -i -e "s/#TCPAddr 127.0.0.1/TCPAddr 127.0.0.1/" /etc/clamd.d/scan.conf $ chown clamscan:clamscan /var/run/clamd.scan $ ln -s /etc/clamd.d/scan.conf /etc/clamd.conf # 5. デーモン起動ついでにchkconfig設定 $ /etc/rc.d/init.d/clamd.scan start $ /sbin/chkconfig clamd.scan on # デーモンのソケットはclamscanユーザにしかrwがないので、その他ユーザも実行できるように権限設定 $ chmod 775 /var/run/clamd.scan/
- ウイルスのパターンファイル更新については、定期的に実行したいので、cronで仕込む必要があると思います。
Rails プロダクションコードからの呼び出し(アップロードファイルのウイルスチェック)
- gem インストール
- 環境変数設定
- コード組み込み
1. gem インストール(Rails.rootにて) && 2. 環境変数設定
$ echo "gem 'clamav-client', require: 'clamav/client'" >> Gemfile $ bundle install $ echo 'export CLAMD_UNIX_SOCKET="/var/run/clamd.scan/clamd.sock"' >> ~/.bash_profile $ source ~/.bash_profile
- 環境変数設定 についてですが、clamav-clientは
CLAMD_UNIX_SOCKET
が設定されていると、そこをソケットパスとして参照しにいきます。
clamav-clientがデフォルトで参照するソケットパスが/var/run/clamav/clamd.ctl
であるため、yum でinstallしたClamAVの設定ファイルのソケットパスに合わせます。
3. コード組み込み
def upload_image client = ClamAV::Client.new io = StringIO.new(params["image"].tempfile.read) raise "detected virus" if client.execute(ClamAV::Commands::InstreamCommand.new(io)).virus_name.present? end
プロダクションコードでやるというよりは、ウイルスチェック専用のサーバにpostして結果だけ受け取るような仕組みにしたいですね。
参考サイト
github.com www.agilegroup.co.jp ClamAV on Amazon Linux - ぬぞうWiki