Как ограничить размер запроса Net :: HTTP? - PullRequest
4 голосов
/ 02 октября 2009

Я создаю службу API, которая позволяет людям предоставлять URL-адрес изображения для вызова API, и служба загружает изображение для обработки.

Как я могу гарантировать, что кто-то НЕ ДАЕТ мне URL-адрес изображения размером 5 МБ? Есть ли способ ограничить запрос?

Это то, что я имею до сих пор, что в основном захватывает все.

  req = Net::HTTP::Get.new(url.path)
  res = Net::HTTP.start(url.host, url.port) { |http|
    http.request(req)
  }

Спасибо, Конрад

Ответы [ 4 ]

6 голосов
/ 05 октября 2009

cwninja , к сожалению, дал вам ответ, который будет работать только для случайных атак.Интеллектуальный злоумышленник без проблем победит эту проверку.Есть две основные причины, по которым его метод не должен использоваться.Во-первых, ничто не гарантирует, что информация в ответе HEAD будет соответствовать соответствующему ответу GET.Правильно работающий сервер, безусловно, сделает это, но злоумышленник не должен следовать спецификации.Злоумышленник может просто отправить ответ HEAD, в котором говорится, что он имеет Content-Length, который меньше вашего порога, но затем передаст вам огромный файл в ответе GET.Но это даже не покрывает потенциальную возможность отправки сервером ответа с набором заголовков Transfer-Encoding: chunked.Частичный ответ вполне может никогда не закончиться.Несколько человек, указывающих вашему серверу на бесконечные ответы, могут проводить тривиальную атаку с исчерпанием ресурсов, даже если ваш HTTP-клиент применяет тайм-аут.

Чтобы сделать это правильно, вам необходимо использовать библиотеку HTTP, котораявам подсчитать байты по мере их получения и прервать, если он пересекает порог.Я, вероятно, рекомендую Curb для этого, а не Net :: HTTP.(Можно ли вообще сделать это с помощью Net :: HTTP?) Если вы используете обратные вызовы on_body и / или on_progress, вы можете подсчитать входящие байты и прервать промежуточный ответ, если получите слишком большой файл.Очевидно, как уже указывалось cwninja , если вы получаете заголовок Content-Length, превышающий пороговое значение, вы также хотите прервать его.Ограничение также заметно быстрее, чем Net :: HTTP .

2 голосов
/ 17 апреля 2018

Объединяя два других ответа, я бы хотел: 1) проверить размер заголовка, 2) посмотреть размер кусков, а также 3) с поддержкой https и 4) агрессивно применять тайм-аут. Вот помощник, который я придумал:

require "net/http"
require 'uri'

module FetchUtil
  # Fetch a URL, with a given max bytes, and a given timeout
  def self.fetch_url url, timeout_sec=5, max_bytes=5*1024*1024
    uri = URI.parse(url)

    t0 = Time.now.to_f
    body = ''
    Net::HTTP.start(uri.host, uri.port,
               :use_ssl => (uri.scheme == 'https'),
               :open_timeout => timeout_sec,
               :read_timeout => timeout_sec) { |http|

      # First make a HEAD request and check the content-length
      check_res = http.request_head(uri.path)
      raise "File too big" if check_res['content-length'].to_i > max_bytes

      # Then fetch in chunks and bail on either timeout or max_bytes
      # (Note: timeout won't work unless bytes are streaming in...)
      http.request_get(uri.path) do |res|
        res.read_body do |chunk|
          raise "Timeout error" if (Time.now().to_f-t0 > timeout_sec)
          raise "Filesize exceeded" if (body.length+chunk.length > max_bytes)
          body += chunk
        end
      end
    }
    return body
  end
end
2 голосов
/ 02 октября 2009

Попробуйте запустить это сначала:

Net::HTTP.start(url.host, url.port) { |http|
  response = http.request_head(url.path)
  raise "File too big." if response['content-length'].to_i > 5*1024*1024
}

У вас все еще есть состояние гонки (кто-то может поменять файл после того, как вы выполните запрос HEAD), но в простом случае сервер запрашивает заголовки, которые он отправит обратно из запроса GET.

1 голос
/ 05 мая 2017

Еще один способ ограничения размера загрузки (полный код должен проверять статус ответа, обработку исключений и т. Д. Это всего лишь пример)

Net::HTTP.start(uri.host, uri.port) do |http|
  request = Net::HTTP::Get.new uri.request_uri
  http.request request do |response|
# check response codes here
      body=''
      response.read_body do |chunk|
           body += chunk
           break if body.size > MY_SAFE_SIZE_LIMIT
      end
      break
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...