GithubHelp home page GithubHelp logo

clamby's Introduction

Clamby Logo

GemVersion Ruby CI

This gem depends on the clamscan and freshclam daemons to be installed already.

If you have a file upload on your site and you do not scan the files for viruses then you not only compromise your software, but also the users of the software and their files. This gem's function is to simply scan a given file.

Usage

Drifting Ruby Screencast

Be sure to check the CHANGELOG as recent changes may affect functionality.

Just add gem 'clamby' to your Gemfile and run bundle install.

You can use two methods to scan a file for a virus:

If you use safe? to scan a file, it will return true if no viruses were found, false if a virus was found, and nil if there was a problem finding the file or if there was a problem using clamscan

Clamby.safe?(path_to_file)

If you use virus? to scan a file, it will return true if a virus was found, false if no virus was found, and nil if there was a problem finding the file or if there was a problem using clamscan

Clamby.virus?(path_to_file)

In your model with the uploader, you can add the scanner to a before method to scan the file. When a file is scanned, a successful scan will return true. An unsuccessful scan will return false. A scan may be unsuccessful for a number of reasons; clamscan could not be found, clamscan returned a virus, or the file which you were trying to scan could not be found.

  before_create :scan_for_viruses

  private

  def scan_for_viruses
      path = self.attribute.url
      Clamby.safe?(path)
  end

Updating Definitions

I have done little testing with updating definitions online. However, there is a method that you can call Clamby.update which will execute freshclam. It is recommended that you follow the instructions below to ensure that this is done automatically on a daily/weekly basis.

Viruses Detected

It's good to note that Clamby will not by default delete files which had a virus. Instead, this is left to you to decide what should occur with that file. Below is an example where if a scan came back false, the file would be deleted.

  before_create :scan_for_viruses

  private

  def scan_for_viruses
      path = self.attribute.path
      scan_result = Clamby.safe?(path)
      if scan_result
        return true
      else
        File.delete(path)
        return false
      end
  end

with ActiveStorage

With ActiveStorage, you don't have access to the file through normal methods, so you'll have to access the file through the attachment_changes.

class User < ApplicationRecord
  has_one_attached :avatar
  before_save :scan_for_viruses

  private

  def scan_for_viruses
    return unless self.attachment_changes['avatar']

    path = self.attachment_changes['avatar'].attachable.tempfile.path
    Clamby.safe?(path)
  end
end

Configuration

Configuration is rather limited right now. You can exclude the check if clamscan exists which will save a bunch of time for scanning your files. However, for development purposes, your machine may not have clamscan installed and you may wonder why it's not working properly. This is just to give you a reminder to install clamscan on your development machine and production machine. You can add the following to an initializer, for example config/initializers/clamby.rb:

    Clamby.configure({
      :check => false,
      :daemonize => false,
      :config_file => nil,
      :error_clamscan_missing => true,
      :error_clamscan_client_error => false,
      :error_file_missing => true,
      :error_file_virus => false,
      :fdpass => false,
      :stream => false,
      :reload => false,
      :output_level => 'medium', # one of 'off', 'low', 'medium', 'high'
      :executable_path_clamscan => 'clamscan',
      :executable_path_clamdscan => 'clamdscan',
      :executable_path_freshclam => 'freshclam',
    })

Daemonize

I highly recommend using the daemonize set to true. This will allow for clamscan to remain in memory and will not have to load for each virus scan. It will save several seconds per request.

To specify a config file for clamdscan to use, you can set config_file with the relevant path. See this page for more information about the config file.

Error suppression

There has been added additional functionality where you can override exceptions. If you set the exceptions below to false, then there will not be a hard exception generated. Instead, it will post to your log that an error had occured. By default each one of these configuration options are set to true. You may want to set these to false in your production environment.

Pass file descriptor permissions to clamd

Setting the fdpass configuration option to true will pass the --fdpass option to clamscan. This might be useful if you are encountering permissions problems between clamscan and files being created by your application. From the clamscan man page:

--fdpass : Pass the file descriptor permissions to clamd. This is useful if clamd is running as a different user as it is faster than streaming the file to clamd. Only available if connected to clamd via local(unix) socket.

Force streaming files to clamd

Setting the stream configuration option will stream the file to the daemon. This may be useful for forcing streaming as a test for local development. Only works when also specifying daemonize. From the clamdscan man page:

--stream : Forces file streaming to clamd. This is generally not needed as clamdscan detects automatically if streaming is required. This option only exists for debugging and testing purposes, in all other cases --fdpass is preferred.

Force streaming files to clamd

Setting the reload configuration option to true will pass the --reload option to the daemon. Only works when also specifying daemonize. From the clamdscan man page:

--reload : Request clamd to reload virus database.

Output levels

  • off: suppress all output
  • low: show errors, but nothing else
  • medium: show errors and briefly what happened (default)
  • high: as verbose as possible

Executable paths

Setting any of the executable paths makes Clamby to use those paths instead of the defaults for the system calls. The default configuration for these should be perfectly fine for most use cases but it may be required to configure custom paths in case ClamAV is manually installed to a custom location.

In order to configure the paths, use the following configuration options:

  • executable_path_clamscan: defines the executable path for the clamscan executable, defaults to clamscan
  • executable_path_clamdscan: defines the executable path for the clamdscan executable, defaults to clamdscan
  • executable_path_freshclam: defines the executable path for the freshclam executable, defaults to freshclam

Dependencies

Ubuntu

sudo apt-get install clamav clamav-daemon

Note, clamav-daemon is optional but recommended. It's needed if you wish to run ClamAV in daemon mode.

macOS

brew install clamav

Auto Update*

To update the virus database, open a terminal and enter the following command:

sudo freshclam

To automate this update you can set up a cron job. I'll show how to update the virus database every day at 8:57 PM.

You need to modify the crontab for the root user.

sudo crontab -e

This opens the root crontab file in a text editor. Add the following line

57 08 * * * sudo freshclam

Contributors

LICENSE

Copyright (c) 2016 kobaltz

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

ClamAV is licensed under GNU GPL. The ClamAV software is NOT distributed nor modified with this gem.

clamby's People

Contributors

ahukkanen avatar andreasronnqvistc avatar bennacer860 avatar bess avatar broder avatar codezomb avatar emilong avatar joshuapinter avatar kironono avatar kobaltz avatar laykou avatar skarlcf avatar szajbus avatar tilsammans avatar zealot128 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

clamby's Issues

False positives when clamdscan daemon is not running

Exceptions::VirusDetected errors are raised when attempting to run a daemonized scan while the daemon is not running. In this case, underlying scanner reports an error like:

ERROR: Could not lookup (...): Servname not supported for ai_socktype

Rather than reporting the error, the #virus? method reports a virus found VirusDetected. The README leads me to believe it should return nil:

If you use virus? to scan a file, it will return true if a virus was found, false if no virus was found, and nil if there was a problem finding the file or if there was a problem using clamscan

Is this the intended interface? I see a similar issue discussed in #9 but the false positive failure state seems taken for granted, there.

I see this behavior with the following configuration:

  Clamby.configure(                                                                                                                                                                                                                                                              
    check:  false,                                                                                                                                                                                                                      
    daemonize: true,                                                                                                                                                                                                                                                             
    error_clamscan_missing: true,                                                                                                                                                                                                                                                
    error_file_missing: true,                                                                                                                                                                                                                                                    
    error_file_virus: true,                                                                                                                                                                                                                                                      
    fdpass: true                                                                                                                                                                                                                                                                 
  ) 

NameError (uninitialized constant Client::Clamby)

Hello,

I am trying to scan before uploading a file, getting NameError (uninitialized constant Client::Clamby) error. I followed the same steps defined in the REDME file. It's working on my local machine(ubuntu 18.04) but not on production server(ubuntu 14.04)

Please help.
Thanks.

File name with `(` and `)` return a false and does not scan

Hello,

When calling Clamby.safe? with a file path which include the character ( or ) (my filename is filename(2021-10-01).pdf, it returns an error and does not test the file:

> Clamby.safe?(path)
ClamAV 0.103.2/26364/Thu Nov 25 09:20:31 2021
sh: 1: Syntax error: "(" unexpected
 => false

I am running it on a Ubuntu 20 server

Thank you!

Clamby detect all the files as virus and not safe!

Guys, I'm using Rails 4 with Ruby version 2.2.10 , I added the gem 'clamby' to my Gemfile
then installed the gem by used the command bundle install
and added the below configurations to my file /config/initializers/clamby.rb :

Clamby.configure({
  :check => false,
  :daemonize => true,
  :config_file => nil,
  :error_clamscan_missing => false,
  :error_clamscan_client_error => false,
  :error_file_missing => false,
  :error_file_virus => false,
  :fdpass => true,
  :stream => true,
  :output_level => 'medium', # one of 'off', 'low', 'medium', 'high'
  :executable_path_clamscan => 'clamscan',
  :executable_path_clamdscan => 'clamdscan',
  :executable_path_freshclam => 'freshclam'
})

but actually my application is dockerized so I defined clamav in my docker-compose.yml file as service

services:
  clamav:
    image: mkodockx/docker-clamav:alpine
    environment:
      MODE: av
    ulimits:
      stack: 1048576
    volumes:
      - conf:/etc/clamav
      - data:/var/lib/clamav

  freshclam:
    image: aschepis/freshclam
    environment:
      MODE: updater
    volumes:
      - conf:/etc/clamav
      - data:/var/lib/clamav

  clamav_milter:
    image: bastienf/clamav-milter
    environment:
      MODE: milter
    container_name: clamav_milter_1
    volumes:
      - conf:/etc/clamav

  clamav_daemon:
    image: oh22/clamav-daemon
    container_name: clamav_daemon_1
    volumes:
      - conf:/etc/clamav
app:
  links:
      - clamav:clamav
  depends_on:
      - clamav
      - freshclam
      - clamav_milter
      - clamav_daemon
volumes:
  conf:
  data:

but I tested the gem through rails c and found it catch any file as virus and not safe file!!

Clamby.safe?("#{Rails.root}/public/images/astm.txt")
=> false
Clamby.virus?("#{Rails.root}/public/images/astm.txt")
=> true

Also I tried all the configurations options but still facing the same case!
what I miss?!!

How complete is this interface?

I am planning to use clamav for scanning uploaded files and was planning to create a ruby wrapper for clamav command line utilities. On searching I found your gem.
So I just wanted to know is this production ready setup. I wanted to use this badly on my production servers.

Make it possible for the version check to use the clamdscan executable

We are integrating this gem to another framework and we would like to do the version check during the application's startup process.

Currently this gem does it with the clamscan executable even when the daemonize configuration option is set to true. The check could also be done using the clamdscan executable:
https://linux.die.net/man/1/clamdscan

It is just a minor annoyance as this only happens once in the startup process of the application but would save few seconds of execution time during the startup. Would be nice change from our perspective if it doesn't pose any possible issues in the existing applications using this gem.

I thought I'd ask whether there is any reasoning behind this before suggesting any changes to the behavior. We would like to change this line to:

  new.run scan_executable, '--version'

Would you see any behavioral impacts of this change in the existing applications that are using this?

Missing tag/release

https://rubygems.org/gems/clamby/versions/1.6.9 and 52b6ff4 are out, but there's no tag/release/etc.

As a result, Dependabot can't show the changes
image

Impact: this looks slightly like a dodgy release by a malicious actor who has potentially compromised your rubygems account.
As clamby is used for AV scanning, it's a plausible target.
The reality is it's a non issue, but it seems alarming at first glance!

README enhancement re: AppArmor blocking clamdscan

Thanks in advance for all of your work on the Clamby gem. In getting the Clamby gem to work, I ran across an issue that isn't specific to Clamby per se. But I imagine it affects a large number of Linux users who are trying to use Clamby. By default, clamdscan is limited by AppArmor in terms of what directories it can access. A rails project would typically be outside of these whitelisted directories (e.g. mine was in /var/www/....). So when I tried to have Clamby scan a file, I received a generic error of "Can't open file or directory ERROR". The ClamAV daemon runs as 'clamav', and that user could read the file fine. So it was rather perplexing. A brief mention of this gotcha in the README might save some time for future users.

Using config file prevents `Clamby.update`

I run clamd as a docker container and
when I defined the :config_file in the Clamby initialiser I used the clamd config.
Then it errors out when trying to run Clamby.update,
since the clamd config has options that freshclam does not.

So it would be preem if there was a way to use a second config for freshclam or something else. ๐Ÿ™‚

Scanning a Tempfile which exists in memory

It would be handy if you could scan a Tempfile (child of File) object as it exists in memory.
irb> require 'tempfile'
file = Tempfile.open("/path/to/file/file.txt")
file.unlink
Clamby.safe?(file)

I realise this may be a limitation as clamscan but thought I would make the suggestion anyway.

False positive in production environment (solved)

This problem is related to #31. For me, #31 didn't solve the problem. Clamsy and clamdscan worked fine local and with files I had put myself on the server in /tmp. But not with tempfiles created by ActiveStorage, like /tmp/RackMultipart20210304-544254-1q5vwnm.jpg.

We use clamsy in daemon mode, like "/usr/sbin/clamd -c /etc/clamd.d/scan.conf" as user 'clamscan'.

The problem was in the file permissions: RackMultipart... had 600, while the files I had put in this directory had 644. So the clamsy user had no access to the tempfile that was created by the application user.

My solution is to change attributes temporarily before the virusscan was done in the code:

if File.exist?(attachable.tempfile.path)
          # Temporarily change permissions, so the daemon has access. If not, it always returns false positive for any file.
          File.chmod(0644, attachable.tempfile.path)
          record.errors.add(attribute, :may_be_infected, file: attachable.original_filename) if Clamby.virus?(attachable.tempfile.path)
          File.chmod(0600, attachable.tempfile.path)
        end

So, for me, this problem is solved, but maybe a better solution could be found.

Clamby showing false positives when scanning from attachment temp file location

I'm not certain if this is a repeat of #9

I configured Clamby with ClamAV in a local environment, and didn't experience any issues.

However, when attempting to configure Clamby and ClamAV in a production environment, I'm experiencing an issue where the Clamby#safe? method returns false for all files and Clamby#virus? method returns true for all files.

My production environment is running Ubuntu 16.05.5 LTS, and ClamAV, clamd, and freshclam have been installed and configured properly, to my knowledge.

irb(main):001:0> Clamby::Command.clamscan_version
ClamAV 0.102.1
=> true
$ ps aux | grep clamd
clamav   26428  3.3 21.3 1073956 864960 ?      Ssl  16:06   1:13 /usr/sbin/clamd --foreground=true

Per ClamAV documentation, clamd is running under the "clamav" user. I'm not sure if this is how the daemon should be configured to work with Clamby or not.

/config/initializers/clamby.rb

Clamby.configure({
  :check => false,
  :daemonize => true,
  :error_clamscan_missing => false,
  :error_file_missing => false,
  :error_file_virus => false,
  :fdpass => true
})

When I check any file, even files contained in my Rails application, Clamby returns that all are viruses:

Example:

irb(main):001:0> test_path = "#{Rails.root}/README.md"
=> "/home/deploy/rails_app/README.md"
irb(main):002:0> Clamby.safe?(test_path)
=> false
irb(main):003:0> Clamby.virus?(test_path)
=> true

Additionally, clamd.conf and freshclam.conf have been configured properly:

clamd.conf
# Comment or remove the line below.
# Example
...
# TCP port address.
# Default: no
TCPSocket 3310
freshclam.conf
# Comment or remove the line below.
# Example

freshclam is also properly configured and updated:

$ freshclam
ClamAV update process started at Thu Dec 12 16:50:23 2019
daily.cld database is up to date (version: 25661, sigs: 2046351, f-level: 63, builder: raynman)
main.cvd database is up to date (version: 59, sigs: 4564902, f-level: 60, builder: sigmgr)
bytecode.cvd database is up to date (version: 331, sigs: 94, f-level: 63, builder: anvilleg)

Any help would be appreciated, as I'm not sure what's going wrong here between the various components involved.

Thanks.

Clamby showing every upload as a virus..

I am running an attache image server inside a container managed by dokku, I have added clamby to attache, and on my development machine (not dokku, just running the apps) it works fine... On my server it does not. It complains that every upload is a virus. I know this is likely a dokku/server problem rather than a clamby problem, but I wondered whether anyone might have an idea of what the problem could be?

clamby configuration:

# setup clamby
Clamby.configure({
                  :check => false,
                  :daemonize => true,
                  :error_clamscan_missing => false,
                  :error_file_missing => false,
                  :error_file_virus => true
                })

then just after upload:

          # check if free from viruses with clamby
          unless Clamby.safe?(path_of(cachekey))
            File.delete(path_of(cachekey))
            # raise virus-found error 
            raise 'Upload infected with a virus - rejected.'
          end

the error I get back is:
VIRUS DETECTED on 2017-09-22 15:22:59 +0000: /tmp/076/6B2/attache.myserver.com%2F7f%2F9c%2Fa8%2F4d%2Ff1%2F80%2Fe1%2F84%2F94%2F2c%2Fd0%2F98%2Fe3%2F35%2F68%2F1d%2Ftest-pic.jpeg

so am I right in assuming that the file is being scanned and giving a false positive? Or could the real error be masked here? I am thinking it seems like the latter as the file is definitely virus free...

As I say, I know this is unlikely a clamby issue, but I was hoping you might be able to point me in the direction of what the real error might be (as it certainly looks as though clamav is running fine, and the file is found and scanned) - or at least if I might get this error even if the real problem is not that a virus has been found (maybe the file is not being scanned or not found or something)?

Thanks,

J

Bug causes rails to crash

Hi after including this gem, bundle and doing nothing else I am getting this error when I run "rails console" and it crash.

versions/2.6.5/lib/ruby/gems/2.6.0/gems/clamby-1.6.6/lib/clamby.rb:34:in `delete': can't modify frozen Hash (FrozenError)

MacOS Sig Sur (11.3)
Rails 5.2.5
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin20]

[FEATURE] Extract virus details and include in VirusDetected

Great gem @kobaltz thanks!

I've got a requirement to display the type of virus that has been detected. I've already written the changes needed to add this to clamby but thought I'd check if that would be something you'd be interested in merging before creating the PR.

Basically just modifying the Command class, specifically the .scan and #run methods to parse the console output and include the parsed virus type when raising the VirusDetected error. My change swaps out the system call with a Open3 library function call to peek at the output and error streams.

Thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.