17

我正在使用 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 上的新 Rack 保护所烧伤,这让我有些悲痛……任何人都有一个很好的指导,可以在这里做什么?我这么说的原因是,突然间我看到日志条目带有会话劫持问题的警报(几乎可以肯定是因为应用程序运行 > 1 Dyno)。我在我的 Gemfile.lock 中看到 rack-protection (1.2.0),即使我从来没有要求它......我的清单中的某些东西正在调用它,所以它被加载了,但我的 Sinatra 应用程序中没有任何东西试图要求它或设置它。

4

5 回答 5

19

在您的 Sinatra 应用程序中使用它应该可以解决您的问题:

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

更好的解决方案可能是将 Sinatra 升级到 1.4,它使用 Rack::Protection 1.5,不会导致您看到的问题。

问题是当您使用 Content-Type: application/json 响应时,您的 in 版本与CORSRackProtection::JsonCsrf不兼容。这是机架保护中旧 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您可以看到,当引用者与服务器不是来自同一主机时,这会拒绝具有响应的请求。

这个问题在更高版本的 rack-protection 中得到了解决,它现在考虑请求是否是 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::AuthenticityTokenRack::Protection::FormTokenRack::Protection::RemoteReferrer,并且Rack::Protection::EscapedParams必须显式添加)。

Sinatra 使用 Rack::Protection 的默认设置,但有一个例外:它只添加SessionHijacking并且RemoteToken启用会话。

最后,如果您尝试将 CORS 与 Sinatra 一起使用,您可以尝试rack-cors,它会为您处理很多细节。

于 2013-04-20T21:20:16.397 回答
4

如果您看到此问题,说明您没有使用 CORS(跨域资源共享),并且位于反向代理(例如 nginx 或 apache)后面,请确保您的反向代理没有剥离host标头并替换它与本地主机。

例如,在 nginx 中,您需要使用proxy_set_header

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

当从请求中删除标头时,Rack::Protection 认为这是一次 CSRF 攻击。

于 2016-02-26T03:57:42.213 回答
3

让我猜猜,您正在使用 Chrome 应用程序“Dev HTTP Client”进行测试?试试这个:

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's !"
  end

您可能想知道chrome-extension://aejoelaoggembcahagimdiliamlcdmfm吗?嗯,这就是当您使用 Chrome 应用程序发送 POST 请求时机架保护获得的env['HTTP_ORIGIN'] 。

于 2013-01-26T00:04:36.047 回答
1

这是因为您没有在选项路线中返回允许的方法吗?

这里的一个问题是指它,它记录了允许的方法。

此处的扩展和此处的中间件可能会对您有所帮助。

于 2012-05-10T02:11:48.010 回答
1

rack-protection 允许从 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

于 2017-09-25T16:41:00.053 回答