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.

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