-
Notifications
You must be signed in to change notification settings - Fork 252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Secureheaders as rack middleware? #167
Comments
I'm not sure I understand. Did you mean to say rack middleware in a non-rails stack? CSP is set in the middleware in case script hashes are used. Can you describe your use case a little more in detail so I can provide a better answer? i.e. what about the current setup is not ideal? |
No, I mean rack middleware in a rails stack. I want to be absolutely sure that all HTTP responses pass through secureheaders so that secureheaders overrides any other settings. I'm fairly sure that requests handled by Rails Engines and api's built with Grape (i.e. things mounted in routes.rb) do not invoke the ActionController so 'ensure_security_headers' in application_controller.rb will not protect those responses. Maybe secureheaders will do what I want so seeing an example would help a lot. My google searches haven't turned up anything. |
👍 |
Ah, I see. Thank you for elaborating. I'm not sure how railties would be involved (I've used them exactly once in my life) but you can use the header classes directly in a middleware. That being said, ::SecureHeaders::Configuration.configure do |config|
config.hsts = {:max_age => 20.years.to_i, :include_subdomains => true}
config.x_frame_options = 'DENY'
config.x_content_type_options = "nosniff"
config.x_xss_protection = {:value => 1, :mode => 'block'}
config.x_download_options = 'noopen'
config.x_permitted_cross_domain_policies = 'none'
config.csp = {
:default_src => "https: self",
:enforce => true,
:frame_src => "https: http:.twimg.com http://itunes.apple.com",
:img_src => "https:",
:report_uri => '//example.com/uri-directive'
}
config.hpkp = {
:max_age => 60.days.to_i,
:include_subdomains => true,
:report_uri => '//example.com/uri-directive',
:pins => [
{:sha256 => 'abc'},
{:sha256 => '123'}
]
}
end
class MySecureHeaders
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
csp = SecureHeaders::ContentSecurityPolicy.new(::SecureHeaders::Configuration.csp)
headers[csp.name] = csp.value
hsts = SecureHeaders::StrictTransportSecurity.new(::SecureHeaders::Configuration.hsts)
headers[hsts.name] = hsts.value
x_xss = SecureHeaders::XXssProtection.new(::SecureHeaders::Configuration.x_xss_protection)
headers[x_xss.name] = x_xss.value
# ... set the remaining headers manually
[status, headers, [response.body]]
end
end
module Testapp
class Application < Rails::Application
config.middleware.use MySecureHeaders
end
end
PRs welcome! |
To be clear, I'd rather fix the code to support this use case rather than adding the above example to any README |
Perhaps a convenience method that returns a hash of all of the headers that can be merged into the rack headers. |
@rlwinter @TiagoCardoso1983 how does the above sound to you? Does it satisfy your use case with a satisfactory API? |
@oreoshake , anyway you do it, I think the cleanest way is to move your code away from rails and closer to the rack, as it concerns headers and stuff which is usually dealt with, this way you make this gem compatible with any rack framework. |
I disagree. Moving closer to rack yes, moving away from rails no. CSP is often not something that can be applied globally unless you want an overly permissive policy. That is why the proposal for adding this to rails core as a middleware has stalled out. Having convenience methods inside of controllers is very handy for one-off CSP config changes. Sure you can do this in rack too, but I'm not really a rack person and haven't really heard any concrete suggestions on how to make it more rack friendly. |
@oreoshake A convenience method returning a hash of headers would be perfect for building a rack app version of SecureHeaders. Then the call method would be: def call(env)
status, headers, response = @app.call(env)
# create or retrieve secure_headers hash here
secure_headers = ?
[status, headers.merge(secure_headers), [response.body]]
end
end I think the RailTies code led me off on a tangent since it explicitly deletes headers. |
@oreoshake I'm wondering about 2 items: one is that CSP might need to be split off from the secureheaders gem, since most of the secure headers are universal to an app, whereas CSP is specific to each HTTP response. The second is that the Asset Pipeline and views already have all the information needed to create the CSP header so what prevents generating the CSP headers from the pipeline? What am I missing? |
The asset pipeline does not have the necessary information to build a policy for any non-trivial application. For example, google analytics loads resources from two other domains. Twitter/facebook buttons do the same. The examples of this can go on and on, and sometime the host names are dynamic (yes I know this is terrible, but this is the internet). If you only serve JS from your domain (i.e. 'self`) then sure, it will work. Also, it would have to be able to detect instance of inline javascript and CSS. Not impossible, but probably very difficult. So there's already 4 ways to do "per response" ways of settings headers. This is horribly undocumented, however it is fully supported but is rails specific. Again, I'd love to make this more rack friendly but I need concrete input or a pull request.
Lastly, from my understanding grape is for API requests. Hardly anyone sets CSP on API requests because they aren't rendered (typically) and the policy is often longer than the body of the response (sometimes the policy is longer than all of the rest of the response combined). If so, ANY policy for an API should be |
I'll take a crack at the "return a hash of all headers" convenience method sometime soon. |
I took a stab at this: #168 |
Hey awesome! I read over the code changes - they look pretty good to me! Thanks, On Wed, Sep 23, 2015 at 6:20 PM, Neil Matatall [email protected]
|
Closed via #168 |
I'd like to insert secureheaders as a rack middleware app in a rails stack. I think I need an equivalent to the SecureHeaders::RailtIe code to override conflicting headers set elsewhere in the Rails code. Is this usage of Secureheaders supported by the current codebase?
The text was updated successfully, but these errors were encountered: