secure_headers 2.5.3 → 3.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of secure_headers might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.travis.yml +2 -1
- data/Gemfile +9 -16
- data/README.md +154 -331
- data/Rakefile +2 -36
- data/lib/secure_headers/configuration.rb +189 -0
- data/lib/secure_headers/headers/content_security_policy.rb +341 -254
- data/lib/secure_headers/headers/public_key_pins.rb +43 -58
- data/lib/secure_headers/headers/strict_transport_security.rb +21 -49
- data/lib/secure_headers/headers/x_content_type_options.rb +18 -33
- data/lib/secure_headers/headers/x_download_options.rb +18 -33
- data/lib/secure_headers/headers/x_frame_options.rb +24 -34
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +19 -34
- data/lib/secure_headers/headers/x_xss_protection.rb +17 -48
- data/lib/secure_headers/middleware.rb +15 -0
- data/lib/secure_headers/padrino.rb +1 -2
- data/lib/secure_headers/railtie.rb +9 -6
- data/lib/secure_headers/view_helper.rb +27 -43
- data/lib/secure_headers.rb +254 -61
- data/secure_headers.gemspec +7 -12
- data/spec/lib/secure_headers/configuration_spec.rb +80 -0
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +111 -276
- data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +17 -17
- data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +11 -43
- data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +11 -18
- data/spec/lib/secure_headers/headers/x_download_options_spec.rb +13 -17
- data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +15 -17
- data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +22 -39
- data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +20 -30
- data/spec/lib/secure_headers/middleware_spec.rb +40 -0
- data/spec/lib/secure_headers_spec.rb +201 -339
- data/spec/spec_helper.rb +30 -30
- data/upgrading-to-3-0.md +35 -0
- metadata +14 -100
- data/fixtures/rails_3_2_22/.rspec +0 -1
- data/fixtures/rails_3_2_22/Gemfile +0 -6
- data/fixtures/rails_3_2_22/README.rdoc +0 -261
- data/fixtures/rails_3_2_22/Rakefile +0 -7
- data/fixtures/rails_3_2_22/app/controllers/application_controller.rb +0 -4
- data/fixtures/rails_3_2_22/app/controllers/other_things_controller.rb +0 -5
- data/fixtures/rails_3_2_22/app/controllers/things_controller.rb +0 -5
- data/fixtures/rails_3_2_22/app/models/.gitkeep +0 -0
- data/fixtures/rails_3_2_22/app/views/layouts/application.html.erb +0 -11
- data/fixtures/rails_3_2_22/app/views/other_things/index.html.erb +0 -2
- data/fixtures/rails_3_2_22/app/views/things/index.html.erb +0 -1
- data/fixtures/rails_3_2_22/config/application.rb +0 -14
- data/fixtures/rails_3_2_22/config/boot.rb +0 -6
- data/fixtures/rails_3_2_22/config/environment.rb +0 -5
- data/fixtures/rails_3_2_22/config/environments/test.rb +0 -37
- data/fixtures/rails_3_2_22/config/initializers/secure_headers.rb +0 -16
- data/fixtures/rails_3_2_22/config/routes.rb +0 -4
- data/fixtures/rails_3_2_22/config/script_hashes.yml +0 -5
- data/fixtures/rails_3_2_22/config.ru +0 -7
- data/fixtures/rails_3_2_22/lib/assets/.gitkeep +0 -0
- data/fixtures/rails_3_2_22/lib/tasks/.gitkeep +0 -0
- data/fixtures/rails_3_2_22/log/.gitkeep +0 -0
- data/fixtures/rails_3_2_22/spec/controllers/other_things_controller_spec.rb +0 -83
- data/fixtures/rails_3_2_22/spec/controllers/things_controller_spec.rb +0 -54
- data/fixtures/rails_3_2_22/spec/spec_helper.rb +0 -15
- data/fixtures/rails_3_2_22/vendor/assets/javascripts/.gitkeep +0 -0
- data/fixtures/rails_3_2_22/vendor/assets/stylesheets/.gitkeep +0 -0
- data/fixtures/rails_3_2_22/vendor/plugins/.gitkeep +0 -0
- data/fixtures/rails_3_2_22_no_init/.rspec +0 -1
- data/fixtures/rails_3_2_22_no_init/Gemfile +0 -6
- data/fixtures/rails_3_2_22_no_init/README.rdoc +0 -261
- data/fixtures/rails_3_2_22_no_init/Rakefile +0 -7
- data/fixtures/rails_3_2_22_no_init/app/controllers/application_controller.rb +0 -4
- data/fixtures/rails_3_2_22_no_init/app/controllers/other_things_controller.rb +0 -20
- data/fixtures/rails_3_2_22_no_init/app/controllers/things_controller.rb +0 -5
- data/fixtures/rails_3_2_22_no_init/app/models/.gitkeep +0 -0
- data/fixtures/rails_3_2_22_no_init/app/views/layouts/application.html.erb +0 -12
- data/fixtures/rails_3_2_22_no_init/app/views/other_things/index.html.erb +0 -1
- data/fixtures/rails_3_2_22_no_init/app/views/things/index.html.erb +0 -0
- data/fixtures/rails_3_2_22_no_init/config/application.rb +0 -17
- data/fixtures/rails_3_2_22_no_init/config/boot.rb +0 -6
- data/fixtures/rails_3_2_22_no_init/config/environment.rb +0 -5
- data/fixtures/rails_3_2_22_no_init/config/environments/test.rb +0 -37
- data/fixtures/rails_3_2_22_no_init/config/routes.rb +0 -4
- data/fixtures/rails_3_2_22_no_init/config.ru +0 -4
- data/fixtures/rails_3_2_22_no_init/lib/assets/.gitkeep +0 -0
- data/fixtures/rails_3_2_22_no_init/lib/tasks/.gitkeep +0 -0
- data/fixtures/rails_3_2_22_no_init/log/.gitkeep +0 -0
- data/fixtures/rails_3_2_22_no_init/spec/controllers/other_things_controller_spec.rb +0 -56
- data/fixtures/rails_3_2_22_no_init/spec/controllers/things_controller_spec.rb +0 -54
- data/fixtures/rails_3_2_22_no_init/spec/spec_helper.rb +0 -5
- data/fixtures/rails_3_2_22_no_init/vendor/assets/javascripts/.gitkeep +0 -0
- data/fixtures/rails_3_2_22_no_init/vendor/assets/stylesheets/.gitkeep +0 -0
- data/fixtures/rails_3_2_22_no_init/vendor/plugins/.gitkeep +0 -0
- data/fixtures/rails_4_1_8/Gemfile +0 -5
- data/fixtures/rails_4_1_8/README.rdoc +0 -28
- data/fixtures/rails_4_1_8/Rakefile +0 -6
- data/fixtures/rails_4_1_8/app/controllers/application_controller.rb +0 -4
- data/fixtures/rails_4_1_8/app/controllers/concerns/.keep +0 -0
- data/fixtures/rails_4_1_8/app/controllers/other_things_controller.rb +0 -5
- data/fixtures/rails_4_1_8/app/controllers/things_controller.rb +0 -5
- data/fixtures/rails_4_1_8/app/models/.keep +0 -0
- data/fixtures/rails_4_1_8/app/models/concerns/.keep +0 -0
- data/fixtures/rails_4_1_8/app/views/layouts/application.html.erb +0 -11
- data/fixtures/rails_4_1_8/app/views/other_things/index.html.erb +0 -2
- data/fixtures/rails_4_1_8/app/views/things/index.html.erb +0 -1
- data/fixtures/rails_4_1_8/config/application.rb +0 -15
- data/fixtures/rails_4_1_8/config/boot.rb +0 -4
- data/fixtures/rails_4_1_8/config/environment.rb +0 -5
- data/fixtures/rails_4_1_8/config/environments/test.rb +0 -10
- data/fixtures/rails_4_1_8/config/initializers/secure_headers.rb +0 -16
- data/fixtures/rails_4_1_8/config/routes.rb +0 -4
- data/fixtures/rails_4_1_8/config/script_hashes.yml +0 -5
- data/fixtures/rails_4_1_8/config/secrets.yml +0 -22
- data/fixtures/rails_4_1_8/config.ru +0 -4
- data/fixtures/rails_4_1_8/lib/assets/.keep +0 -0
- data/fixtures/rails_4_1_8/lib/tasks/.keep +0 -0
- data/fixtures/rails_4_1_8/log/.keep +0 -0
- data/fixtures/rails_4_1_8/spec/controllers/other_things_controller_spec.rb +0 -83
- data/fixtures/rails_4_1_8/spec/controllers/things_controller_spec.rb +0 -59
- data/fixtures/rails_4_1_8/spec/spec_helper.rb +0 -15
- data/fixtures/rails_4_1_8/vendor/assets/javascripts/.keep +0 -0
- data/fixtures/rails_4_1_8/vendor/assets/stylesheets/.keep +0 -0
- data/lib/secure_headers/controller_extension.rb +0 -158
- data/lib/secure_headers/hash_helper.rb +0 -7
- data/lib/secure_headers/header.rb +0 -5
- data/lib/secure_headers/headers/content_security_policy/script_hash_middleware.rb +0 -22
- data/lib/secure_headers/version.rb +0 -3
- data/lib/tasks/tasks.rake +0 -48
- data/spec/lib/secure_headers/headers/content_security_policy/script_hash_middleware_spec.rb +0 -46
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
# This controller is meant to be something that inherits config from application controller
|
4
|
-
# all values are defaulted because no initializer is configured, and the values in app controller
|
5
|
-
# only provide csp => false
|
6
|
-
|
7
|
-
describe ThingsController, :type => :controller do
|
8
|
-
describe "headers" do
|
9
|
-
it "sets the X-XSS-Protection header" do
|
10
|
-
get :index
|
11
|
-
expect(response.headers['X-XSS-Protection']).to eq(SecureHeaders::XXssProtection::Constants::DEFAULT_VALUE)
|
12
|
-
end
|
13
|
-
|
14
|
-
it "sets the X-Frame-Options header" do
|
15
|
-
get :index
|
16
|
-
expect(response.headers['X-Frame-Options']).to eq(SecureHeaders::XFrameOptions::Constants::DEFAULT_VALUE)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "sets the X-WebKit-CSP header" do
|
20
|
-
get :index
|
21
|
-
expect(response.headers['Content-Security-Policy-Report-Only']).to eq(nil)
|
22
|
-
end
|
23
|
-
|
24
|
-
#mock ssl
|
25
|
-
it "sets the Strict-Transport-Security header" do
|
26
|
-
request.env['HTTPS'] = 'on'
|
27
|
-
get :index
|
28
|
-
expect(response.headers['Strict-Transport-Security']).to eq(SecureHeaders::StrictTransportSecurity::Constants::DEFAULT_VALUE)
|
29
|
-
end
|
30
|
-
|
31
|
-
it "sets the X-Download-Options header" do
|
32
|
-
get :index
|
33
|
-
expect(response.headers['X-Download-Options']).to eq(SecureHeaders::XDownloadOptions::Constants::DEFAULT_VALUE)
|
34
|
-
end
|
35
|
-
|
36
|
-
it "sets the X-Content-Type-Options header" do
|
37
|
-
get :index
|
38
|
-
expect(response.headers['X-Content-Type-Options']).to eq(SecureHeaders::XContentTypeOptions::Constants::DEFAULT_VALUE)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "sets the X-Permitted-Cross-Domain-Policies" do
|
42
|
-
get :index
|
43
|
-
expect(response.headers['X-Permitted-Cross-Domain-Policies']).to eq("none")
|
44
|
-
end
|
45
|
-
|
46
|
-
context "using IE" do
|
47
|
-
it "sets the X-Content-Type-Options header" do
|
48
|
-
request.env['HTTP_USER_AGENT'] = "Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0"
|
49
|
-
get :index
|
50
|
-
expect(response.headers['X-Content-Type-Options']).to eq(SecureHeaders::XContentTypeOptions::Constants::DEFAULT_VALUE)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,28 +0,0 @@
|
|
1
|
-
== README
|
2
|
-
|
3
|
-
This README would normally document whatever steps are necessary to get the
|
4
|
-
application up and running.
|
5
|
-
|
6
|
-
Things you may want to cover:
|
7
|
-
|
8
|
-
* Ruby version
|
9
|
-
|
10
|
-
* System dependencies
|
11
|
-
|
12
|
-
* Configuration
|
13
|
-
|
14
|
-
* Database creation
|
15
|
-
|
16
|
-
* Database initialization
|
17
|
-
|
18
|
-
* How to run the test suite
|
19
|
-
|
20
|
-
* Services (job queues, cache servers, search engines, etc.)
|
21
|
-
|
22
|
-
* Deployment instructions
|
23
|
-
|
24
|
-
* ...
|
25
|
-
|
26
|
-
|
27
|
-
Please feel free to use a different markup language if you do not plan to run
|
28
|
-
<tt>rake doc:app</tt>.
|
File without changes
|
File without changes
|
File without changes
|
@@ -1 +0,0 @@
|
|
1
|
-
things
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require File.expand_path('../boot', __FILE__)
|
2
|
-
|
3
|
-
require "action_controller/railtie"
|
4
|
-
require "sprockets/railtie"
|
5
|
-
|
6
|
-
# Require the gems listed in Gemfile, including any gems
|
7
|
-
# you've limited to :test, :development, or :production.
|
8
|
-
Bundler.require(*Rails.groups)
|
9
|
-
|
10
|
-
|
11
|
-
module Rails418
|
12
|
-
class Application < Rails::Application
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
@@ -1,10 +0,0 @@
|
|
1
|
-
Rails418::Application.configure do
|
2
|
-
config.cache_classes = true
|
3
|
-
config.eager_load = false
|
4
|
-
config.serve_static_assets = true
|
5
|
-
config.static_cache_control = 'public, max-age=3600'
|
6
|
-
config.consider_all_requests_local = true
|
7
|
-
config.action_controller.perform_caching = false
|
8
|
-
config.action_dispatch.show_exceptions = false
|
9
|
-
config.action_controller.allow_forgery_protection = false
|
10
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
::SecureHeaders::Configuration.configure do |config|
|
2
|
-
config.hsts = { :max_age => 10.years.to_i.to_s, :include_subdomains => false }
|
3
|
-
config.x_frame_options = 'DENY'
|
4
|
-
config.x_content_type_options = "nosniff"
|
5
|
-
config.x_xss_protection = {:value => 0}
|
6
|
-
config.x_permitted_cross_domain_policies = 'none'
|
7
|
-
csp = {
|
8
|
-
:default_src => "'self'",
|
9
|
-
:script_src => "'self' nonce",
|
10
|
-
:report_uri => 'somewhere',
|
11
|
-
:script_hash_middleware => true,
|
12
|
-
:enforce => false # false means warnings only
|
13
|
-
}
|
14
|
-
|
15
|
-
config.csp = csp
|
16
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# Be sure to restart your server when you modify this file.
|
2
|
-
|
3
|
-
# Your secret key is used for verifying the integrity of signed cookies.
|
4
|
-
# If you change this key, all old signed cookies will become invalid!
|
5
|
-
|
6
|
-
# Make sure the secret is at least 30 characters and all random,
|
7
|
-
# no regular words or you'll be exposed to dictionary attacks.
|
8
|
-
# You can use `rake secret` to generate a secure secret key.
|
9
|
-
|
10
|
-
# Make sure the secrets in this file are kept private
|
11
|
-
# if you're sharing your code publicly.
|
12
|
-
|
13
|
-
development:
|
14
|
-
secret_key_base: ddba38f932720d8f18257f2a05dc278963a29cf569c45aa97ff4e9fc9bbc78af5a03fcf135caad45caee66ac09f8f9913c1f5e338a61213f420eefa8dd6363d2
|
15
|
-
|
16
|
-
test:
|
17
|
-
secret_key_base: f73abd7eab84fa7af5a2fc0a9c2727c5bad47433e51aa0c9c6b0782dac176a8e7f337e1f93adc6d6fc17027e67a533040b6408e54d72dea2eec6e5b9820dbcb9
|
18
|
-
|
19
|
-
# Do not keep production secrets in the repository,
|
20
|
-
# instead read values from the environment.
|
21
|
-
production:
|
22
|
-
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'secure_headers/headers/content_security_policy/script_hash_middleware'
|
4
|
-
|
5
|
-
describe OtherThingsController, :type => :controller do
|
6
|
-
include Rack::Test::Methods
|
7
|
-
|
8
|
-
def app
|
9
|
-
OtherThingsController.action(:index)
|
10
|
-
end
|
11
|
-
|
12
|
-
def request(opts = {})
|
13
|
-
options = opts.merge(
|
14
|
-
{
|
15
|
-
'HTTPS' => 'on',
|
16
|
-
'HTTP_USER_AGENT' => "Mozilla/5.0 (Macintosh; Intel Mac OS X 1084) AppleWebKit/537.22 (KHTML like Gecko) Chrome/25.0.1364.99 Safari/537.22"
|
17
|
-
}
|
18
|
-
)
|
19
|
-
|
20
|
-
|
21
|
-
Rack::MockRequest.env_for('/', options)
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
describe "headers" do
|
26
|
-
before(:each) do
|
27
|
-
_, @env = app.call(request)
|
28
|
-
end
|
29
|
-
|
30
|
-
it "sets the X-XSS-Protection header" do
|
31
|
-
get '/'
|
32
|
-
expect(@env['X-XSS-Protection']).to eq('0')
|
33
|
-
end
|
34
|
-
|
35
|
-
it "sets the X-Frame-Options header" do
|
36
|
-
get '/'
|
37
|
-
expect(@env['X-Frame-Options']).to eq('DENY')
|
38
|
-
end
|
39
|
-
|
40
|
-
it "sets the CSP header with a local reference to a nonce" do
|
41
|
-
middleware = ::SecureHeaders::ContentSecurityPolicy::ScriptHashMiddleware.new(app)
|
42
|
-
_, env = middleware.call(request(@env))
|
43
|
-
expect(env['Content-Security-Policy-Report-Only']).to match(/script-src[^;]*'nonce-[a-zA-Z0-9\+\/=]{44}'/)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "sets the required hashes to whitelist inline script" do
|
47
|
-
middleware = ::SecureHeaders::ContentSecurityPolicy::ScriptHashMiddleware.new(app)
|
48
|
-
_, env = middleware.call(request(@env))
|
49
|
-
hashes = ['sha256-VjDxT7saxd2FgaUQQTWw/jsTnvonaoCP/ACWDBTpyhU=', 'sha256-ZXAcP8a0y1pPMTJW8pUr43c+XBkgYQBwHOPvXk9mq5A=']
|
50
|
-
hashes.each do |hash|
|
51
|
-
expect(env['Content-Security-Policy-Report-Only']).to include(hash)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
it "sets the Strict-Transport-Security header" do
|
56
|
-
get '/'
|
57
|
-
expect(@env['Strict-Transport-Security']).to eq("max-age=315576000")
|
58
|
-
end
|
59
|
-
|
60
|
-
it "sets the X-Download-Options header" do
|
61
|
-
get '/'
|
62
|
-
expect(@env['X-Download-Options']).to eq('noopen')
|
63
|
-
end
|
64
|
-
|
65
|
-
it "sets the X-Content-Type-Options header" do
|
66
|
-
get '/'
|
67
|
-
expect(@env['X-Content-Type-Options']).to eq("nosniff")
|
68
|
-
end
|
69
|
-
|
70
|
-
it "sets the X-Permitted-Cross-Domain-Policies" do
|
71
|
-
get '/'
|
72
|
-
expect(@env['X-Permitted-Cross-Domain-Policies']).to eq("none")
|
73
|
-
end
|
74
|
-
|
75
|
-
context "using IE" do
|
76
|
-
it "sets the X-Content-Type-Options header" do
|
77
|
-
@env['HTTP_USER_AGENT'] = "Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0"
|
78
|
-
get '/'
|
79
|
-
expect(@env['X-Content-Type-Options']).to eq("nosniff")
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# config.action_dispatch.default_headers defaults to:
|
2
|
-
# {"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff"}
|
3
|
-
# so we want to set our specs to expect something else to ensure secureheaders is taking precedence
|
4
|
-
|
5
|
-
require 'spec_helper'
|
6
|
-
|
7
|
-
# This controller is meant to be something that inherits config from application controller
|
8
|
-
# all values are defaulted because no initializer is configured, and the values in app controller
|
9
|
-
# only provide csp => false
|
10
|
-
|
11
|
-
describe ThingsController, :type => :controller do
|
12
|
-
|
13
|
-
describe "headers" do
|
14
|
-
it "sets the X-XSS-Protection header" do
|
15
|
-
get :index
|
16
|
-
expect(response.headers['X-XSS-Protection']).to eq('0')
|
17
|
-
end
|
18
|
-
|
19
|
-
it "sets the X-Frame-Options header" do
|
20
|
-
get :index
|
21
|
-
expect(response.headers['X-Frame-Options']).to eq('DENY')
|
22
|
-
end
|
23
|
-
|
24
|
-
it "does not set CSP header" do
|
25
|
-
get :index
|
26
|
-
expect(response.headers['Content-Security-Policy-Report-Only']).to eq(nil)
|
27
|
-
end
|
28
|
-
|
29
|
-
#mock ssl
|
30
|
-
it "sets the Strict-Transport-Security header" do
|
31
|
-
request.env['HTTPS'] = 'on'
|
32
|
-
get :index
|
33
|
-
expect(response.headers['Strict-Transport-Security']).to eq("max-age=315576000")
|
34
|
-
end
|
35
|
-
|
36
|
-
it "sets the X-Download-Options header" do
|
37
|
-
get :index
|
38
|
-
expect(response.headers['X-Download-Options']).to eq('noopen')
|
39
|
-
end
|
40
|
-
|
41
|
-
it "sets the X-Content-Type-Options header" do
|
42
|
-
get :index
|
43
|
-
expect(response.headers['X-Content-Type-Options']).to eq("nosniff")
|
44
|
-
end
|
45
|
-
|
46
|
-
it "sets the X-Permitted-Cross-Domain-Policies" do
|
47
|
-
get :index
|
48
|
-
expect(response.headers['X-Permitted-Cross-Domain-Policies']).to eq("none")
|
49
|
-
end
|
50
|
-
|
51
|
-
context "using IE" do
|
52
|
-
it "sets the X-Content-Type-Options header" do
|
53
|
-
request.env['HTTP_USER_AGENT'] = "Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0"
|
54
|
-
get :index
|
55
|
-
expect(response.headers['X-Content-Type-Options']).to eq("nosniff")
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
#uncomment the following line to use spork with the debugger
|
4
|
-
#require 'spork/ext/ruby-debug'
|
5
|
-
|
6
|
-
# Spork.prefork do
|
7
|
-
# Loading more in this block will cause your tests to run faster. However,
|
8
|
-
# if you change any configuration or code from libraries loaded here, you'll
|
9
|
-
# need to restart spork for it take effect.
|
10
|
-
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
11
|
-
ENV["RAILS_ENV"] ||= 'test'
|
12
|
-
require File.expand_path("../../config/environment", __FILE__)
|
13
|
-
require 'rspec/rails'
|
14
|
-
# end
|
15
|
-
|
File without changes
|
File without changes
|
@@ -1,158 +0,0 @@
|
|
1
|
-
module SecureHeaders
|
2
|
-
module ControllerExtension
|
3
|
-
class << self
|
4
|
-
def append_features(base)
|
5
|
-
base.module_eval do
|
6
|
-
extend ClassMethods
|
7
|
-
include InstanceMethods
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
attr_writer :secure_headers_options
|
14
|
-
def secure_headers_options
|
15
|
-
if @secure_headers_options
|
16
|
-
@secure_headers_options
|
17
|
-
elsif superclass.respond_to?(:secure_headers_options) # stop at application_controller
|
18
|
-
superclass.secure_headers_options
|
19
|
-
else
|
20
|
-
{}
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def ensure_security_headers options = {}
|
25
|
-
if RUBY_VERSION == "1.8.7"
|
26
|
-
warn "[DEPRECATION] secure_headers ruby 1.8.7 support will dropped in the next release"
|
27
|
-
end
|
28
|
-
self.secure_headers_options = options
|
29
|
-
hook = respond_to?(:before_action) ? :before_action : :before_filter
|
30
|
-
::SecureHeaders::ALL_FILTER_METHODS.each do |method|
|
31
|
-
send(hook, method)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
module InstanceMethods
|
37
|
-
def set_security_headers(options = self.class.secure_headers_options)
|
38
|
-
set_csp_header(request, options[:csp])
|
39
|
-
set_hsts_header(options[:hsts])
|
40
|
-
set_hpkp_header(options[:hpkp])
|
41
|
-
set_x_frame_options_header(options[:x_frame_options])
|
42
|
-
set_x_xss_protection_header(options[:x_xss_protection])
|
43
|
-
set_x_content_type_options_header(options[:x_content_type_options])
|
44
|
-
set_x_download_options_header(options[:x_download_options])
|
45
|
-
set_x_permitted_cross_domain_policies_header(options[:x_permitted_cross_domain_policies])
|
46
|
-
end
|
47
|
-
|
48
|
-
# set_csp_header - uses the request accessor and SecureHeader::Configuration settings
|
49
|
-
# set_csp_header(+Rack::Request+) - uses the parameter and and SecureHeader::Configuration settings
|
50
|
-
# set_csp_header(+Hash+) - uses the request accessor and options from parameters
|
51
|
-
# set_csp_header(+Rack::Request+, +Hash+)
|
52
|
-
def set_csp_header(req = nil, config=nil)
|
53
|
-
if req.is_a?(Hash) || req.is_a?(FalseClass)
|
54
|
-
config = req
|
55
|
-
end
|
56
|
-
|
57
|
-
config = self.class.secure_headers_options[:csp] if config.nil?
|
58
|
-
config = secure_header_options_for :csp, config
|
59
|
-
|
60
|
-
return if config == false
|
61
|
-
|
62
|
-
if config && config[:script_hash_middleware]
|
63
|
-
ContentSecurityPolicy.add_to_env(request, self, config)
|
64
|
-
else
|
65
|
-
csp_header = ContentSecurityPolicy.new(config, :request => request, :controller => self)
|
66
|
-
set_header(csp_header)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
def prep_script_hash
|
72
|
-
if ::SecureHeaders::Configuration.script_hashes
|
73
|
-
@script_hashes = ::SecureHeaders::Configuration.script_hashes.dup
|
74
|
-
ActiveSupport::Notifications.subscribe("render_partial.action_view") do |event_name, start_at, end_at, id, payload|
|
75
|
-
save_hash_for_later payload
|
76
|
-
end
|
77
|
-
|
78
|
-
ActiveSupport::Notifications.subscribe("render_template.action_view") do |event_name, start_at, end_at, id, payload|
|
79
|
-
save_hash_for_later payload
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def save_hash_for_later payload
|
85
|
-
matching_hashes = @script_hashes[payload[:identifier].gsub(Rails.root.to_s + "/", "")] || []
|
86
|
-
|
87
|
-
if payload[:layout]
|
88
|
-
# We're assuming an html.erb layout for now. Will need to handle mustache too, just not sure of the best way to do this
|
89
|
-
layout_hashes = @script_hashes[File.join("app", "views", payload[:layout]) + '.html.erb']
|
90
|
-
|
91
|
-
matching_hashes << layout_hashes if layout_hashes
|
92
|
-
end
|
93
|
-
|
94
|
-
if matching_hashes.any?
|
95
|
-
request.env[HASHES_ENV_KEY] = ((request.env[HASHES_ENV_KEY] || []) << matching_hashes).flatten
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def set_x_frame_options_header(options=self.class.secure_headers_options[:x_frame_options])
|
100
|
-
set_a_header(:x_frame_options, XFrameOptions, options)
|
101
|
-
end
|
102
|
-
|
103
|
-
def set_x_content_type_options_header(options=self.class.secure_headers_options[:x_content_type_options])
|
104
|
-
set_a_header(:x_content_type_options, XContentTypeOptions, options)
|
105
|
-
end
|
106
|
-
|
107
|
-
def set_x_xss_protection_header(options=self.class.secure_headers_options[:x_xss_protection])
|
108
|
-
set_a_header(:x_xss_protection, XXssProtection, options)
|
109
|
-
end
|
110
|
-
|
111
|
-
def set_hsts_header(options=self.class.secure_headers_options[:hsts])
|
112
|
-
return unless request.ssl?
|
113
|
-
set_a_header(:hsts, StrictTransportSecurity, options)
|
114
|
-
end
|
115
|
-
|
116
|
-
def set_hpkp_header(options=self.class.secure_headers_options[:hpkp])
|
117
|
-
return unless request.ssl?
|
118
|
-
config = secure_header_options_for :hpkp, options
|
119
|
-
|
120
|
-
return if config == false || config.nil?
|
121
|
-
|
122
|
-
hpkp_header = PublicKeyPins.new(config)
|
123
|
-
set_header(hpkp_header)
|
124
|
-
end
|
125
|
-
|
126
|
-
def set_x_download_options_header(options=self.class.secure_headers_options[:x_download_options])
|
127
|
-
set_a_header(:x_download_options, XDownloadOptions, options)
|
128
|
-
end
|
129
|
-
|
130
|
-
def set_x_permitted_cross_domain_policies_header(options=self.class.secure_headers_options[:x_permitted_cross_domain_policies])
|
131
|
-
set_a_header(:x_permitted_cross_domain_policies, XPermittedCrossDomainPolicies, options)
|
132
|
-
end
|
133
|
-
|
134
|
-
private
|
135
|
-
|
136
|
-
# we can't use ||= because I'm overloading false => disable, nil => default
|
137
|
-
# both of which trigger the conditional assignment
|
138
|
-
def secure_header_options_for(type, options)
|
139
|
-
options.nil? ? ::SecureHeaders::Configuration.send(type) : options
|
140
|
-
end
|
141
|
-
|
142
|
-
def set_a_header(name, klass, options=nil)
|
143
|
-
options = secure_header_options_for(name, options)
|
144
|
-
return if options == false
|
145
|
-
set_header(SecureHeaders::get_a_header(klass, options))
|
146
|
-
end
|
147
|
-
|
148
|
-
def set_header(name_or_header, value=nil)
|
149
|
-
if name_or_header.is_a?(Header)
|
150
|
-
header = name_or_header
|
151
|
-
response.headers[header.name] = header.value
|
152
|
-
else
|
153
|
-
response.headers[name_or_header] = value
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module SecureHeaders
|
2
|
-
class ContentSecurityPolicy
|
3
|
-
class ScriptHashMiddleware
|
4
|
-
def initialize(app)
|
5
|
-
@app = app
|
6
|
-
end
|
7
|
-
|
8
|
-
def call(env)
|
9
|
-
status, headers, response = @app.call(env)
|
10
|
-
metadata = env[ContentSecurityPolicy::ENV_KEY]
|
11
|
-
if !metadata.nil?
|
12
|
-
config, options = metadata.values_at(:config, :options)
|
13
|
-
config.merge!(:script_hashes => env[HASHES_ENV_KEY])
|
14
|
-
csp_header = ContentSecurityPolicy.new(config, options)
|
15
|
-
headers[csp_header.name] = csp_header.value
|
16
|
-
end
|
17
|
-
|
18
|
-
[status, headers, response]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|