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
data/Rakefile CHANGED
@@ -7,44 +7,10 @@ require 'net/https'
7
7
  desc "Run RSpec"
8
8
  RSpec::Core::RakeTask.new do |t|
9
9
  t.verbose = false
10
- t.rspec_opts = "--format progress"
10
+ t.rspec_opts = "--format progress"
11
11
  end
12
12
 
13
- task :default => :all_spec
14
-
15
- desc "Run all specs, and test fixture apps"
16
- task :all_spec => :spec do
17
- pwd = Dir.pwd
18
- Dir.chdir 'fixtures/rails_3_2_22'
19
- puts Dir.pwd
20
- str = `bundle install >> /dev/null; bundle exec rspec spec`
21
- puts str
22
- unless $? == 0
23
- Dir.chdir pwd
24
- fail "Header tests with app not using initializer failed exit code: #{$?}"
25
- end
26
-
27
- Dir.chdir pwd
28
- Dir.chdir 'fixtures/rails_3_2_22_no_init'
29
- puts Dir.pwd
30
- puts `bundle install >> /dev/null; bundle exec rspec spec`
31
-
32
- unless $? == 0
33
- fail "Header tests with app not using initializer failed"
34
- Dir.chdir pwd
35
- end
36
-
37
- Dir.chdir pwd
38
- Dir.chdir 'fixtures/rails_4_1_8'
39
- puts Dir.pwd
40
- puts `bundle install >> /dev/null; bundle exec rspec spec`
41
-
42
- unless $? == 0
43
- fail "Header tests with Rails 4 failed"
44
- Dir.chdir pwd
45
- end
46
-
47
- end
13
+ task default: :spec
48
14
 
49
15
  begin
50
16
  require 'rdoc/task'
@@ -0,0 +1,189 @@
1
+ module SecureHeaders
2
+ class Configuration
3
+ DEFAULT_CONFIG = :default
4
+ NOOP_CONFIGURATION = "secure_headers_noop_config"
5
+ class NotYetConfiguredError < StandardError; end
6
+ class << self
7
+ # Public: Set the global default configuration.
8
+ #
9
+ # Optionally supply a block to override the defaults set by this library.
10
+ #
11
+ # Returns the newly created config.
12
+ def default(&block)
13
+ config = new(&block)
14
+ add_noop_configuration
15
+ add_configuration(DEFAULT_CONFIG, config)
16
+ end
17
+ alias_method :configure, :default
18
+
19
+ # Public: create a named configuration that overrides the default config.
20
+ #
21
+ # name - use an idenfier for the override config.
22
+ # base - override another existing config, or override the default config
23
+ # if no value is supplied.
24
+ #
25
+ # Returns: the newly created config
26
+ def override(name, base = DEFAULT_CONFIG)
27
+ unless get(base)
28
+ raise NotYetConfiguredError, "#{base} policy not yet supplied"
29
+ end
30
+ override = @configurations[base].dup
31
+ yield(override)
32
+ add_configuration(name, override)
33
+ end
34
+
35
+ # Public: retrieve a global configuration object
36
+ #
37
+ # Returns the configuration with a given name or raises a
38
+ # NotYetConfiguredError if `default` has not been called.
39
+ def get(name = DEFAULT_CONFIG)
40
+ if @configurations.nil?
41
+ raise NotYetConfiguredError, "Default policy not yet supplied"
42
+ end
43
+ @configurations[name]
44
+ end
45
+
46
+ # Public: perform a basic deep dup. The shallow copy provided by dup/clone
47
+ # can lead to modifying parent objects.
48
+ def deep_copy(config)
49
+ config.each_with_object({}) do |(key, value), hash|
50
+ hash[key] = if value.is_a?(Array)
51
+ value.dup
52
+ else
53
+ value
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Private: add a valid configuration to the global set of named configs.
61
+ #
62
+ # config - the config to store
63
+ # name - the lookup value for this config
64
+ #
65
+ # Raises errors if the config is invalid or if a config named `name`
66
+ # already exists.
67
+ #
68
+ # Returns the config, if valid
69
+ def add_configuration(name, config)
70
+ config.validate_config!
71
+ @configurations ||= {}
72
+ config.send(:cache_headers!)
73
+ config.freeze
74
+ @configurations[name] = config
75
+ end
76
+
77
+ # Private: Automatically add an "opt-out of everything" override.
78
+ #
79
+ # Returns the noop config
80
+ def add_noop_configuration
81
+ noop_config = new do |config|
82
+ ALL_HEADER_CLASSES.each do |klass|
83
+ config.send("#{klass::CONFIG_KEY}=", OPT_OUT)
84
+ end
85
+ end
86
+
87
+ add_configuration(NOOP_CONFIGURATION, noop_config)
88
+ end
89
+ end
90
+
91
+ attr_accessor :hsts, :x_frame_options, :x_content_type_options,
92
+ :x_xss_protection, :csp, :x_download_options, :x_permitted_cross_domain_policies,
93
+ :hpkp
94
+ attr_reader :cached_headers
95
+
96
+ def initialize(&block)
97
+ self.hpkp = OPT_OUT
98
+ self.csp = self.class.deep_copy(CSP::DEFAULT_CONFIG)
99
+ instance_eval &block if block_given?
100
+ end
101
+
102
+ # Public: copy everything but the cached headers
103
+ #
104
+ # Returns a deep-dup'd copy of this configuration.
105
+ def dup
106
+ copy = self.class.new
107
+ copy.hsts = hsts
108
+ copy.x_frame_options = x_frame_options
109
+ copy.x_content_type_options = x_content_type_options
110
+ copy.x_xss_protection = x_xss_protection
111
+ copy.x_download_options = x_download_options
112
+ copy.x_permitted_cross_domain_policies = x_permitted_cross_domain_policies
113
+ copy.csp = if csp.is_a?(Hash)
114
+ self.class.deep_copy(csp)
115
+ else
116
+ csp
117
+ end
118
+
119
+ copy.hpkp = if hpkp.is_a?(Hash)
120
+ self.class.deep_copy(hpkp)
121
+ else
122
+ hpkp
123
+ end
124
+ copy
125
+ end
126
+
127
+ # Public: Retrieve a config based on the CONFIG_KEY for a class
128
+ #
129
+ # Returns the value if available, and returns a dup of any hash values.
130
+ def fetch(key)
131
+ config = send(key)
132
+ config = self.class.deep_copy(config) if config.is_a?(Hash)
133
+ config
134
+ end
135
+
136
+ # Public: validates all configurations values.
137
+ #
138
+ # Raises various configuration errors if any invalid config is detected.
139
+ #
140
+ # Returns nothing
141
+ def validate_config!
142
+ StrictTransportSecurity.validate_config!(hsts)
143
+ ContentSecurityPolicy.validate_config!(csp)
144
+ XFrameOptions.validate_config!(x_frame_options)
145
+ XContentTypeOptions.validate_config!(x_content_type_options)
146
+ XXssProtection.validate_config!(x_xss_protection)
147
+ XDownloadOptions.validate_config!(x_download_options)
148
+ XPermittedCrossDomainPolicies.validate_config!(x_permitted_cross_domain_policies)
149
+ PublicKeyPins.validate_config!(hpkp)
150
+ end
151
+
152
+ # Public: Precompute the header names and values for this configuraiton.
153
+ # Ensures that headers generated at configure time, not on demand.
154
+ #
155
+ # Returns the cached headers
156
+ def cache_headers!
157
+ # generate defaults for the "easy" headers
158
+ headers = (ALL_HEADERS_BESIDES_CSP).each_with_object({}) do |klass, hash|
159
+ config = fetch(klass::CONFIG_KEY)
160
+ unless config == OPT_OUT
161
+ hash[klass::CONFIG_KEY] = klass.make_header(config).freeze
162
+ end
163
+ end
164
+
165
+ generate_csp_headers(headers)
166
+
167
+ headers.freeze
168
+ @cached_headers = headers
169
+ end
170
+
171
+ # Private: adds CSP headers for each variation of CSP support.
172
+ #
173
+ # headers - generated headers are added to this hash namespaced by The
174
+ # different variations
175
+ #
176
+ # Returns nothing
177
+ def generate_csp_headers(headers)
178
+ unless csp == OPT_OUT
179
+ headers[CSP::CONFIG_KEY] = {}
180
+
181
+ CSP::VARIATIONS.each do |name, _|
182
+ csp_config = fetch(CSP::CONFIG_KEY)
183
+ csp = CSP.make_header(csp_config, UserAgent.parse(name))
184
+ headers[CSP::CONFIG_KEY][name] = csp.freeze
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end