2021年10月29日
プログラミング
clambyを利用したウイルススキャン


目次
はじめに
Railsでアップロードファイルに対してウイルススキャンを行う方法をご紹介したいと思います。
今回はgem clambyを利用して、ファイルアップロード後に非同期処理でウイルススキャンを実行。
ウイルスが検出された場合はダミーファイルを差し替えるという流れです。
今回使用する環境
- Ruby: 2.7.4
- Ruby on Rails: 6.1.4
- clamby: 1.6.6
clamavの導入
clamav のインストール
gem clambyはclamavに依存しているため、まずは clamav をインストールします。
mac OS(homebrew利用)の場合
$ brew install clamav
Dockerを利用している場合
Dockerfile
RUN apt-get -y install clamav clamav-daemon && freshclam
gem clambyの導入
gem clamby のインストール
Gemfile
gem 'clamby'
$ bundle install
を実行
ウイルススキャンの処理を追加
アップローダーをマウントしているモデルにafter_saveを追加
user_image.rb
class UserImage < ApplicationRecord
attr_accessor :skip_scan_viruses
after_save -> { scan_viruses(:image) }, unless: :skip_scan_viruses
...
mount_uploader :image, ImageUploader
private
def scan_viruses(attribute)
ScanVirusesJob.perform_later(self, attribute)
end
end
ウイルススキャンをスキップすることを可能にするためattr_accessorにskip_scan_virusesを追加
ウイルススキャンのジョブを作成
syoryukenを利用していますが非同期処理の方法についてはスキップします。
ウイルススキャンを行い、検出された場合はダミーファイルと差し替えの上メールを送信します。
scan_viruses._job.rb
class ScanVirusesJob < ApplicationJob
def perform(record, attribute)
return if record.send(attribute).blank? || Rails.env.test?
return if Clamby.safe?(file_path(record, attribute))
record.send("#{attribute}=", File.open('app/assets/images/common/no_image.png'))
# 差し替え済みファイルなのでウイルススキャンはスキップ
record.skip_scan_viruses = true
record.save!(validate: false)
Admin::ScanVirusesMailer.virus_detected_email(record).deliver_now
if Rails.env.production?
SlackAlertNotification.call(title: "#{notify_env}: ウイルスを検出しました", text: slack_text(record))
end
end
private
def file_path(record, attribute)
# ファイルのpathを渡さなければいけないのでs3に保存しているproductionとそれ以外では分岐
if Rails.env.production?
# s3のファイルが上手く開ける状態かの確認
# carrierwaveの挙動の問題か、s3側の準備ができておらずnot foundとなってしまうことがあった
# sleep 2を噛ませたら上手く動いたので、200を確認してからウイルススキャンするよう修正
5.times do
response = Net::HTTP.get_response(URI.parse(record.send(attribute).url))
break if response.code == '200'
sleep 1
end
# URI.open(record.send(attribute).url).pathをそのままpathとして渡していた
# が、疑似ウイルスファイルでundefined method `path' for #発生
# 原因は10kb以下のファイルは Tempfile ではなく StringIOを返すRubyの仕様
# なので、強制的にTempfileを作成する
temp_file = Tempfile.new('file_')
temp_file.binmode
URI.open(record.send(attribute).url) { |file| temp_file.write(file.read) }
temp_file.rewind
temp_file.path
else
record.send(attribute).path
end
end
end
Point!
- ウイルスを検出してファイル差し替え後はウイルススキャンをスキップ
- S3のファイルが開ける状態かの確認
- 強制的にTempfileを作成する
挙動確認
擬似ウイルスファイルでの挙動確認
EICARのサイトで実害のないテスト用の擬似ウイルスファイルをダウンロードできます。
ダウンロードしたファイルをアップロードしてファイルが差し替えられることを確認します。
beanstalkへのclamavの導入
ebextensionsを利用してbeanstalkにclamavをインストール
今回はAWSのbeanstalkというサービスを利用しているためebextentionsディレクトリを利用してclamavのインストールと定義ファイルの更新を行います。
.ebextensions/01_settings.config
03_install_clamav:
command: "sudo amazon-linux-extras install -y epel && sudo yum install -y clamav clamav-update clamd"
04_freshcram:
command: "sudo freshclam" # ウイルス定義ファイルの更新
ウイルス定義ファイルの更新
cronを利用して定義ファイルの更新を更新を定時実行する
gem wheneverを利用しているためschedule.rbに追記します。
config/schedule.rb
every 1.day, at: '0:30 am' do
command "sudo freshclam"
end
まとめ
gem clamavを利用したウイルススキャンの実装をご紹介しました。
あまりウイルススキャンに関する記事は多くないので実装に少し苦労しましたが、こちらの記事が何かの助けになれば幸いです!
Rubyのお仕事に関するご相談
Bageleeの運営会社、palanではRubyに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
1
0
関連記事

2021年12月22日
RDBでセットメニューを表現する方法

2021年12月11日
Railsでツリー構造アプリを作ってみた

2021年12月9日
モデルに書いていたメソッドをPOLOに切り出してみた!

2021年12月7日
gem cancancanを使ってみた!

2021年11月15日
CustomCopで命名規則を作ってみた

2021年10月29日
clambyを利用したウイルススキャン
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへ
palanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー

Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。

やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。

はらた エンジニア
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています

こぼり ともろう エンジニア
サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。

ささい エンジニア
フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。

Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。

ゲスト bagelee

かっきー

まりな

suzuki
miyagi

ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。

いわもと
デザイナーをしています。 好きな食べ物はラーメンです。

taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。

kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya

aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。

Kainuma
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています

sugimoto
asama
ando
iwasawa ayane

yoko oshimo
異業界からやってきたデザイナー。palanARのUIをメインに担当してます。これからたくさん吸収していきます!