卡巴斯基+NodeJS打造远程杀毒服务器

来源:互联网 发布:网络培训 编辑:程序博客网 时间:2024/06/08 09:54

很多系统都自带邮件服务器,比如最常见的办公系统。一般邮件服务器都建立在Linux设备上,但是杀毒软件往往很少有支持Linux平台的,即使支持,操作往往也很麻烦或者需要图形界面,而人们一般不会再邮件服务器上特意去装一个图形界面的。所以不妨换个思路,在局域网中再来几台Windows设备,装上杀毒软件专门提供病毒检测服务。邮件服务器把需要检测的文件发送给Windows杀毒服务器进行扫描,获得一个扫描结果后入库。Windows服务器和邮件服务器不共享存储,虽然降低了效率但是安全性保密性得到提高。而且邮件附件不会每天都去扫一遍,发邮件的时候实时扫描就可以了。对于小规模的邮件服务器非常方便,搭建成本极低,也就是买个服务器的成本。要是虚拟化平台可以直接打到零成本部署杀毒服务器。

一、基于卡巴斯基免费版命令行使用说明

测试了国内国外很多杀毒软件,包括收费的和免费的。这里要隆重表扬一下卡巴斯基,在大多数杀毒大厂都设为收费服务的命令行查毒工具卡巴斯基竟然在他的免费版本里提供了。这个命令行查毒工具是邮件服务器的核心,卡巴斯基真乃良心企业。

首先到卡巴斯基官网下载最新的免费版,当然你要下收费版更好。https://www.kaspersky.com.cn/free-antivirus

我下载的版本是kfa18.0.0.405abzh-hans_12797.exe

安装完毕是这个样子的,就是普通的家用版,然而我们现在要把它当成服务器级别的来使用了。

重要的是卡巴斯基安装目录下的命令行杀毒程序,他的位置是C:\Program Files (x86)\Kaspersky Lab\Kaspersky Free 18.0.0\avp.com,几乎所有的Windows电脑都只能安装在这个位置。


然后我们使用命令行尝试一下查杀功能,注意,如果你电脑上卡巴斯基程序没有运行的话,那么执行avp.com会开启卡巴斯基防护服务和图形界面

avp.com SCAN 文件或文件夹路径

注意如果你参数是文件路径那么就只扫描这一个文件,如果填的是文件夹路径那么就会递归搜索这个文件夹下所有的文件,但是不支持通配符,比如*.rar,2017.*这样的文件名。另外还需要注意windows cmd程序不支持路径中间有空格,需要用双引号把路径包起来,下面分别是扫描单个文件和扫描文件夹

可以看出卡巴斯基把文件扫描的具体清单打印了出来,包括扫描的哪个文件,这个文件是不是ok,最下面有一个总扫描文件数,总安全文件数和被发现病毒文件数。在读取报文的时候我们可以先检查总病毒文件数是不是为0,如果不为0再向上寻找是哪个文件没有检测通过。

注意:有些文件虽然只是单个文件,但是卡巴斯基会拆成一块一块的扫描,典型的就是zip,rar等压缩文件,exe安装包,Word Excel等办公文件,如下图只扫描了一个excel文。件但是他扫描了4个,估计把工作簿里每一个sheet都算做一个文件。很多时候word文档能扫描出30多个文件


中文出现乱码是很正常的事,不会影响扫描结果。


1.1 NodeJS服务器调用卡巴斯基过程说明


既然有了这么好用的命令行工具,那么我们找一个中间件,对外提供一个可访问的接口,让其他服务器把要查毒的文件上传上来,然后扫描完把这个报文发送回去,让其他的服务器自己去解析报文各取所需就好了,报文格式就是上面的截图所示案例,一般如下

AV bases release date: 2017-09-15 19:55:00 (full); --- Settings ---; Action on detect:     Ask after scan; Scan objects: All objects; Use iChecker: Yes; Use iSwift:   Yes; Try disinfect:        Yes; Try delete:   Yes; Try delete container: No; Exclude by mask:      No; Include by mask:      No; Objects to scan:;       "E:\54\"        Enable = Yes    Recursive = Yes; ------------------2017-09-16 15:58:01     Scan_Objects$0320         starting   1%2017-09-16 15:58:01     E:\54\Save003.sav       ok2017-09-16 15:58:01     Scan_Objects$0320         running    1%2017-09-16 15:58:01     E:\54\saves.ini ok2017-09-16 15:58:01     E:\54\Save001.sav       ok2017-09-16 15:58:01     E:\54\Save002.sav       ok2017-09-16 15:58:01     Scan_Objects$0320         completedInfo: task 'ods' finished, last error code 0;  --- Statistics ---; Time Start:   2017-09-16 15:58:01; Time Finish:  2017-09-16 15:58:01; Processed objects:    4; Total OK:     4; Total detected:       0; Suspicions:   0; Total skipped:        0; Password protected:   0; Corrupted:    0; Errors:       0;  ------------------

注意尽量不要使用中文文件名,不然在文件夹内一次扫描多个文件时因为乱码不知道哪个文件有毒,但是每次都使用单文件扫描就不会有这个问题了。

中间件这里不选大佬级的Apache或者Tomcat,用个小规模高效率服务器就好,我这里使用nodeJS,因为程序写起来太简短了,搭建一个杀毒服务器只需不到100行代码即可搞定。


首先确保你电脑上已经部署了node和express框架,如果不会安装出门左拐上百度,然后程序主文件如下写法,下面这个例子是单文件扫描,就是客户端每次只上传一个文件进行扫描。注意在服务器调用的时候加上了/i0参数,目的是不让它自动询问或清除带毒文件,只做扫描即可。以免询问过程卡住进程。

index.js

var express = require('express');var app = express();var upload = require('./fileupload');app.use(express.static('html'));var process = require('child_process');var anvirusSoftware = '"C:\\Program Files (x86)\\Kaspersky Lab\\Kaspersky Free 18.0.0\\avp.com" SCAN /i0 '//文件上传服务app.post('/upload', upload.single('virus_file'), function (req, res, next) {    console.log('上传来的文件是:'+req.file);    if (req.file) {        //res.send('文件上传成功');        console.log(req.file);var upload_directory = req.file.destination;var path = req.file.path;console.log('上传文件被存储到了目标文件夹:'+upload_directory);console.log('被保存的文件路径:'+upload_directory);console.log('=======');        console.log(req.body);console.log("准备开启杀毒程序")process.exec(anvirusSoftware + path,function (error, stdout, stderr) {        if (error !== null) {          console.log('exec error: ' + error);        } else if (stdout !== null){res.send(stdout);console.log('success: ' + stdout);}});    } else {res.send('没有上传任何文件');    }});app.get('/upload', function (req, res, next) {console.log('get来了'+req.file);res.send('不要用get请求');});app.get('/', function (req, res) {  res.send('Hello World!');});var server = app.listen(3000, function () {  var host = server.address().address;  var port = server.address().port;  console.log('Example app listening at http://%s:%s', host, port);});

其中<input>的name属性在upload.single中确定,本例是“virus_file”
客户端使用POST进行上传,服务器地址为127.0.0.1:3000并监听全部网卡的3000端口,你可以自己配置。这里用到了nodeJS的文件上传模块,专门写了一个文件用来配置multer ,这个文件配置了上传后文件存储的位置,文件存储的文件名等信息,返回值是个multer实例

fileupload.js

var multer = require('multer');var dstPath = process.cwd() + '/uploads';//设置上传文件路径var storage = multer.diskStorage({    //Note:如果destination:传递的是一个函数,你负责创建文件夹,如果你传递的是一个字符串,multer会自动创建    destination: dstPath,    //TODO:文件区分目录存放    //给上传文件重命名    filename: function (req, file, cb) {        cb(null, '收到的文件_'+file.originalname);    }});//添加配置文件到muler对象。var upload = multer({    storage: storage,    //其他设置请参考multer的limits    //limits:{}});//导出对象module.exports = upload;

另外再展示一下依赖文件Package.json,命令行使用npm install就可以自动联网下载依赖包

{  "name": "anti_virus",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "author": "",  "license": "ISC",  "dependencies": {    "child_process": "^1.0.2",    "express": "^4.15.4",    "multer": "^1.3.0"  }}


其中child_process是用来新开进程执行cmd命令的依赖库,multer是执行文件存储接收的依赖库。

短短几行一个杀毒服务器就搭建好啦


为了测试方便,我们写一个简单的前端页面,真正使用的时候一般是Java或者PHP直接上传的。注意这里的input name属性要写和上面index.js规定的一样,为“virus_file”


<head>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><form id='editfile' method='post' action='/upload' enctype='multipart/form-data'>选择要扫描的文件:<input name="virus_file"  type='file'/></br>    <input type='submit' value='提交'/></form></body>



然后命令行cd到我们node程序的文件夹,执行node index.js启动服务器,观察3000端口是否在监听状态,然后访问127.0.0.1:3000/test.html ,然后就可以选择文件然后点击提交,提交之后就会看见命令行输出上面的卡巴斯基的扫描过程,然后把最后结果反馈给浏览器

同时文件出现在了我们node app文件夹\uploads下,文件名为“收到的文件_”+原文件名,当然一般来说使用随机字母比较好

EDGE浏览器没有显示换行符,但是使用JAVA或PHP是没有什么问题的。nodeJS后台日志如下


这样我们就测试通过了。


1.2 多文件上传,批量扫描NodeJS配置


单个文件上传查毒可能会频繁地启动和关闭杀毒引擎,效率比较低,所以我们也可以设置一个多文件上传和杀毒的方案。他的核心是卡巴斯基对文件夹的扫描能力。

方法就是对于每一次上传文件请求,在NodeJS服务器上都单独建立一个文件夹,这个文件夹的名字是随机生成的,这个文件夹里存放本次请求上传的所有文件,查毒时只需要让卡巴斯基扫描这个文件夹就知道哪个文件有毒了。而且这样做同时发起的不同文件扫描请求不会冲突,结果准确,支持较大的并发量。

首先最重要的是修改fileupload.js这个文件,让它智能的对每个不同的request建立不同的文件夹,但是由于diskStorage这个方法每一个新上传的文件都会执行一次,关键在于如何区分当前这个文件是属于哪一个request的,毕竟同一时间我们的病毒服务器可能收到来自不同设备的好几个杀毒请求。

型号multer给出了req这个对象作为传入参数,所以我们为了方便识别当前文件的req是谁的req,我们可以在req这个对象内部放一个新成员“dir_name”,这个新成员是个随机数,对于一次上传多个文件来说,第一个被循环到的文件把这个随机数放入,并根据这个随机数建立本地的文件夹,然后后来的文件如果检查到这个随机数存在,那么就证明这一批文件是同一个request发来的,那么就放到刚才建立的哪个文件夹里。

/** * * @Description 文件上传配置 * */var multer = require('multer');var fs = require('fs');var dstPath = process.cwd() + '/uploads/';//设置上传文件路径var storage = multer.diskStorage({    //Note:如果destination:传递的是一个函数,你负责创建文件夹,如果你传递的是一个字符串,multer会自动创建    destination: function (req, file, cb) {console.log('req.dir_name===='+req.dir_name);var upload_dir = dstPath + req.dir_name;if(!req.dir_name){//如果这是这个req的第一个文件,还没有建立相关文件夹var dir_name = (Math.random()+"").slice(9);req.dir_name = dir_name;//标记这个requpload_dir = dstPath + dir_name;if (!fs.existsSync(upload_dir)) {            fs.mkdirSync(upload_dir);    console.log('创建文件夹成功:'+upload_dir);        }}        cb(null, upload_dir);    },    //TODO:文件区分目录存放    //给上传文件重命名    filename: function (req, file, cb) {        cb(null, '收到的文件_'+file.originalname);    }});//添加配置文件到muler对象。var upload = multer({    storage: storage,    //其他设置请参考multer的limits    //limits:{}});//导出对象module.exports = upload;

然后主入口文件也要做相应的修改,主要是把刚才的upload.single改成upload.array('属性名',最大文件上传数量),属性名还是要与<input>的name属性一致
var express = require('express');var app = express();app.use(express.static('html'));var upload = require('./fileupload');var process = require('child_process');var anvirusSoftware = '"C:\\Program Files (x86)\\Kaspersky Lab\\Kaspersky Free 18.0.0\\avp.com" SCAN /i0 '//文件上传服务app.post('/upload', upload.array('virus_file',10), function (req, res, next) {    console.log(req.files);    if (req.files) {        //res.send('文件上传成功');var length = req.files.length;        console.log('上传文件个数是:'+ length);var upload_directory = req.files[0].destination;console.log('上传文件被存储到了目标文件夹:'+upload_directory);for(var i=0;i<length;i++){var path = req.files[i].path;console.log('被保存的文件完整路径:'+path);}console.log('=======');        console.log(req.body);console.log("准备开启杀毒程序");process.exec(anvirusSoftware + upload_directory ,function (error, stdout, stderr) {        if (error !== null) {          console.log('exec error: ' + error);        } else if (stdout !== null){res.send(stdout);console.log('success: ' + stdout);}});    } else {res.send('没有上传任何文件');}});app.get('/upload', function (req, res, next) {console.log('get来了'+req.file);res.send('不要用get请求');});app.get('/', function (req, res) {  res.send('Hello World!');});var server = app.listen(3000, function () {  var host = server.address().address;  var port = server.address().port;  console.log('Example app listening at http://%s:%s', host, port);});

由于上面规定了最大可以上传10个文件,那么HTML测试页面也要小改一下

<head>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><form id='editfile' method='post' action='/upload' enctype='multipart/form-data'>选择要扫描的文件:<input name="virus_file"  type='file'/></br>选择要扫描的文件:<input name="virus_file"  type='file'/></br>选择要扫描的文件:<input name="virus_file"  type='file'/></br>选择要扫描的文件:<input name="virus_file"  type='file'/></br>选择要扫描的文件:<input name="virus_file"  type='file'/></br>    <input type='submit' value='提交'/></form></body>


具体的项目结构和代码可以到github上下载:https://github.com/AlexZhuo/NodeScanVirus

此时我们既可以上传单个文件,也能上传多个文件,只要最大数量不超过上面index.js标记的就可以,而且也不需要从第一个input框开始,如我上面这样上传是没有问题的。点击提交之后会出现扫描结果的报文。可以看到是两个文件都进行了扫描(对于压缩文件可能会更多)

然后本次上传的文件被单独存储在一个uploads\466101518\下,如果再上传一次,那么就是另一个随机数文件夹里:

这样我们的反病毒服务器就搭建好了。


卡巴斯基其他命令行选项


另外卡巴斯基命令行还支持很多别的参数,执行avp.com HELP SCAN 结果如下,比如可以添加日志记录什么的,根据实际情况进行配置

C:\Program Files (x86)\Kaspersky Lab\Kaspersky Endpoint Security 10 for Windows SP1>avp.com HELP SCANKaspersky Endpoint Security 10 for Windows (R) 10.2.4.674(C) 2013 Kaspersky Lab ZAO. All rights reserved.Usage: SCAN [<files>] [/ALL][/MEMORY][/STARTUP][/MAIL][/REMDRIVES]            [/FIXDRIVES][/NETDRIVES][/QUARANTINE] [/@:<filelist.lst>]            [/i<0-4>] [-e:a|s|b|<filemask>|<seconds>]            [/R[A]:<report_file>] [/C:<settings_file>]       SCAN /VLNS2 [/WUA][/WSUSCAB <wsus_file>] [<files>] [/lst <filelist.lst>]VLNS2 specific options:/WUA               Scan with WUA (default: off)/WSUSCAB           WSUS fileScan area:<files>            List of files and/or folders delimited with space.                   Long path names must be enclosed in quotes./ALL               Scan my computer/MEMORY            Scan computer memory/STARTUP           Scan startup-objects/MAIL              Scan mailboxes/REMDRIVES         Scan removable media/FIXDRIVES         Scan hard drives/NETDRIVES         Scan network drives/QUARANTINE        Scan quarantined objects/@:<filelist.lst>  Scan files in specified list fileAction with infected files:/i0                Report only/i1                Disinfect object,                   skip if disinfection is impossible./i2                Disinfect object,                   delete object if disinfection is impossible,                   dont't delete objects from containers,                   delete containers with executable header./i3                Disinfect object,                   delete object if disinfection is impossible,                   delete containers if objects can not be deleted./i4                Delete infected objects,                   delete containers if objects can not be deleted./i8 (default)      Ask me immediately/i9                Ask me when scan is finishedFile types:/fe                Quick check (by extensions)/fi                Smart check (by format)r/fa (default)      All filesExcludes:-e:a               Skip archives-e:b               Skip e-mail databases and plain text e-mail-e:<filemask>      Skip files by mask-e:<seconds>       Skip files scanned longer than <seconds>-es:<size>         Skip files greater than <size in megabytes>Reports:/R:<report_file>   Save only critical events/RA:<report_file>  Save all eventsAdditional settings:/iChecker=<on|off> Enable/disable iChecker technology/iSwift=<on|off>   Enable/disable iSwift technology/C:<settings_file> Specifies configuration fileExamples:avp.com SCAN /R:log.txt /MEMORY /STARTUP /MAIL "C:\Documents and Settings\All Users\My Documents" "C:\Program Files" C:\Downloads\test.exeavp.com SCAN /MEMORY /@:objects2scan.txt /C:scan_settings.txt /RA:scan.logavp.com SCAN /VLNS2avp.com SCAN /VLNS2 /RA:scan.log /WUA C:\Windows\

二、Avast,AVG杀毒软件命令行扫描


另外再提一下,除了卡巴斯基有Windows下的命令行查毒工具之外,Avast,AVG杀毒软件也有,扫描速度要比卡巴斯基的快,但是是按照设备数和时间进行收费的。

Avast和AVG的目录结构和杀毒命令是一模一样的,如下ashCmd.exe就是专为命令行设计的工具,不过只能在收费版中看到这个文件。


运行杀毒也很简单,只是不像卡巴斯基那样有stdout输出,但是有一个图形界面,可以输出日志。不是很适合服务器调用,调用命令如下

C:\Program Files\AVAST Software\Avast>ashCmd.exe /SCAN D:\bilibili\


如果加上输出日志就能很清晰的看到具体扫描了哪些文件,每个文件的状态如何

C:\Program Files\AVAST Software\Avast>ashCmd.exe D:\bilibili\ /_ > C:\results.txt

日志内容如下

D:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-1[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-2503[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-3812[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-4954[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-5670[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-6294[超清版].flvOKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-6821[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-7588[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-8043[超清版].flvOKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-8529[高清版].mp4OKD:\bilibili\0001.哔哩哔哩-那年那兔那些事儿 第二季-9061[高清版].mp4OKD:\bilibili\【历史_战争】鸦片战争 1997年【CCTV6高清720p】[高清版]\合并\0001.哔哩哔哩-【历史_战争】鸦片战争 1997年【CCTV6高清720p】[高清版].flvOKD:\bilibili\鸦片战争前夕的世界_flv-国语高清.qsvOK# ----------------------------------------------------------------# 扫描文件个数: 13# 扫描文件夹个数: 3# 感染文件个数: 0# 扫描文件的总大小: 2897597658# 病毒数据库: 170914-2, 17/09/14# 扫描时间总计: 0:0:1

比卡巴斯基的优势是扫描速度更快,而且完美的支持中文。但是需要在扫描结束之后同步读取刚刚生成的日志文件,对系统开销会更大。另外卡巴斯基其实也支持生成日志文件。