Настройка Sinatra и Rack Protection

Я использую Sinatra и CORS, чтобы принять загрузку файла в домене A (hefty.burger.com). Домен B (fizzbuzz.com) имеет форму, которая загружает файл в маршрут на A.

У меня есть маршрут опций и почтовый маршрут, оба с именем '/uploader'.

options '/uploader' do
  headers 'Access-Control-Allow-Origin' => 'http://fizz.buzz.com',
  'Access-Control-Allow-Methods' => 'POST'
  200
end 

post '/uploader' do
  ... 
  content_type :json
  [{:mary => 'little lamb'}].to_json
end

Параметры сначала попадают... и это работает.. тогда сообщение получает удар и возвращает 403.

Если я отключу защиту, почта работает... какую защиту мне нужно исключить из списка для поддержки защиты, но разрешить эти сообщения через?

Я только недавно был сожжен новой защитой стойки, носящей на Heroku и причиняющей мне некоторую скорбь... у кого есть хороший указатель на то, что здесь делать? Причина, по которой я говорю это, внезапно я вижу записи журнала с предупреждениями о проблемах с захватом сессии (почти наверняка из-за ничего, кроме запускa > 1 Dyno для приложения). Я вижу стойку-защиту (1.2.0) в своем Gemfile.lock, хотя я никогда не просил об этом... что-то в моем манифесте вызывает его, поэтому оно загружено, но ничто в моем приложении Sinatra даже не пытается его потребовать или настроить его.

Ответы

Ответ 1

Использование этого в приложении Sinatra должно решить вашу проблему:

set :protection, :except => [:json_csrf]

Лучшим решением может стать обновление Sinatra до 1.4, в котором используется Rack:: Protection 1.5 и не должно вызывать проблему, которую вы видите.

Проблема в том, что ваша версия RackProtection::JsonCsrf in несовместима с CORS, когда вы отвечаете с Content-Type: application/json. Вот фрагмент из старого json_csrf.rb в стойке:

def call(env)
  status, headers, body = app.call(env)
  if headers['Content-Type'].to_s.split(';', 2).first =~ /^\s*application\/json\s*$/
    if referrer(env) != Request.new(env).host
      result = react(env)
      warn env, "attack prevented by #{self.class}"
    end
  end
  result or [status, headers, body]
end

Вы можете видеть, что это отклоняет запросы, у которых есть ответ application/json, когда реферер не с того же хоста, что и сервер.

Эта проблема была решена в более поздней версии стойкой защиты, которая теперь рассматривает вопрос о том, является ли запрос XMLHttpRequest:

   def has_vector?(request, headers)
    return false if request.xhr?
    return false unless headers['Content-Type'].to_s.split(';', 2).first =~ /^\s*application\/json\s*$/
    origin(request.env).nil? and referrer(request.env) != request.host
  end

Если вы используете Sinatra 1.3.2 и не можете обновить решение, отключите эту конкретную защиту. С помощью CORS вы явно разрешаете междоменные запросы XHR. Sinatra позволяет полностью отключить защиту или отключить определенные компоненты Rack::Protection (см. "Настройка защиты от атак" в документах Sinatra).

Rack::Protection предоставляет 12 промежуточных компонентов, которые помогают поражение общих атак:

  • Rack::Protection::AuthenticityToken
  • Rack::Protection::EscapedParams
  • Rack::Protection::FormToken
  • Rack::Protection::FrameOptions
  • Rack::Protection::HttpOrigin
  • Rack::Protection::IPSpoofing
  • Rack::Protection::JsonCsrf
  • Rack::Protection::PathTraversal
  • Rack::Protection::RemoteReferrer
  • Rack::Protection::RemoteToken
  • Rack::Protection::SessionHijacking
  • Rack::Protection::XssHeader

Во время записи все, кроме четырех, загружаются автоматически, когда вы используете промежуточное ПО Rack:: Protection (Rack::Protection::AuthenticityToken, Rack::Protection::FormToken, Rack::Protection::RemoteReferrer и Rack::Protection::EscapedParams должны быть добавлены явно).

Sinatra использует настройки Rack:: Protection по умолчанию с одно исключение: оно добавляет только SessionHijacking и RemoteToken, если вы включаете сеансы.

И, наконец, если вы пытаетесь использовать CORS с Sinatra, вы можете попробовать rack-cors, который заботится о многом детали для вас.

Ответ 2

Предположим, вы тестируете приложение "Dev HTTP Client" для Chrome? Вместо этого попробуйте:

curl -v -X POST http://fizz.buzz.com/uploader

Из модуля защиты стойки: "Поддерживаемые браузеры:: Google Chrome 2, Safari 4 и более поздние версии"

Это должно работать:

class App < Sinatra::Base
  ...
  enable :protection
  use Rack::Protection, except: :http_origin
  use Rack::Protection::HttpOrigin, origin_whitelist: ["chrome-extension://aejoelaoggembcahagimdiliamlcdmfm", "http://fizz.buzz.com"]

  post '/uploader' do
    headers \
      'Allow'   => 'POST',
      'Access-Control-Allow-Origin' => 'http://fizz.buzz.com'
    body "it work !"
  end

Вероятно, вы задаетесь вопросом о chrome-extension://aejoelaoggembcahagimdiliamlcdmfm? Хорошо, что защита стойки получает как env ['HTTP_ORIGIN'] при отправке запроса POST с приложением Chrome.

Ответ 3

Если вы заметили эту проблему, вы не используете CORS (совместное использование ресурсов Cross-origin) и находитесь за обратным прокси-сервером (например, nginx или apache), убедитесь, что ваш обратный прокси не отключен host и заменить его на localhost.

Например, в nginx вам нужно использовать proxy_set_header:

location / {
    proxy_pass http://localhost:9296;
    proxy_set_header Host $host;
}

Когда заголовок удаляется из запроса, Rack:: Protection считает его атакой CSRF.

Ответ 4

Это потому, что вы не возвращаете разрешенные методы обратно в маршрут опций?

Вопрос здесь относится к нему, который отмечает возвращенные методы.

Расширение здесь и промежуточное ПО здесь может помогите вам.