secure_headers 2.5.2 → 2.5.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9f7672d8914364e8eef869c24c4fd82101944de
4
- data.tar.gz: c0e93e3380c8299eb0cef567ddebbcba2b72d1ed
3
+ metadata.gz: 294b9a718031dad10faeef1232529098e5ca6b1d
4
+ data.tar.gz: 4e937445b4e743d1e55934cf7355d99f793dd9cd
5
5
  SHA512:
6
- metadata.gz: 90011cbc58f5b045268542ef3798cd5d58ecafdb06c762c5eca118cadba2848e9520a9e583070cc3486f4e5a7ac2d1ef80822b16deaf452cfae797535f8c9580
7
- data.tar.gz: ff6e285cbec857db35dddbe110c47dbbc314ef2b937bf425bd3add5268751107e335c1f990d5c45f8915d8238b649c835109fdadb987e970653568064836efce
6
+ metadata.gz: 1873f2f27ad028125dbef4aafb27cb2b95dfdac50521e33003771ac1a62de0543fbc4f8dac1ca2001df6d0264f108ab0d3ad70572c26519da6a43b1d3bb0ea11
7
+ data.tar.gz: df5a83f54557f074f8da741b869844fabf8ae55657c08cf01d0aa3abbb01062187bbafa45061b2b69cdc9ca2606e7c819f763ec28e84527a933b8f057a172132
data/Gemfile CHANGED
@@ -3,7 +3,11 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem "guard-rspec", platforms: [:ruby_19, :ruby_20, :ruby_21, :ruby_22]
6
+ gem 'listen', '<= 3.0.8', :platforms => [:ruby_19, :ruby_20, :ruby_22]
7
+ gem "term-ansicolor", "< 1.4"
8
+ gem "tins", "< 1.3.4"
9
+
10
+ gem "guard-rspec", :platforms => [:ruby_19, :ruby_20, :ruby_21, :ruby_22]
7
11
  gem 'test-unit', '~> 3.0'
8
12
  gem 'rails', '3.2.22'
9
13
  gem 'sqlite3', :platforms => [:ruby, :mswin, :mingw]
data/README.md CHANGED
@@ -48,7 +48,7 @@ The following methods are going to be called, unless they are provided in a `ski
48
48
  :enforce => proc {|controller| controller.my_feature_flag_api.enabled? },
49
49
  :frame_src => "https: http:.twimg.com http://itunes.apple.com",
50
50
  :img_src => "https:",
51
- :connect_src => "wws:"
51
+ :connect_src => "wws:",
52
52
  :font_src => "'self' data:",
53
53
  :frame_src => "'self'",
54
54
  :img_src => "mycdn.com data:",
@@ -61,7 +61,7 @@ The following methods are going to be called, unless they are provided in a `ski
61
61
  :form_action => "'self' github.com",
62
62
  :frame_ancestors => "'none'",
63
63
  :plugin_types => 'application/x-shockwave-flash',
64
- :block_all_mixed_content => '' # see [http://www.w3.org/TR/mixed-content/]()
64
+ :block_all_mixed_content => '', # see [http://www.w3.org/TR/mixed-content/]()
65
65
  :report_uri => '//example.com/uri-directive'
66
66
  }
67
67
  config.hpkp = {
@@ -0,0 +1,158 @@
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
@@ -11,7 +11,7 @@ if defined?(Rails::Railtie)
11
11
 
12
12
  initializer "secure_headers.action_controller" do
13
13
  ActiveSupport.on_load(:action_controller) do
14
- include ::SecureHeaders
14
+ include ::SecureHeaders::ControllerExtension
15
15
 
16
16
  unless Rails.application.config.action_dispatch.default_headers.nil?
17
17
  conflicting_headers.each do |header|
@@ -26,7 +26,7 @@ if defined?(Rails::Railtie)
26
26
  else
27
27
  module ActionController
28
28
  class Base
29
- include ::SecureHeaders
29
+ include ::SecureHeaders::ControllerExtension
30
30
  end
31
31
  end
32
32
  end
@@ -1,3 +1,3 @@
1
1
  module SecureHeaders
2
- VERSION = "2.5.2"
2
+ VERSION = "2.5.3"
3
3
  end
@@ -8,6 +8,7 @@ require "secure_headers/headers/x_xss_protection"
8
8
  require "secure_headers/headers/x_content_type_options"
9
9
  require "secure_headers/headers/x_download_options"
10
10
  require "secure_headers/headers/x_permitted_cross_domain_policies"
11
+ require "secure_headers/controller_extension"
11
12
  require "secure_headers/railtie"
12
13
  require "secure_headers/hash_helper"
13
14
  require "secure_headers/view_helper"
@@ -62,10 +63,7 @@ module SecureHeaders
62
63
 
63
64
  class << self
64
65
  def append_features(base)
65
- base.module_eval do
66
- extend ClassMethods
67
- include InstanceMethods
68
- end
66
+ base.send(:include, ControllerExtension)
69
67
  end
70
68
 
71
69
  def header_hash(options = nil)
@@ -92,149 +90,4 @@ module SecureHeaders
92
90
  end
93
91
  end
94
92
 
95
- module ClassMethods
96
- attr_writer :secure_headers_options
97
- def secure_headers_options
98
- if @secure_headers_options
99
- @secure_headers_options
100
- elsif superclass.respond_to?(:secure_headers_options) # stop at application_controller
101
- superclass.secure_headers_options
102
- else
103
- {}
104
- end
105
- end
106
-
107
- def ensure_security_headers options = {}
108
- if RUBY_VERSION == "1.8.7"
109
- warn "[DEPRECATION] secure_headers ruby 1.8.7 support will dropped in the next release"
110
- end
111
- self.secure_headers_options = options
112
- hook = respond_to?(:before_action) ? :before_action : :before_filter
113
- ALL_FILTER_METHODS.each do |method|
114
- send(hook, method)
115
- end
116
- end
117
- end
118
-
119
- module InstanceMethods
120
- def set_security_headers(options = self.class.secure_headers_options)
121
- set_csp_header(request, options[:csp])
122
- set_hsts_header(options[:hsts])
123
- set_hpkp_header(options[:hpkp])
124
- set_x_frame_options_header(options[:x_frame_options])
125
- set_x_xss_protection_header(options[:x_xss_protection])
126
- set_x_content_type_options_header(options[:x_content_type_options])
127
- set_x_download_options_header(options[:x_download_options])
128
- set_x_permitted_cross_domain_policies_header(options[:x_permitted_cross_domain_policies])
129
- end
130
-
131
- # set_csp_header - uses the request accessor and SecureHeader::Configuration settings
132
- # set_csp_header(+Rack::Request+) - uses the parameter and and SecureHeader::Configuration settings
133
- # set_csp_header(+Hash+) - uses the request accessor and options from parameters
134
- # set_csp_header(+Rack::Request+, +Hash+)
135
- def set_csp_header(req = nil, config=nil)
136
- if req.is_a?(Hash) || req.is_a?(FalseClass)
137
- config = req
138
- end
139
-
140
- config = self.class.secure_headers_options[:csp] if config.nil?
141
- config = secure_header_options_for :csp, config
142
-
143
- return if config == false
144
-
145
- if config && config[:script_hash_middleware]
146
- ContentSecurityPolicy.add_to_env(request, self, config)
147
- else
148
- csp_header = ContentSecurityPolicy.new(config, :request => request, :controller => self)
149
- set_header(csp_header)
150
- end
151
- end
152
-
153
-
154
- def prep_script_hash
155
- if ::SecureHeaders::Configuration.script_hashes
156
- @script_hashes = ::SecureHeaders::Configuration.script_hashes.dup
157
- ActiveSupport::Notifications.subscribe("render_partial.action_view") do |event_name, start_at, end_at, id, payload|
158
- save_hash_for_later payload
159
- end
160
-
161
- ActiveSupport::Notifications.subscribe("render_template.action_view") do |event_name, start_at, end_at, id, payload|
162
- save_hash_for_later payload
163
- end
164
- end
165
- end
166
-
167
- def save_hash_for_later payload
168
- matching_hashes = @script_hashes[payload[:identifier].gsub(Rails.root.to_s + "/", "")] || []
169
-
170
- if payload[:layout]
171
- # 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
172
- layout_hashes = @script_hashes[File.join("app", "views", payload[:layout]) + '.html.erb']
173
-
174
- matching_hashes << layout_hashes if layout_hashes
175
- end
176
-
177
- if matching_hashes.any?
178
- request.env[HASHES_ENV_KEY] = ((request.env[HASHES_ENV_KEY] || []) << matching_hashes).flatten
179
- end
180
- end
181
-
182
- def set_x_frame_options_header(options=self.class.secure_headers_options[:x_frame_options])
183
- set_a_header(:x_frame_options, XFrameOptions, options)
184
- end
185
-
186
- def set_x_content_type_options_header(options=self.class.secure_headers_options[:x_content_type_options])
187
- set_a_header(:x_content_type_options, XContentTypeOptions, options)
188
- end
189
-
190
- def set_x_xss_protection_header(options=self.class.secure_headers_options[:x_xss_protection])
191
- set_a_header(:x_xss_protection, XXssProtection, options)
192
- end
193
-
194
- def set_hsts_header(options=self.class.secure_headers_options[:hsts])
195
- return unless request.ssl?
196
- set_a_header(:hsts, StrictTransportSecurity, options)
197
- end
198
-
199
- def set_hpkp_header(options=self.class.secure_headers_options[:hpkp])
200
- return unless request.ssl?
201
- config = secure_header_options_for :hpkp, options
202
-
203
- return if config == false || config.nil?
204
-
205
- hpkp_header = PublicKeyPins.new(config)
206
- set_header(hpkp_header)
207
- end
208
-
209
- def set_x_download_options_header(options=self.class.secure_headers_options[:x_download_options])
210
- set_a_header(:x_download_options, XDownloadOptions, options)
211
- end
212
-
213
- def set_x_permitted_cross_domain_policies_header(options=self.class.secure_headers_options[:x_permitted_cross_domain_policies])
214
- set_a_header(:x_permitted_cross_domain_policies, XPermittedCrossDomainPolicies, options)
215
- end
216
-
217
- private
218
-
219
- # we can't use ||= because I'm overloading false => disable, nil => default
220
- # both of which trigger the conditional assignment
221
- def secure_header_options_for(type, options)
222
- options.nil? ? ::SecureHeaders::Configuration.send(type) : options
223
- end
224
-
225
- def set_a_header(name, klass, options=nil)
226
- options = secure_header_options_for(name, options)
227
- return if options == false
228
- set_header(SecureHeaders::get_a_header(klass, options))
229
- end
230
-
231
- def set_header(name_or_header, value=nil)
232
- if name_or_header.is_a?(Header)
233
- header = name_or_header
234
- response.headers[header.name] = header.value
235
- else
236
- response.headers[name_or_header] = value
237
- end
238
- end
239
- end
240
93
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: secure_headers
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.2
4
+ version: 2.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Matatall
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-19 00:00:00.000000000 Z
11
+ date: 2016-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -138,6 +138,7 @@ files:
138
138
  - fixtures/rails_4_1_8/vendor/assets/javascripts/.keep
139
139
  - fixtures/rails_4_1_8/vendor/assets/stylesheets/.keep
140
140
  - lib/secure_headers.rb
141
+ - lib/secure_headers/controller_extension.rb
141
142
  - lib/secure_headers/hash_helper.rb
142
143
  - lib/secure_headers/header.rb
143
144
  - lib/secure_headers/headers/content_security_policy.rb