Настройка 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
Это потому, что вы не возвращаете разрешенные методы обратно в маршрут опций?
Вопрос здесь относится к нему, который отмечает возвращенные методы.
Расширение здесь и промежуточное ПО здесь может помогите вам.
Ответ 5
стойка-защита позволяет указать пользовательскую проверку, начиная с 2.0.0:
set :protection, :allow_if => lambda{ |env| env['HTTP_REFERER'] && URI(env['HTTP_REFERER']).host == 'fizz.buzz.com' }
https://github.com/sinatra/sinatra/blob/a2fe3e698b19ac4065f166f1727afd31d0e72f95/rack-protection/lib/rack/protection/json_csrf.rb#L39