Настройка сканирования потока загрузки файлов с использованием Clamav в бэкэнде Django - PullRequest
0 голосов
/ 24 мая 2018

Работа над приложением React / Django.У меня есть файлы, загружаемые пользователями через интерфейс React, которые в конечном итоге попадают в интерфейс Django / DRF.У нас на сервере постоянно работает антивирус (AV), но мы хотим добавить потоковое сканирование, прежде чем оно будет записано на диск.

Мне не совсем понятно, как его настроить.Вот несколько источников, на которые я смотрю.

Как вы проверяете вирус, загружаемый в ваше веб-приложение java во время потоковой передачи?

Хотя принятый лучший ответ описываетэто "... довольно легко" настроить, я изо всех сил.

Мне, очевидно, нужно cat testfile | clamscan - за пост и соответствующую документацию:

Как выВирус проверяет файл, загружаемый в ваше веб-приложение java во время его потоковой передачи?

Так что, если мой бэкэнд выглядит следующим образом:

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) Как запустить Bash из Python?

2) Как получитьрезультат ответа сканирования, чтобы его можно было отправить обратно пользователю, а другие действия можно выполнить с ответом на серверной части?(Подобно созданию логики, чтобы отправить пользователю и администратору электронное письмо о том, что в их файле был вирус).

Я играл с этим, но не сильно удача.

Запуск Bashкоманды в Python

Более того, есть репозитории Github, которые утверждают, что довольно хорошо женятся на Кламаве с Django, но они либо не обновлялись годами, либо существующая документация довольно плохая.См. Следующее:

https://github.com/vstoykov/django-clamd

https://github.com/musashiXXX/django-clamav-upload

https://github.com/QueraTeam/django-clamav

1 Ответ

0 голосов
/ 24 мая 2018

Хорошо, получил это с clamd .Я изменил свой SaveDocumentAPIView на следующее.Это сканирует файлы перед их записью на диск и предотвращает их запись в случае заражения.По-прежнему пропускает незараженные файлы, поэтому пользователю не нужно повторно загружать их.

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)
...