Как безопасно проверить размер загружаемого файла в Bottlepy?

Я действительно боюсь этой операции read(), потому что она использует память. Например, кто-нибудь может атаковать мой сервер, загрузив файл размером 1 ГБ, верно?

name = request.forms.get('name')
data = request.files.get('data')
if name and data.file:
    raw = data.file.read() # This is dangerous for big files
    filename = data.filename
    return "Hello %s! You uploaded %s (%d bytes)." % (name, filename, len(raw))

Есть ли безопасное решение для получения размера загруженного файла? Можно предположить, что размер файла можно получить из файловой системы; request.files.get('data'), вероятно, хранится где-то во временном файле, верно?


person holms    schedule 27.06.2012    source источник
comment
Если вы запускаете бутылку через wsgi под чем-то вроде apache, apache может ограничить размер загрузки.   -  person jordanm    schedule 27.06.2012
comment
Bottle сохраняет request.body и все загруженные файлы во временные файлы (или буферы ByteIO, если они достаточно малы), как только вы обращаетесь к любому из них. Если вы хотите ограничить размер загрузки до того, как сервер выполнит всю работу, проверьте request.content_length. Если вы просто хотите убедиться, что все помещается в память, прочитайте/скопируйте загруженные файлы небольшими порциями, как описано pyfunc в его ответе.   -  person defnull    schedule 28.06.2012


Ответы (2)


Можете ли вы проверить, можете ли вы читать куски данных по одному.

Если это возможно, то:

name = request.forms.get('name')
data = request.files.get('data')
raw = ""
if name and data.file:
    while True:
        datachunk = data.file.read(1024)
        if not datachunk:
            break
        raw = raw + datachunk

    filename = data.filename
    return "Hello %s! You uploaded %s (%d bytes)." % (name, filename, len(raw))

Если это возможно, вы также должны иметь возможность добавить механизм отслеживания того, насколько большой файл вы хотите прочитать, и, если он превышен, прервать эту операцию.

Однако это решает только один из возможных способов DDOS.

person pyfunc    schedule 27.06.2012
comment
не могли бы вы исправить свой код? размер = должен быть удален. это создает TypeError: read() не принимает аргументов ключевого слова, если указано только 1024, оно работает - person holms; 10.07.2012
comment
@holms: Спасибо за исправление. Я предполагал, что будет передан именованный аргумент. Попробуйте посмотреть код, может он как-то по другому называется. - person pyfunc; 10.07.2012

Это интересный вопрос. Обычно вы либо получаете статистику по файловому объекту, либо используете os.path для получения размера. Этот вопрос уже обсуждался.

Но вы спрашиваете, как узнать размер файла на стороне клиента с сервера, прежде чем мы потратим время на его загрузку. Я думаю, что лучший способ сделать это — с помощью JavaScript. Этот вопрос может получить вы начали с того, как добавить код JavaScript в свое приложение BottlePy.

Используйте JavaScript для проверки ввода, чтобы в коде сервера можно было предположить, что файл находится в пределах ваших ограничений. Как только вы это выясните, я предлагаю вам попросить людей из BottlePy добавить поддержку этого непосредственно в поддержку BaseRequest.files.

person ChipJust    schedule 27.06.2012
comment
But you are asking about how to tell the client side file size from the server before we spend time uploading it. ‹-- правда? Я не помню, чтобы я это писал. вы можете изменить это поле на размер, который проходит проверку, и передать файл размером 1 ГБ, и что ..? - person holms; 27.06.2012
comment
О, может быть, я неправильно понял тогда. Я думал, вы хотите получить размер файла, не подвергая себя DDOS... может быть, я что-то предполагаю. Единственный способ сделать это — проверить размер файла перед его фактической загрузкой, иначе какой в ​​этом смысл. Большой файл уже загружен, так что вы не предотвратили DDOS. Другой вариант похож на то, что предлагает pyfunc, но вы добавляете проверку, чтобы выйти за пределы некоторого предела. Последний вариант, как вы предлагаете, и получить статистику по временному файлу. - person ChipJust; 27.06.2012
comment
@holms, вы можете изменить это поле на размер, который проходит проверку, и передать файл размером 1 ГБ, и что ..? Я не понимаю вашей точки зрения. Вы управляете кодом проверки на стороне клиента, поэтому вы можете разрешить любой размер, который хотите... - person ChipJust; 27.06.2012
comment
с каких это пор вы управляете КЛИЕНТСКИМ кодом?? откройте firebug и измените все, что хотите. - person holms; 27.06.2012
comment
DDOS - это не размер файла, который вы загрузили, я сомневаюсь, что кто-то попытается загрузить туда файл размером 500 ГБ смеется. это опасно, когда вы проверяете размер самого файла в python с помощью data.file.read(), потому что вам нужно сначала поместить весь файл в ОЗУ, а метод pyfunc с кусками кажется законным, после того, как размер куска достигнет предела, я могу прервать операцию и вернуться ошибка. даже в этом случае возможен DDOS с несколькими загрузками, но тогда я могу просто уменьшить лимит подключения. - person holms; 27.06.2012
comment
минус 1 за предложение бесполезной проверки на стороне клиента. - person Jonathon Reinhart; 27.04.2015