Python 在Django后端使用Clamav设置文件上载流扫描

Python 在Django后端使用Clamav设置文件上载流扫描,python,django,web-applications,antivirus,antivirus-integration,Python,Django,Web Applications,Antivirus,Antivirus Integration,正在使用React/Django应用程序。我有用户通过React前端上传的文件,这些文件最终位于Django/DRF后端。我们在服务器上不断运行防病毒(AV),但我们希望在写入磁盘之前添加流扫描 至于如何设置它,我有点不知所措。以下是我正在寻找的一些资料来源 尽管公认的最佳答案描述了它的设置“相当容易”,但我仍在苦苦挣扎 我显然需要按照帖子和相应的文档cat testfile | clascan-: 因此,如果我的后端如下所示: class SaveDocumentAPIView(APIVi

正在使用React/Django应用程序。我有用户通过React前端上传的文件,这些文件最终位于Django/DRF后端。我们在服务器上不断运行防病毒(AV),但我们希望在写入磁盘之前添加流扫描

至于如何设置它,我有点不知所措。以下是我正在寻找的一些资料来源

尽管公认的最佳答案描述了它的设置“相当容易”,但我仍在苦苦挣扎

我显然需要按照帖子和相应的文档
cat testfile | clascan-

因此,如果我的后端如下所示:

class SaveDocumentAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):

        # this is for handling the files we do want
        # it writes the files to disk and writes them to the database
        for f in request.FILES.getlist('file'):
            max_id = Uploads.objects.all().aggregate(Max('id'))
            if max_id['id__max'] == None:
                max_id = 1
            else:    
                max_id = max_id['id__max'] + 1
            data = {
                'user_id': request.user.id,
                'sur_id': kwargs.get('sur_id'),
                'co': User.objects.get(id=request.user.id).co,
                'date_uploaded': datetime.datetime.now(),
                'size': f.size
            }
            filename = str(data['co']) + '_' + \
                    str(data['sur_id']) + '_' + \
                    str(max_id) + '_' + \
                    f.name
            data['doc_path'] = filename
            self.save_file(f, filename)
            serializer = SaveDocumentSerializer(data=data)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
        return Response(status=HTTP_200_OK)

    # Handling the document
    def save_file(self, file, filename):
        with open('fileupload/' + filename, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
我想我需要在
save_file
方法中添加如下内容:

for chunk in file.chunks():
    # run bash comman from python
    cat chunk | clamscan -
    if passes_clamscan:
        destination.write(chunk)
        return HttpResponse('It passed')
    else:
        return HttpResponse('Virus detected')
因此,我的问题是:

1) 如何从Python运行Bash

2) 如何从扫描中接收结果响应,以便将其发送回用户,并使用后端的响应完成其他事情?(比如创建逻辑,向用户和管理员发送一封电子邮件,告知他们的文件有病毒)

我一直在玩这个,但运气不太好

此外,还有一些Github回购协议声称Clamav与Django的婚姻相当不错,但它们要么多年没有更新,要么现有的文档相当糟糕。见下文:

class SaveDocumentAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):

        # this is for handling the files we do want
        # it writes the files to disk and writes them to the database
        for f in request.FILES.getlist('file'):
            max_id = Uploads.objects.all().aggregate(Max('id'))
            if max_id['id__max'] == None:
                max_id = 1
            else:    
                max_id = max_id['id__max'] + 1
            data = {
                'user_id': request.user.id,
                'sur_id': kwargs.get('sur_id'),
                'co': User.objects.get(id=request.user.id).co,
                'date_uploaded': datetime.datetime.now(),
                'size': f.size
            }
            filename = str(data['co']) + '_' + \
                    str(data['sur_id']) + '_' + \
                    str(max_id) + '_' + \
                    f.name
            data['doc_path'] = filename
            self.save_file(f, filename)
            serializer = SaveDocumentSerializer(data=data)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
        return Response(status=HTTP_200_OK)

    # Handling the document
    def save_file(self, file, filename):
        with open('fileupload/' + filename, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)

好的,我们已经准备好了。我将我的
保存视图
修改为以下内容。这将在文件写入磁盘之前扫描这些文件,并防止它们在被感染时被写入。仍然允许未受感染的文件通过,因此用户不必重新上传它们

class SaveDocumentAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):

        # create array for files if infected
        infected_files = []

        # setup unix socket to scan stream
        cd = clamd.ClamdUnixSocket()

        # this is for handling the files we do want
        # it writes the files to disk and writes them to the database
        for f in request.FILES.getlist('file'):
            # scan stream
            scan_results = cd.instream(f)

            if (scan_results['stream'][0] == 'OK'):    
                # start to create the file name
                max_id = Uploads.objects.all().aggregate(Max('id'))
                if max_id['id__max'] == None:
                    max_id = 1
                else:    
                    max_id = max_id['id__max'] + 1
                data = {
                    'user_id': request.user.id,
                    'sur_id': kwargs.get('sur_id'),
                    'co': User.objects.get(id=request.user.id).co,
                    'date_uploaded': datetime.datetime.now(),
                    'size': f.size
                }
                filename = str(data['co']) + '_' + \
                        str(data['sur_id']) + '_' + \
                        str(max_id) + '_' + \
                        f.name
                data['doc_path'] = filename
                self.save_file(f, filename)
                serializer = SaveDocumentSerializer(data=data)
                if serializer.is_valid(raise_exception=True):
                    serializer.save()

            elif (scan_results['stream'][0] == 'FOUND'):
                send_mail(
                    'Virus Found in Submitted File',
                    'The user %s %s with email %s has submitted the following file ' \
                    'flagged as containing a virus: \n\n %s' % \
                    (
                        user_obj.first_name, 
                        user_obj.last_name, 
                        user_obj.email, 
                        f.name
                    ),
                    'The Company <no-reply@company.com>',
                    ['admin@company.com']
                )
                infected_files.append(f.name)

        return Response({'filename': infected_files}, status=HTTP_200_OK)

    # Handling the document
    def save_file(self, file, filename):
        with open('fileupload/' + filename, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
class SaveDocumentPiView(APIView):
权限\u类=[IsAuthenticated]
def post(自我、请求、*args、**kwargs):
#如果被感染,为文件创建数组
受感染的_文件=[]
#设置unix套接字以扫描流
cd=clamd.ClamdUnixSocket()
#这是为了处理我们想要的文件
#它将文件写入磁盘并写入数据库
对于request.FILES.getlist('file')中的f:
#扫描流
扫描结果=流内cd(f)
如果(扫描结果['stream'][0]=='OK'):
#开始创建文件名
max_id=Uploads.objects.all().aggregate(max('id'))
如果max\u id['id\u max']==无:
max_id=1
其他:
max\u id=max\u id['id\u max']+1
数据={
“用户id”:request.user.id,
'sur_id':kwargs.get('sur_id'),
“co”:User.objects.get(id=request.User.id).co,
“上载日期”:datetime.datetime.now(),
“大小”:f.size
}
filename=str(数据['co'])+''.'+\
str(数据['sur_id'])+''.'+\
str(max_id)+''''+\
f、 名字
数据['doc_path']=文件名
self.save_文件(f,文件名)
serializer=SaveDocumentSerializer(数据=数据)
如果serializer.is_有效(raise_exception=True):
serializer.save()
elif(扫描结果['stream'][0]=='FOUND'):
寄信(
“在提交的文件中发现病毒”,
'带有电子邮件%s的用户%s%s已提交以下文件'\
'标记为包含病毒:\n\n%s'%\
(
用户名称,
用户名,
用户_obj.email,
f、 名字
),
“公司”,
['admin@company.com']
)
受感染的_文件。追加(f.name)
返回响应({'filename':受感染的\u文件},状态=HTTP\u 200\u OK)
#处理文件
def save_文件(自身、文件、文件名):
以open('fileupload/'+文件名,'wb+')作为目标:
对于文件.chunks()中的块:
destination.write(块)
好的,我们已经准备好了。我将我的
保存视图
修改为以下内容。这将在文件写入磁盘之前扫描这些文件,并防止它们在被感染时被写入。仍然允许未受感染的文件通过,因此用户不必重新上传它们

class SaveDocumentAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, *args, **kwargs):

        # create array for files if infected
        infected_files = []

        # setup unix socket to scan stream
        cd = clamd.ClamdUnixSocket()

        # this is for handling the files we do want
        # it writes the files to disk and writes them to the database
        for f in request.FILES.getlist('file'):
            # scan stream
            scan_results = cd.instream(f)

            if (scan_results['stream'][0] == 'OK'):    
                # start to create the file name
                max_id = Uploads.objects.all().aggregate(Max('id'))
                if max_id['id__max'] == None:
                    max_id = 1
                else:    
                    max_id = max_id['id__max'] + 1
                data = {
                    'user_id': request.user.id,
                    'sur_id': kwargs.get('sur_id'),
                    'co': User.objects.get(id=request.user.id).co,
                    'date_uploaded': datetime.datetime.now(),
                    'size': f.size
                }
                filename = str(data['co']) + '_' + \
                        str(data['sur_id']) + '_' + \
                        str(max_id) + '_' + \
                        f.name
                data['doc_path'] = filename
                self.save_file(f, filename)
                serializer = SaveDocumentSerializer(data=data)
                if serializer.is_valid(raise_exception=True):
                    serializer.save()

            elif (scan_results['stream'][0] == 'FOUND'):
                send_mail(
                    'Virus Found in Submitted File',
                    'The user %s %s with email %s has submitted the following file ' \
                    'flagged as containing a virus: \n\n %s' % \
                    (
                        user_obj.first_name, 
                        user_obj.last_name, 
                        user_obj.email, 
                        f.name
                    ),
                    'The Company <no-reply@company.com>',
                    ['admin@company.com']
                )
                infected_files.append(f.name)

        return Response({'filename': infected_files}, status=HTTP_200_OK)

    # Handling the document
    def save_file(self, file, filename):
        with open('fileupload/' + filename, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
class SaveDocumentPiView(APIView):
权限\u类=[IsAuthenticated]
def post(自我、请求、*args、**kwargs):
#如果被感染,为文件创建数组
受感染的_文件=[]
#设置unix套接字以扫描流
cd=clamd.ClamdUnixSocket()
#这是为了处理我们想要的文件
#它将文件写入磁盘并写入数据库
对于request.FILES.getlist('file')中的f:
#扫描流
扫描结果=流内cd(f)
如果(扫描结果['stream'][0]=='OK'):
#开始创建文件名
max_id=Uploads.objects.all().aggregate(max('id'))
如果max\u id['id\u max']==无:
max_id=1
其他:
max\u id=max\u id['id\u max']+1
数据={
“用户id”:request.user.id,
'sur_id':kwargs.get('sur_id'),
“co”:User.objects.get(id=request.User.id).co,
“上载日期”:datetime.datetime.now(),
“大小”:f.size
}
filename=str(数据['co'])+''.'+\
str(数据['sur_id'])+''.'+\
str(max_id)+''''+\
f、 名字
数据['doc_path']=文件名
self.save_文件(f,文件名)
serializer=SaveDocumentSeriali