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.
attack prevented by RemoteToken
(with the logger preamble before it). – Urbanize