обслуживание файлов с помощью django - это уязвимость безопасности - PullRequest
1 голос
/ 31 марта 2010

Я использую следующий код для обслуживания загруженных файлов из защищенного представления входа в систему в приложении django.

Как вы думаете, есть ли уязвимость в этом коде? Я немного обеспокоен тем, что пользователь может поместить произвольные строки в URL после загрузки /, и это напрямую отображается в локальной файловой системе.

На самом деле я не думаю, что это проблема уязвимости, поскольку доступ к файловой системе ограничен файлами в папке, определенной с помощью параметра UPLOAD_LOCATION.

UPLOAD_LOCATION = is set to a not publicly available folder on the webserver

url(r'^upload/(?P<file_url>[/,.,\s,_,\-,\w]+)', 'project_name.views.serve_upload_files', name='project_detail'),

@login_required
def serve_upload_files(request, file_url):
    import os.path
    import mimetypes
    mimetypes.init()

    try:
        file_path = settings.UPLOAD_LOCATION + '/' + file_url
        fsock = open(file_path,"r")
        file_name = os.path.basename(file_path)
        file_size = os.path.getsize(file_path)
        print "file size is: " + str(file_size)
        mime_type_guess = mimetypes.guess_type(file_name)
        if mime_type_guess is not None:
            response = HttpResponse(fsock, mimetype=mime_type_guess[0])
        response['Content-Disposition'] = 'attachment; filename=' + file_name
        #response.write(file)             
    except IOError:
        response = HttpResponseNotFound()
    return response

РЕДАКТИРОВАТЬ: Обновлен источник в соответствии с комментариями Игнасио Васкес-Абрамс:

 import os.path
 import mimetypes

  @login_required
  def serve_upload_files(request, file_url):
    mimetypes.init()
    try:
        file_path = os.path.join(settings.UPLOAD_LOCATION, file_url)
        #collapse possibly available up-level references
        file_path = os.path.normpath(file_path)
        #check if file path still begins with settings.UPLOAD_LOCATION, otherwise the user tampered around with up-level references in the url
        #for example this input: http://127.0.0.1:8000/upload/..\test_upload.txt results having the user access to a folder one-level higher than the upload folder
        #AND check if the common_prefix ends with a dir separator, Because although '/foo/barbaz' starts with '/foo/bar'
        common_prefix = os.path.commonprefix([settings.UPLOAD_LOCATION, file_path])
        if common_prefix == settings.UPLOAD_LOCATION and common_prefix.endswith(os.sep):
            fsock = open(file_path,"r")
            file_name = os.path.basename(file_path)
            mime_type_guess = mimetypes.guess_type(file_name)
            if mime_type_guess is not None:
                response = HttpResponse(fsock, mimetype=mime_type_guess[0])
                response['Content-Disposition'] = 'attachment; filename=' + file_name
            else:
                response = HttpResponseNotFound() 
        else:
            print "wrong directory"
            response = HttpResponseNotFound()           
    except IOError:
        response = HttpResponseNotFound()
    return response

1 Ответ

5 голосов
/ 31 марта 2010

Несколько советов:

  1. Используйте os.path.join(), чтобы объединить путь.
  2. Используйте os.path.normpath(), чтобы получить фактический путь без ссылок "..".
  3. Используйте os.path.commonprefix() против UPLOAD_LOCATION и сгенерированного пути и убедитесь, что результат начинается с UPLOAD_LOCATION.
  4. Убедитесь, что UPLOAD_LOCATION заканчивается разделителем dir.

TL; DR: используйте os.path.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...