README.md in secure_headers-2.5.3 vs README.md in secure_headers-3.0.0.pre
- old
+ new
@@ -1,254 +1,201 @@
# SecureHeaders [![Build Status](https://travis-ci.org/twitter/secureheaders.png?branch=master)](http://travis-ci.org/twitter/secureheaders) [![Code Climate](https://codeclimate.com/github/twitter/secureheaders.png)](https://codeclimate.com/github/twitter/secureheaders) [![Coverage Status](https://coveralls.io/repos/twitter/secureheaders/badge.png)](https://coveralls.io/r/twitter/secureheaders)
+**The 3.x branch was recently merged**. See the [upgrading to 3.x doc](upgrading-to-3-0.md) for instructions on how to upgrade including the differences and benefits of using the 3.x branch.
+
+**The [2.x branch](https://github.com/twitter/secureheaders/tree/2.x) will be maintained**. The documentation below only applies to the 2.x branch. See the 2.x [README](https://github.com/twitter/secureheaders/blob/2.x/README.md) for the old way of doing things.
+
The gem will automatically apply several headers that are related to security. This includes:
- Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](http://www.w3.org/TR/CSP2/)
- HTTP Strict Transport Security (HSTS) - Ensures the browser never visits the http version of a website. Protects from SSLStrip/Firesheep attacks. [HSTS Specification](https://tools.ietf.org/html/rfc6797)
- X-Frame-Options (XFO) - Prevents your content from being framed and potentially clickjacked. [X-Frame-Options draft](https://tools.ietf.org/html/draft-ietf-websec-x-frame-options-02)
- X-XSS-Protection - [Cross site scripting heuristic filter for IE/Chrome](http://msdn.microsoft.com/en-us/library/dd565647\(v=vs.85\).aspx)
- X-Content-Type-Options - [Prevent content type sniffing](http://msdn.microsoft.com/en-us/library/ie/gg622941\(v=vs.85\).aspx)
- X-Download-Options - [Prevent file downloads opening](http://msdn.microsoft.com/en-us/library/ie/jj542450(v=vs.85).aspx)
- X-Permitted-Cross-Domain-Policies - [Restrict Adobe Flash Player's access to data](https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html)
-- Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorities. [Public Key Pinning Specification](https://tools.ietf.org/html/rfc7469)
+- Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorities. [Public Key Pinning Specification](https://tools.ietf.org/html/rfc7469)
-## Usage
+`secure_headers` is a library with a global config, per request overrides, and rack milddleware that enables you customize your application settings.
-- `ensure_security_headers` in a controller will set security-related headers automatically based on the configuration below.
-
-### Disabling
-
-Use the standard `skip_before_filter :filter_name, options` mechanism. e.g. `skip_before_filter :set_csp_header, :only => :tinymce_page`
-
-The following methods are going to be called, unless they are provided in a `skip_before_filter` block.
-
-* `:set_csp_header`
-* `:set_hsts_header`
-* `:set_hpkp_header`
-* `:set_x_frame_options_header`
-* `:set_x_xss_protection_header`
-* `:set_x_content_type_options_header`
-* `:set_x_download_options_header`
-* `:set_x_permitted_cross_domain_policies_header`
-
## Configuration
-**Place the following in an initializer (recommended):**
+If you do not supply a `default` configuration, exceptions will be raised. If you would like to use a default configuration (which is fairly locked down), just call `SecureHeaders::Configuration.default` without any arguments or block.
-**NOTE: All CSP config values accept procs for one way of dynamically setting values**
+All `nil` values will fallback to their default value. `SecureHeaders::OPT_OUT` will disable the header entirely.
```ruby
-::SecureHeaders::Configuration.configure do |config|
- config.hsts = {:max_age => 20.years.to_i, :include_subdomains => true}
- config.x_frame_options = 'DENY'
+SecureHeaders::Configuration.default do |config|
+ config.hsts = 20.years.to_i.to_s
+ 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.x_xss_protection = "1; mode=block"
+ config.x_download_options = "noopen"
+ config.x_permitted_cross_domain_policies = "none"
config.csp = {
- :default_src => "https: 'self'",
- :enforce => proc {|controller| controller.my_feature_flag_api.enabled? },
- :frame_src => "https: http:.twimg.com http://itunes.apple.com",
- :img_src => "https:",
- :connect_src => "wws:",
- :font_src => "'self' data:",
- :frame_src => "'self'",
- :img_src => "mycdn.com data:",
- :media_src => "utoob.com",
- :object_src => "'self'",
- :script_src => "'self'",
- :style_src => "'unsafe-inline'",
- :base_uri => "'self'",
- :child_src => "'self'",
- :form_action => "'self' github.com",
- :frame_ancestors => "'none'",
- :plugin_types => 'application/x-shockwave-flash',
- :block_all_mixed_content => '', # see [http://www.w3.org/TR/mixed-content/]()
- :report_uri => '//example.com/uri-directive'
+ default_src: %w(https: 'self'),
+ report_only: false,
+ frame_src: %w(*.twimg.com itunes.apple.com),
+ connect_src: %w(wws:),
+ font_src: %w('self' data:),
+ frame_src: %w('self'),
+ img_src: %w(mycdn.com data:),
+ media_src: %w(utoob.com),
+ object_src: %w('self'),
+ script_src: %w('self'),
+ style_src: %w('unsafe-inline'),
+ base_uri: %w('self'),
+ child_src: %w('self'),
+ form_action: %w('self' github.com),
+ frame_ancestors: %w('none'),
+ plugin_types: %w(application/x-shockwave-flash),
+ block_all_mixed_content: true, # see [http://www.w3.org/TR/mixed-content/](http://www.w3.org/TR/mixed-content/)
+ report_uri: %w(https://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'}
+ report_only: false,
+ max_age: 60.days.to_i,
+ include_subdomains: true,
+ report_uri: "https://example.com/uri-directive",
+ pins: [
+ {sha256: "abc"},
+ {sha256: "123"}
]
}
end
-
-# and then include this in application_controller.rb
-class ApplicationController < ActionController::Base
- ensure_security_headers
-end
```
-Or do the config as a parameter to `ensure_security_headers`
+### rails 2
+For rails 3+ applications, `secure_headers` has a `railtie` that should automatically include the middleware. For rails 2 applications, an explicit statement is required to use the middleware component.
+
```ruby
-ensure_security_headers(
- :hsts => {:include_subdomains => true, :max_age => 20.years.to_i},
- :x_frame_options => 'DENY',
- :csp => false
-)
+use SecureHeaders::Middleware
```
-## Per-action configuration
+## Default values
-Sometimes you need to override your content security policy for a given endpoint. Rather than applying the exception globally, you have a few options:
+All headers except for PublicKeyPins have a default value. See the [corresponding classes for their defaults](https://github.com/twitter/secureheaders/tree/master/lib/secure_headers/headers).
-1. Use procs as config values as mentioned above.
-1. Specifying `ensure_security_headers csp: ::SecureHeaders::Configuration.csp.merge(script_src: shadyhost.com)` in a descendent controller will override the settings for that controller only.
-1. Override the `secure_header_options_for` class instance method. e.g.
+## Named overrides
+Named overrides serve two purposes:
+
+* To be able to refer to a configuration by simple name.
+* By precomputing the headers for a named configuration, the headers generated once and reused over every request.
+
+To use a named override, drop a `SecureHeaders::Configuration.override` block **outside** of method definitions and then declare which named override you'd like to use. You can even override an override.
+
```ruby
-class SomethingController < ApplicationController
- def wumbus
- # gets style-src override
+class ApplicationController < ActionController::Base
+ SecureHeaders::Configuration.default do |config|
+ config.csp = {
+ default_src: %w('self'),
+ script_src: %w(example.org)
+ }
end
- def diffendoofer
- # does not get style-src override
+ # override default configuration
+ SecureHeaders::Configuration.override(:script_from_otherdomain_com) do |config|
+ config.csp[:script_src] << "otherdomain.com"
end
- def secure_header_options_for(header, options)
- options = super
- if params[:action] == "wumbus"
- if header == :csp
- options.merge(style_src: "'self'")
- end
- else
- options
- end
+ # overrides the :script_from_otherdomain_com configuration
+ SecureHeaders::Configuration.override(:another_config, :script_from_otherdomain_com) do |config|
+ config.csp[:script_src] << "evenanotherdomain.com"
end
end
-```
-## Options for ensure\_security\_headers
+class MyController < ApplicationController
+ def index
+ # Produces default-src 'self'; script-src example.org otherdomain.org
+ use_secure_headers_override(:script_from_otherdomain_com)
+ end
-**To disable any of these headers, supply a value of false (e.g. :hsts => false), supplying nil will set the default value**
+ def show
+ # Produces default-src 'self'; script-src example.org otherdomain.org evenanotherdomain.com
+ use_secure_headers_override(:another_config)
+ end
+end
+```
-Each header configuration can take a hash, or a string, or both. If a string
-is provided, that value is inserted verbatim. If a hash is supplied, a
-header will be constructed using the supplied options.
+By default, a noop configuration is provided. No headers will be set when this default override is used.
-### The Easy Headers
-
-This configuration will likely work for most applications without modification.
-
```ruby
-:hsts => {:max_age => 631138519, :include_subdomains => false}
-:x_frame_options => {:value => 'SAMEORIGIN'}
-:x_xss_protection => {:value => 1, :mode => 'block'} # set the :mode option to false to use "warning only" mode
-:x_content_type_options => {:value => 'nosniff'}
-:x_download_options => {:value => 'noopen'}
-:x_permitted_cross_domain_policies => {:value => 'none'}
+class MyController < ApplicationController
+ def index
+ SecureHeaders::opt_out_of_all_protection(request)
+ end
+end
```
-### Content Security Policy (CSP)
+## Per-action configuration
+You can override the settings for a given action by producing a temporary override. This approach is not recommended because the header values will be computed per request.
+
```ruby
-:csp => {
- :enforce => false, # sets header to report-only, by default
- # default_src is required!
- :default_src => nil, # sets the default-src/allow+options directives
+# Given a config of:
+::SecureHeaders::Configuration.default do |config|
+ config.csp = {
+ default_src: %w('self'),
+ script_src: %w('self')
+ }
+ end
- # Where reports are sent. Use protocol relative URLs if you are posting to the same domain (TLD+1). Use paths if you are posting to the application serving the header
- :report_uri => '//mysite.example.com',
+class MyController < ApplicationController
+ def index
+ # Append value to the source list, override 'none' values
+ # Produces: default-src 'self'; script-src 'self' s3.amazaonaws.com; object-src 'self' youtube.com
+ append_content_security_policy_directives(script_src: %w(s3.amazaonaws.com), object_src: %w('self' youtube.com))
- # these directives all take 'none', 'self', or a globbed pattern
- :img_src => nil,
- :frame_src => nil,
- :connect_src => nil,
- :font_src => nil,
- :media_src => nil,
- :object_src => nil,
- :style_src => nil,
- :script_src => nil,
+ # Overrides the previously set source list, override 'none' values
+ # Produces: default-src 'self'; script-src s3.amazaonaws.com; object-src 'self'
+ override_content_security_policy_directive(script_src: %w(s3.amazaonaws.com), object_src: %w('self'))
- # http additions will be appended to the various directives when
- # over http, relaxing the policy
- # e.g.
- # :csp => {
- # :img_src => 'https:',
- # :http_additions => {:img_src => 'http'}
- # }
- # would produce the directive: "img-src https: http:;"
- # when over http, ignored for https requests
- :http_additions => {}
-}
+ # Global settings default to "sameorigin"
+ override_x_frame_options("DENY")
+ end
```
-### Example CSP header config
+The following methods are available as controller instance methods. They are also available as class methods, but require you to pass in the `request` object.
+* `append_content_security_policy_directives(hash)`: appends each value to the corresponding CSP app-wide configuration.
+* `override_content_security_policy_directive(hash)`: merges the hash into the app-wide configuration, overwriting any previous config
+* `override_x_frame_options(value)`: sets the `X-Frame-Options header` to `value`
+## Appending / overriding Content Security Policy
-```ruby
-# most basic example
-:csp => {
- :default_src => "https: 'unsafe-inline' 'unsafe-eval'",
- :report_uri => '/uri-directive'
-}
+When manipulating content security policy, there are a few things to consider. The default header value is `default-src https:` which corresponds to a default configuration of `{ default_src: %w(https:)}`.
-> "default-src 'unsafe-inline' 'unsafe-eval' https:; report-uri /uri-directive;"
+#### Append to the policy with a directive other than `default_src`
-# turn off inline scripting/eval
-:csp => {
- :default_src => 'https:',
- :report_uri => '/uri-directive'
-}
+The value of `default_src` is joined with the addition. Note the `https:` is carried over from the `default-src` config. If you do not want this, use `override_content_security_policy_directives` instead. To illustrate:
-> "default-src https:; report-uri /uri-directive;"
-
-# Auction site wants to allow images from anywhere, plugin content from a list of trusted media providers (including a content distribution network), and scripts only from its server hosting sanitized JavaScript
-:csp => {
- :default_src => "'self'",
- :img_src => '*',
- :object_src => ['media1.com', 'media2.com', '*.cdn.com'],
- # alternatively (NOT csv) :object_src => 'media1.com media2.com *.cdn.com'
- :script_src => 'trustedscripts.example.com'
-}
-"default-src 'self'; img-src *; object-src media1.com media2.com *.cdn.com; script-src trustedscripts.example.com;"
-```
-
-### Tagging Requests
-
-It's often valuable to send extra information in the report uri that is not available in the reports themselves. Namely, "was the policy enforced" and "where did the report come from"
-
```ruby
-{
- :tag_report_uri => true,
- :enforce => true,
- :app_name => 'twitter',
- :report_uri => 'csp_reports'
-}
-```
+::SecureHeaders::Configuration.configure do |config|
+ config.csp = {
+ default_src: %w('self')
+ }
+ end
+ ```
-Results in
-```
-report-uri csp_reports?enforce=true&app_name=twitter
-```
+Code | Result
+------------- | -------------
+`append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src 'self' mycdn.com`
+`override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src mycdn.com`
-### CSP Level 2 features
+Code | Result
+------------- | -------------
+`append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src https:; script-src https: mycdn.com`
+`override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src https:; script-src mycdn.com`
-*NOTE: Currently, only erb is supported. Mustache support isn't far off. Hash sources are valid for inline style blocks but are not yet supported by secure_headers.*
-
#### Nonce
-script/style-nonce can be used to whitelist inline content. To do this, add "nonce" to your script/style-src configuration, then set the nonce attributes on the various tags.
+script/style-nonce can be used to whitelist inline content. To do this, call the SecureHeaders::content_security_policy_nonce then set the nonce attributes on the various tags.
Setting a nonce will also set 'unsafe-inline' for browsers that don't support nonces for backwards compatibility. 'unsafe-inline' is ignored if a nonce is present in a directive in compliant browsers.
-```ruby
-:csp => {
- :default_src => "'self'",
- :script_src => "'self' nonce"
-}
-```
-
-> content-security-policy: default-src 'self'; script-src 'self' 'nonce-abc123' 'unsafe-inline'
-
```erb
-<script nonce="<%= @content_security_policy_nonce %>">
+<script nonce="<%= content_security_policy_nonce %>">
console.log("whitelisted, will execute")
</script>
<script nonce="lol">
console.log("won't execute, not whitelisted")
@@ -256,117 +203,56 @@
<script>
console.log("won't execute, not whitelisted")
</script>
```
+
You can use a view helper to automatically add nonces to script tags:
+
```erb
<%= nonced_javascript_tag do %>
- console.log("nonced!")
+console.log("hai");
<% end %>
-<%= nonced_javascript_tag("nonced without a block!") %>
+
+<%= nonced_style_tag do %>
+body {
+ background-color: black;
+}
+<% end %>
```
becomes:
```html
<script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
console.log("nonced!")
</script>
+<style nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">
+body {
+ background-color: black;
+}
+</style>
```
#### Hash
-setting hash source values will also set 'unsafe-inline' for browsers that don't support hash sources for backwards compatibility. 'unsafe-inline' is ignored if a hash is present in a directive in compliant browsers.
+The hash feature has been removed, for now.
-Hash source support works by taking the hash value of the contents of an inline script block and adding the hash "fingerprint" to the CSP header.
-
-If you only have a few hashes, you can hardcode them for the entire app:
-
-```ruby
- config.csp = {
- :default_src => "https:",
- :script_src => "'self'"
- :script_hashes => ['sha1-abc', 'sha1-qwe']
- }
-```
-
-The following will work as well, but may not be as clear:
-
-```ruby
- config.csp = {
- :default_src => "https:",
- :script_src => "'self' 'sha1-qwe'"
- }
-```
-
-If you find you have many hashes or the content of the script tags change frequently, you can apply these hashes in a more intelligent way. This method expects config/script_hashes.yml to contain a map of templates => [hashes]. When the individual templates, layouts, or partials are rendered the hash values for the script tags in those templates will be automatically added to the header. *Currently, only erb layouts are supported.* This requires the use of middleware:
-
-```ruby
-# config.ru
-require 'secure_headers/headers/content_security_policy/script_hash_middleware'
-use ::SecureHeaders::ContentSecurityPolicy::ScriptHashMiddleware
-```
-
-```ruby
- config.csp = {
- :default_src => "https:",
- :script_src => "'self'",
- :script_hash_middleware => true
- }
-```
-
-Hashes are stored in a yaml file with a mapping of Filename => [list of hashes] in config/script_hashes.yml. You can automatically populate this file by running the following rake task:
-
-```$ bundle exec rake secure_headers:generate_hashes```
-
-Which will generate something like:
-
-```yaml
-# config/script_hashes.yml
-app/views/layouts/application.html.erb:
-- sha256-l8OLjZqYRnKilpdE0VosRMvhdYArjXT4NZaK2p7QVvs=
-app/templates/articles/edit.html.erb:
-- sha256-+7mij1/uCwtCQRWrof2NmOln5qX+5WdVwTLMpi8nuoA=
-- sha256-Ny4TRIhhFpnYnSeKC274P6bfAz4TOkezLabavIAU4dA=
-- sha256-I5e58Gqbu4WpO9dck18QxO7aYOHKrELIi70it4jIPi0=
-- sha256-Po4LMynwnAJHxiTp3DQaQ3YDBj3paN/xrDoKl4OyxY4=
-```
-
-In this example, if we visit /articles/edit/[id], the above hashes will automatically be added to the CSP header's
-script-src value!
-
-You can use plain "script" tags or you can use a built-in helper:
-
-```erb
-<%= hashed_javascript_tag do %>
-console.log("hashed automatically!")
-<% end %>
-```
-
-By using the helper, hash values will be computed dynamically in development/test environments. If a dynamically computed hash value does not match what is expected to be found in config/script_hashes.yml a warning message will be printed to the console. If you want to raise exceptions instead, use:
-
-```erb
-<%= hashed_javascript_tag(raise_error_on_unrecognized_hash = true) do %>
-console.log("will raise an exception if not in script_hashes.yml!")
-<% end %>
-```
-
### Public Key Pins
Be aware that pinning error reporting is governed by the same rules as everything else. If you have a pinning failure that tries to report back to the same origin, by definition this will not work.
-```
+```ruby
config.hpkp = {
max_age: 60.days.to_i, # max_age is a required parameter
include_subdomains: true, # whether or not to apply pins to subdomains
# Per the spec, SHA256 hashes are the only currently supported format.
pins: [
{sha256: 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c'},
{sha256: '73a2c64f9545172c1195efb6616ca5f7afd1df6f245407cafb90de3998a1c97f'}
],
- enforce: true, # defaults to false (report-only mode)
+ report_only: true, # defaults to false (report-only mode)
report_uri: '//example.com/uri-directive',
app_name: 'example',
tag_report_uri: true
}
```
@@ -379,32 +265,21 @@
require 'rubygems'
require 'sinatra'
require 'haml'
require 'secure_headers'
-::SecureHeaders::Configuration.configure do |config|
- config.hsts = {:max_age => 99, :include_subdomains => true}
- config.x_frame_options = 'DENY'
- config.x_content_type_options = "nosniff"
- config.x_xss_protection = {:value => 1, :mode => false}
- config.x_download_options = 'noopen'
- config.x_permitted_cross_domain_policies = 'none'
- config.csp = {
- :default_src => "https: inline eval",
- :report_uri => '//example.com/uri-directive',
- :img_src => "https: data:",
- :frame_src => "https: http:.twimg.com http://itunes.apple.com"
- }
- config.hpkp = false
+use SecureHeaders::Middleware
+
+SecureHeaders::Configuration.configure do |config|
+ ...
end
class Donkey < Sinatra::Application
- include SecureHeaders
set :root, APP_ROOT
get '/' do
- set_csp_header
+ SecureHeaders.override_x_frame_options(SecureHeaders::OPT_OUT)
haml :index
end
end
```
@@ -413,100 +288,48 @@
You can use SecureHeaders for Padrino applications as well:
In your `Gemfile`:
```ruby
- gem "secure_headers", :require => 'secure_headers'
+ gem "secure_headers", require: 'secure_headers'
```
then in your `app.rb` file you can:
```ruby
+Padrino.use(SecureHeaders::Middleware)
require 'secure_headers/padrino'
module Web
class App < Padrino::Application
register SecureHeaders::Padrino
get '/' do
- set_csp_header
render 'index'
end
end
end
```
and in `config/boot.rb`:
```ruby
def before_load
- ::SecureHeaders::Configuration.configure do |config|
- config.hsts = {:max_age => 99, :include_subdomains => true}
- config.x_frame_options = 'DENY'
- config.x_content_type_options = "nosniff"
- config.x_xss_protection = {:value => '1', :mode => false}
- config.x_download_options = 'noopen'
- config.x_permitted_cross_domain_policies = 'none'
- config.csp = {
- :default_src => "https: inline eval",
- :report_uri => '//example.com/uri-directive',
- :img_src => "https: data:",
- :frame_src => "https: http:.twimg.com http://itunes.apple.com"
- }
+ SecureHeaders::Configuration.configure do |config|
+ ...
end
end
```
-### Using in rack middleware
-
-The `SecureHeaders::header_hash` generates a hash of all header values, which is useful for merging with rack middleware values.
-
-```ruby
-class MySecureHeaders
- include SecureHeaders
- def initialize(app)
- @app = app
- end
-
- def call(env)
- status, headers, response = @app.call(env)
- security_headers = if override?
- SecureHeaders::header_hash(:csp => false) # uses global config, but overrides CSP config
- else
- SecureHeaders::header_hash # uses global config
- end
- [status, headers.merge(security_headers), [response.body]]
- end
-end
-
-module Testapp
- class Application < Rails::Application
- config.middleware.use MySecureHeaders
- end
-end
-```
-
## Similar libraries
* Rack [rack-secure_headers](https://github.com/harmoni/rack-secure_headers)
* Node.js (express) [helmet](https://github.com/evilpacket/helmet) and [hood](https://github.com/seanmonstar/hood)
* Node.js (hapi) [blankie](https://github.com/nlf/blankie)
* J2EE Servlet >= 3.0 [headlines](https://github.com/sourceclear/headlines)
* ASP.NET - [NWebsec](https://github.com/NWebsec/NWebsec/wiki)
* Python - [django-csp](https://github.com/mozilla/django-csp) + [commonware](https://github.com/jsocol/commonware/); [django-security](https://github.com/sdelements/django-security)
* Go - [secureheader](https://github.com/kr/secureheader)
-
-## Authors
-
-* Neil Matatall [@ndm](https://twitter.com/ndm) - primary author.
-* Nicholas Green [@nickgreen](https://twitter.com/nickgreen) - code contributions, main reviewer.
-
-## Acknowledgements
-
-* Justin Collins [@presidentbeef](https://twitter.com/presidentbeef) & Jim O'Leary [@jimio](https://twitter.com/jimio) for reviews.
-* Ian Melven [@imelven](https://twitter.com/imelven) - Discussions/info about CSP in general, made us aware of the [userCSP](https://addons.mozilla.org/en-US/firefox/addon/newusercspdesign/) Mozilla extension.
-* Sumit Shah [@omnidactyl](https://twitter.com/omnidactyl) - For being an eager guinea pig.
-* Chris Aniszczyk [@cra](https://twitter.com/cra) - For running an awesome open source program at Twitter.
## License
Copyright 2013-2014 Twitter, Inc and other contributors.