Sinatra and Rack Protection setting

后端 未结 5 589
[愿得一人]
[愿得一人] 2020-12-16 14:16

I am using Sinatra and CORS to accept a file upload on domain A (hefty.burger.com). Domain B (fizzbuzz.com) has a form that uploads a file to a route on A.

I have a

相关标签:
5条回答
  • 2020-12-16 14:22

    Is this because you are not returning the allowed methods back in your options route?

    A question here refers to it which notes the allowed methods back.

    An extension here and middleware here might help you out.

    0 讨论(0)
  • 2020-12-16 14:26

    rack-protection allows to specify a custom check starting from 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

    0 讨论(0)
  • 2020-12-16 14:35

    Using this in your Sinatra app should solve your problem:

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

    A better solution may be to upgrade Sinatra to 1.4, which uses Rack::Protection 1.5 and should not cause the problem you are seeing.

    The problem is that your version of RackProtection::JsonCsrf in is incompatible with CORS when you respond with Content-Type: application/json. Here is a snippet from the old json_csrf.rb in rack-protection:

    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
    

    You can see this rejects requests that have an application/json response when the referrer is not from the same host as the server.

    This problem was solved in a later version of rack-protection, which now considers whether the request is an 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
    

    If you are using Sinatra 1.3.2 and cannot upgrade the solution is to disable this particular protection. With CORS you are explicitly enabling cross-domain XHR requests. Sinatra lets you disable protection entirely, or disable specific components of Rack::Protection (see "Configuring Attack Protection" in the Sinatra docs).

    Rack::Protection provides 12 middleware components that help defeat common attacks:

    • 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

    At time of writing, all but four of these are loaded automatically when you use the Rack::Protection middleware (Rack::Protection::AuthenticityToken, Rack::Protection::FormToken, Rack::Protection::RemoteReferrer, and Rack::Protection::EscapedParams must be added explicitly).

    Sinatra uses Rack::Protection's default settings with one exception: it only adds SessionHijacking and RemoteToken if you enable sessions.

    And, finally, if you are trying to use CORS with Sinatra, you might try rack-cors, which takes care of a lot of the details for you.

    0 讨论(0)
  • 2020-12-16 14:39

    If you see this issue, you are not using CORS (Cross-origin resource sharing), and are behind a reverse-proxy (such as nginx or apache), make sure that your reverse-proxy isn't stripping out host header and replacing it with localhost.

    For example, in nginx you need to use proxy_set_header:

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

    When the header is stripped out from a request, Rack::Protection believes it to be a CSRF attack.

    0 讨论(0)
  • Let me guess, you're testing with the Chrome app 'Dev HTTP Client' ? Try this instead:

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

    From the rack protection module: "Supported browsers:: Google Chrome 2, Safari 4 and later"

    This should work:

    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
    

    You probably wonder about chrome-extension://aejoelaoggembcahagimdiliamlcdmfm ? Well, that's what the rack protection gets as env['HTTP_ORIGIN'] when you send a POST request with the Chrome app.

    0 讨论(0)
提交回复
热议问题