secure_headers 2.5.3 → 3.0.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.travis.yml +2 -1
  4. data/Gemfile +9 -16
  5. data/README.md +154 -331
  6. data/Rakefile +2 -36
  7. data/lib/secure_headers/configuration.rb +189 -0
  8. data/lib/secure_headers/headers/content_security_policy.rb +341 -254
  9. data/lib/secure_headers/headers/public_key_pins.rb +43 -58
  10. data/lib/secure_headers/headers/strict_transport_security.rb +21 -49
  11. data/lib/secure_headers/headers/x_content_type_options.rb +18 -33
  12. data/lib/secure_headers/headers/x_download_options.rb +18 -33
  13. data/lib/secure_headers/headers/x_frame_options.rb +24 -34
  14. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +19 -34
  15. data/lib/secure_headers/headers/x_xss_protection.rb +17 -48
  16. data/lib/secure_headers/middleware.rb +15 -0
  17. data/lib/secure_headers/padrino.rb +1 -2
  18. data/lib/secure_headers/railtie.rb +9 -6
  19. data/lib/secure_headers/view_helper.rb +27 -43
  20. data/lib/secure_headers.rb +254 -61
  21. data/secure_headers.gemspec +7 -12
  22. data/spec/lib/secure_headers/configuration_spec.rb +80 -0
  23. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +111 -276
  24. data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +17 -17
  25. data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +11 -43
  26. data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +11 -18
  27. data/spec/lib/secure_headers/headers/x_download_options_spec.rb +13 -17
  28. data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +15 -17
  29. data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +22 -39
  30. data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +20 -30
  31. data/spec/lib/secure_headers/middleware_spec.rb +40 -0
  32. data/spec/lib/secure_headers_spec.rb +201 -339
  33. data/spec/spec_helper.rb +30 -30
  34. data/upgrading-to-3-0.md +35 -0
  35. metadata +14 -100
  36. data/fixtures/rails_3_2_22/.rspec +0 -1
  37. data/fixtures/rails_3_2_22/Gemfile +0 -6
  38. data/fixtures/rails_3_2_22/README.rdoc +0 -261
  39. data/fixtures/rails_3_2_22/Rakefile +0 -7
  40. data/fixtures/rails_3_2_22/app/controllers/application_controller.rb +0 -4
  41. data/fixtures/rails_3_2_22/app/controllers/other_things_controller.rb +0 -5
  42. data/fixtures/rails_3_2_22/app/controllers/things_controller.rb +0 -5
  43. data/fixtures/rails_3_2_22/app/models/.gitkeep +0 -0
  44. data/fixtures/rails_3_2_22/app/views/layouts/application.html.erb +0 -11
  45. data/fixtures/rails_3_2_22/app/views/other_things/index.html.erb +0 -2
  46. data/fixtures/rails_3_2_22/app/views/things/index.html.erb +0 -1
  47. data/fixtures/rails_3_2_22/config/application.rb +0 -14
  48. data/fixtures/rails_3_2_22/config/boot.rb +0 -6
  49. data/fixtures/rails_3_2_22/config/environment.rb +0 -5
  50. data/fixtures/rails_3_2_22/config/environments/test.rb +0 -37
  51. data/fixtures/rails_3_2_22/config/initializers/secure_headers.rb +0 -16
  52. data/fixtures/rails_3_2_22/config/routes.rb +0 -4
  53. data/fixtures/rails_3_2_22/config/script_hashes.yml +0 -5
  54. data/fixtures/rails_3_2_22/config.ru +0 -7
  55. data/fixtures/rails_3_2_22/lib/assets/.gitkeep +0 -0
  56. data/fixtures/rails_3_2_22/lib/tasks/.gitkeep +0 -0
  57. data/fixtures/rails_3_2_22/log/.gitkeep +0 -0
  58. data/fixtures/rails_3_2_22/spec/controllers/other_things_controller_spec.rb +0 -83
  59. data/fixtures/rails_3_2_22/spec/controllers/things_controller_spec.rb +0 -54
  60. data/fixtures/rails_3_2_22/spec/spec_helper.rb +0 -15
  61. data/fixtures/rails_3_2_22/vendor/assets/javascripts/.gitkeep +0 -0
  62. data/fixtures/rails_3_2_22/vendor/assets/stylesheets/.gitkeep +0 -0
  63. data/fixtures/rails_3_2_22/vendor/plugins/.gitkeep +0 -0
  64. data/fixtures/rails_3_2_22_no_init/.rspec +0 -1
  65. data/fixtures/rails_3_2_22_no_init/Gemfile +0 -6
  66. data/fixtures/rails_3_2_22_no_init/README.rdoc +0 -261
  67. data/fixtures/rails_3_2_22_no_init/Rakefile +0 -7
  68. data/fixtures/rails_3_2_22_no_init/app/controllers/application_controller.rb +0 -4
  69. data/fixtures/rails_3_2_22_no_init/app/controllers/other_things_controller.rb +0 -20
  70. data/fixtures/rails_3_2_22_no_init/app/controllers/things_controller.rb +0 -5
  71. data/fixtures/rails_3_2_22_no_init/app/models/.gitkeep +0 -0
  72. data/fixtures/rails_3_2_22_no_init/app/views/layouts/application.html.erb +0 -12
  73. data/fixtures/rails_3_2_22_no_init/app/views/other_things/index.html.erb +0 -1
  74. data/fixtures/rails_3_2_22_no_init/app/views/things/index.html.erb +0 -0
  75. data/fixtures/rails_3_2_22_no_init/config/application.rb +0 -17
  76. data/fixtures/rails_3_2_22_no_init/config/boot.rb +0 -6
  77. data/fixtures/rails_3_2_22_no_init/config/environment.rb +0 -5
  78. data/fixtures/rails_3_2_22_no_init/config/environments/test.rb +0 -37
  79. data/fixtures/rails_3_2_22_no_init/config/routes.rb +0 -4
  80. data/fixtures/rails_3_2_22_no_init/config.ru +0 -4
  81. data/fixtures/rails_3_2_22_no_init/lib/assets/.gitkeep +0 -0
  82. data/fixtures/rails_3_2_22_no_init/lib/tasks/.gitkeep +0 -0
  83. data/fixtures/rails_3_2_22_no_init/log/.gitkeep +0 -0
  84. data/fixtures/rails_3_2_22_no_init/spec/controllers/other_things_controller_spec.rb +0 -56
  85. data/fixtures/rails_3_2_22_no_init/spec/controllers/things_controller_spec.rb +0 -54
  86. data/fixtures/rails_3_2_22_no_init/spec/spec_helper.rb +0 -5
  87. data/fixtures/rails_3_2_22_no_init/vendor/assets/javascripts/.gitkeep +0 -0
  88. data/fixtures/rails_3_2_22_no_init/vendor/assets/stylesheets/.gitkeep +0 -0
  89. data/fixtures/rails_3_2_22_no_init/vendor/plugins/.gitkeep +0 -0
  90. data/fixtures/rails_4_1_8/Gemfile +0 -5
  91. data/fixtures/rails_4_1_8/README.rdoc +0 -28
  92. data/fixtures/rails_4_1_8/Rakefile +0 -6
  93. data/fixtures/rails_4_1_8/app/controllers/application_controller.rb +0 -4
  94. data/fixtures/rails_4_1_8/app/controllers/concerns/.keep +0 -0
  95. data/fixtures/rails_4_1_8/app/controllers/other_things_controller.rb +0 -5
  96. data/fixtures/rails_4_1_8/app/controllers/things_controller.rb +0 -5
  97. data/fixtures/rails_4_1_8/app/models/.keep +0 -0
  98. data/fixtures/rails_4_1_8/app/models/concerns/.keep +0 -0
  99. data/fixtures/rails_4_1_8/app/views/layouts/application.html.erb +0 -11
  100. data/fixtures/rails_4_1_8/app/views/other_things/index.html.erb +0 -2
  101. data/fixtures/rails_4_1_8/app/views/things/index.html.erb +0 -1
  102. data/fixtures/rails_4_1_8/config/application.rb +0 -15
  103. data/fixtures/rails_4_1_8/config/boot.rb +0 -4
  104. data/fixtures/rails_4_1_8/config/environment.rb +0 -5
  105. data/fixtures/rails_4_1_8/config/environments/test.rb +0 -10
  106. data/fixtures/rails_4_1_8/config/initializers/secure_headers.rb +0 -16
  107. data/fixtures/rails_4_1_8/config/routes.rb +0 -4
  108. data/fixtures/rails_4_1_8/config/script_hashes.yml +0 -5
  109. data/fixtures/rails_4_1_8/config/secrets.yml +0 -22
  110. data/fixtures/rails_4_1_8/config.ru +0 -4
  111. data/fixtures/rails_4_1_8/lib/assets/.keep +0 -0
  112. data/fixtures/rails_4_1_8/lib/tasks/.keep +0 -0
  113. data/fixtures/rails_4_1_8/log/.keep +0 -0
  114. data/fixtures/rails_4_1_8/spec/controllers/other_things_controller_spec.rb +0 -83
  115. data/fixtures/rails_4_1_8/spec/controllers/things_controller_spec.rb +0 -59
  116. data/fixtures/rails_4_1_8/spec/spec_helper.rb +0 -15
  117. data/fixtures/rails_4_1_8/vendor/assets/javascripts/.keep +0 -0
  118. data/fixtures/rails_4_1_8/vendor/assets/stylesheets/.keep +0 -0
  119. data/lib/secure_headers/controller_extension.rb +0 -158
  120. data/lib/secure_headers/hash_helper.rb +0 -7
  121. data/lib/secure_headers/header.rb +0 -5
  122. data/lib/secure_headers/headers/content_security_policy/script_hash_middleware.rb +0 -22
  123. data/lib/secure_headers/version.rb +0 -3
  124. data/lib/tasks/tasks.rake +0 -48
  125. data/spec/lib/secure_headers/headers/content_security_policy/script_hash_middleware_spec.rb +0 -46
@@ -1,31 +1,27 @@
1
+ require 'spec_helper'
2
+
1
3
  module SecureHeaders
2
4
  describe XDownloadOptions do
3
- specify { expect(XDownloadOptions.new.name).to eq(XDO_HEADER_NAME)}
4
- specify { expect(XDownloadOptions.new.value).to eq("noopen")}
5
- specify { expect(XDownloadOptions.new('noopen').value).to eq('noopen')}
6
- specify { expect(XDownloadOptions.new(:value => 'noopen').value).to eq('noopen') }
5
+ specify { expect(XDownloadOptions.make_header).to eq([XDownloadOptions::HEADER_NAME, XDownloadOptions::DEFAULT_VALUE]) }
6
+ specify { expect(XDownloadOptions.make_header('noopen')).to eq([XDownloadOptions::HEADER_NAME, 'noopen']) }
7
7
 
8
8
  context "invalid configuration values" do
9
9
  it "accepts noopen" do
10
- expect {
11
- XDownloadOptions.new("noopen")
12
- }.not_to raise_error
13
-
14
- expect {
15
- XDownloadOptions.new(:value => "noopen")
16
- }.not_to raise_error
10
+ expect do
11
+ XDownloadOptions.validate_config!("noopen")
12
+ end.not_to raise_error
17
13
  end
18
14
 
19
15
  it "accepts nil" do
20
- expect {
21
- XDownloadOptions.new
22
- }.not_to raise_error
16
+ expect do
17
+ XDownloadOptions.validate_config!(nil)
18
+ end.not_to raise_error
23
19
  end
24
20
 
25
21
  it "doesn't accept anything besides noopen" do
26
- expect {
27
- XDownloadOptions.new("open")
28
- }.to raise_error(XDOBuildError)
22
+ expect do
23
+ XDownloadOptions.validate_config!("open")
24
+ end.to raise_error(XDOConfigError)
29
25
  end
30
26
  end
31
27
  end
@@ -2,34 +2,32 @@ require 'spec_helper'
2
2
 
3
3
  module SecureHeaders
4
4
  describe XFrameOptions do
5
- specify{ expect(XFrameOptions.new.name).to eq("X-Frame-Options") }
6
-
7
5
  describe "#value" do
8
- specify { expect(XFrameOptions.new.value).to eq(XFrameOptions::Constants::DEFAULT_VALUE)}
9
- specify { expect(XFrameOptions.new("SAMEORIGIN").value).to eq("SAMEORIGIN")}
10
- specify { expect(XFrameOptions.new(:value => 'DENY').value).to eq("DENY")}
6
+ specify { expect(XFrameOptions.make_header).to eq([XFrameOptions::HEADER_NAME, XFrameOptions::DEFAULT_VALUE]) }
7
+ specify { expect(XFrameOptions.make_header("DENY")).to eq([XFrameOptions::HEADER_NAME, "DENY"]) }
11
8
 
12
9
  context "with invalid configuration" do
13
10
  it "allows SAMEORIGIN" do
14
- expect {
15
- XFrameOptions.new("SAMEORIGIN").value
16
- }.not_to raise_error
11
+ expect do
12
+ XFrameOptions.validate_config!("SAMEORIGIN")
13
+ end.not_to raise_error
17
14
  end
18
15
 
19
16
  it "allows DENY" do
20
- expect {
21
- XFrameOptions.new("DENY").value
22
- }.not_to raise_error end
17
+ expect do
18
+ XFrameOptions.validate_config!("DENY")
19
+ end.not_to raise_error
20
+ end
23
21
 
24
22
  it "allows ALLOW-FROM*" do
25
- expect {
26
- XFrameOptions.new("ALLOW-FROM: example.com").value
27
- }.not_to raise_error
23
+ expect do
24
+ XFrameOptions.validate_config!("ALLOW-FROM: example.com")
25
+ end.not_to raise_error
28
26
  end
29
27
  it "does not allow garbage" do
30
- expect {
31
- XFrameOptions.new("I like turtles").value
32
- }.to raise_error(XFOBuildError)
28
+ expect do
29
+ XFrameOptions.validate_config!("I like turtles")
30
+ end.to raise_error(XFOConfigError)
33
31
  end
34
32
  end
35
33
  end
@@ -1,63 +1,46 @@
1
+ require 'spec_helper'
2
+
1
3
  module SecureHeaders
2
4
  describe XPermittedCrossDomainPolicies do
3
- specify { expect(XPermittedCrossDomainPolicies.new.name).to eq(XPermittedCrossDomainPolicies::Constants::XPCDP_HEADER_NAME)}
4
- specify { expect(XPermittedCrossDomainPolicies.new.value).to eq("none")}
5
- specify { expect(XPermittedCrossDomainPolicies.new('master-only').value).to eq('master-only')}
6
- specify { expect(XPermittedCrossDomainPolicies.new(:value => 'master-only').value).to eq('master-only') }
5
+ specify { expect(XPermittedCrossDomainPolicies.make_header).to eq([XPermittedCrossDomainPolicies::HEADER_NAME, "none"]) }
6
+ specify { expect(XPermittedCrossDomainPolicies.make_header('master-only')).to eq([XPermittedCrossDomainPolicies::HEADER_NAME, 'master-only']) }
7
7
 
8
8
  context "valid configuration values" do
9
9
  it "accepts 'all'" do
10
- expect {
11
- XPermittedCrossDomainPolicies.new("all")
12
- }.not_to raise_error
13
-
14
- expect {
15
- XPermittedCrossDomainPolicies.new(:value => "all")
16
- }.not_to raise_error
10
+ expect do
11
+ XPermittedCrossDomainPolicies.validate_config!("all")
12
+ end.not_to raise_error
17
13
  end
18
14
 
19
15
  it "accepts 'by-ftp-filename'" do
20
- expect {
21
- XPermittedCrossDomainPolicies.new("by-ftp-filename")
22
- }.not_to raise_error
23
-
24
- expect {
25
- XPermittedCrossDomainPolicies.new(:value => "by-ftp-filename")
26
- }.not_to raise_error
16
+ expect do
17
+ XPermittedCrossDomainPolicies.validate_config!("by-ftp-filename")
18
+ end.not_to raise_error
27
19
  end
28
20
 
29
21
  it "accepts 'by-content-type'" do
30
- expect {
31
- XPermittedCrossDomainPolicies.new("by-content-type")
32
- }.not_to raise_error
33
-
34
- expect {
35
- XPermittedCrossDomainPolicies.new(:value => "by-content-type")
36
- }.not_to raise_error
22
+ expect do
23
+ XPermittedCrossDomainPolicies.validate_config!("by-content-type")
24
+ end.not_to raise_error
37
25
  end
38
26
  it "accepts 'master-only'" do
39
- expect {
40
- XPermittedCrossDomainPolicies.new("master-only")
41
- }.not_to raise_error
42
-
43
- expect {
44
- XPermittedCrossDomainPolicies.new(:value => "master-only")
45
- }.not_to raise_error
27
+ expect do
28
+ XPermittedCrossDomainPolicies.validate_config!("master-only")
29
+ end.not_to raise_error
46
30
  end
47
31
 
48
32
  it "accepts nil" do
49
- expect {
50
- XPermittedCrossDomainPolicies.new
51
- }.not_to raise_error
33
+ expect do
34
+ XPermittedCrossDomainPolicies.validate_config!(nil)
35
+ end.not_to raise_error
52
36
  end
53
37
  end
54
38
 
55
39
  context 'invlaid configuration values' do
56
-
57
40
  it "doesn't accept invalid values" do
58
- expect {
59
- XPermittedCrossDomainPolicies.new("open")
60
- }.to raise_error(XPCDPBuildError)
41
+ expect do
42
+ XPermittedCrossDomainPolicies.validate_config!("open")
43
+ end.to raise_error(XPCDPConfigError)
61
44
  end
62
45
  end
63
46
  end
@@ -2,55 +2,45 @@ require 'spec_helper'
2
2
 
3
3
  module SecureHeaders
4
4
  describe XXssProtection do
5
- specify { expect(XXssProtection.new.name).to eq(X_XSS_PROTECTION_HEADER_NAME)}
6
- specify { expect(XXssProtection.new.value).to eq("1")}
7
- specify { expect(XXssProtection.new("0").value).to eq("0")}
8
- specify { expect(XXssProtection.new(:value => 1, :mode => 'block').value).to eq('1; mode=block') }
9
- specify { expect(XXssProtection.new(:value => 1, :mode => 'block', :report_uri => 'https://www.secure.com/reports').value).to eq('1; mode=block; report=https://www.secure.com/reports') }
5
+ specify { expect(XXssProtection.make_header).to eq([XXssProtection::HEADER_NAME, XXssProtection::DEFAULT_VALUE]) }
6
+ specify { expect(XXssProtection.make_header("1; mode=block; report=https://www.secure.com/reports")).to eq([XXssProtection::HEADER_NAME, '1; mode=block; report=https://www.secure.com/reports']) }
10
7
 
11
8
  context "with invalid configuration" do
12
9
  it "should raise an error when providing a string that is not valid" do
13
- expect {
14
- XXssProtection.new("asdf")
15
- }.to raise_error(XXssProtectionBuildError)
10
+ expect do
11
+ XXssProtection.validate_config!("asdf")
12
+ end.to raise_error(XXssProtectionConfigError)
16
13
 
17
- expect {
18
- XXssProtection.new("asdf; mode=donkey")
19
- }.to raise_error(XXssProtectionBuildError)
14
+ expect do
15
+ XXssProtection.validate_config!("asdf; mode=donkey")
16
+ end.to raise_error(XXssProtectionConfigError)
20
17
  end
21
18
 
22
19
  context "when using a hash value" do
23
20
  it "should allow string values ('1' or '0' are the only valid strings)" do
24
- expect {
25
- XXssProtection.new(:value => '1')
26
- }.not_to raise_error
27
- end
28
-
29
- it "should allow integer values (1 or 0 are the only valid integers)" do
30
- expect {
31
- XXssProtection.new(:value => 1)
32
- }.not_to raise_error
21
+ expect do
22
+ XXssProtection.validate_config!('1')
23
+ end.not_to raise_error
33
24
  end
34
25
 
35
26
  it "should raise an error if no value key is supplied" do
36
- expect {
37
- XXssProtection.new(:mode => 'block')
38
- }.to raise_error(XXssProtectionBuildError)
27
+ expect do
28
+ XXssProtection.validate_config!("mode=block")
29
+ end.to raise_error(XXssProtectionConfigError)
39
30
  end
40
31
 
41
32
  it "should raise an error if an invalid key is supplied" do
42
- expect {
43
- XXssProtection.new(:value => 123)
44
- }.to raise_error(XXssProtectionBuildError)
33
+ expect do
34
+ XXssProtection.validate_config!("123")
35
+ end.to raise_error(XXssProtectionConfigError)
45
36
  end
46
37
 
47
38
  it "should raise an error if mode != block" do
48
- expect {
49
- XXssProtection.new(:value => 1, :mode => "donkey")
50
- }.to raise_error(XXssProtectionBuildError)
39
+ expect do
40
+ XXssProtection.validate_config!("1; mode=donkey")
41
+ end.to raise_error(XXssProtectionConfigError)
51
42
  end
52
43
  end
53
-
54
44
  end
55
45
  end
56
46
  end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ module SecureHeaders
4
+ describe Middleware do
5
+ let(:app) { ->(env) { [200, env, "app"] } }
6
+
7
+ let :middleware do
8
+ Middleware.new(app)
9
+ end
10
+
11
+ before(:each) do
12
+ reset_config
13
+ Configuration.default do |config|
14
+ # use all default provided by the library
15
+ end
16
+ end
17
+
18
+ it "sets the headers" do
19
+ _, env = middleware.call(Rack::MockRequest.env_for("https://looocalhost", {}))
20
+ expect_default_values(env)
21
+ end
22
+
23
+ it "respects overrides" do
24
+ request = Rack::Request.new("HTTP_X_FORWARDED_SSL" => "on")
25
+ SecureHeaders.override_x_frame_options(request, "DENY")
26
+ _, env = middleware.call request.env
27
+ expect(env[XFrameOptions::HEADER_NAME]).to eq("DENY")
28
+ end
29
+
30
+ it "uses named overrides" do
31
+ Configuration.override("my_custom_config") do |config|
32
+ config.csp[:script_src] = %w(example.org)
33
+ end
34
+ request = Rack::Request.new({})
35
+ SecureHeaders.use_secure_headers_override(request, "my_custom_config")
36
+ _, env = middleware.call request.env
37
+ expect(env[CSP::HEADER_NAME]).to match("example.org")
38
+ end
39
+ end
40
+ end