secure_headers 1.2.0 → 1.3.0
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 +8 -8
- data/Gemfile +0 -2
- data/HISTORY.md +9 -13
- data/README.md +54 -28
- data/fixtures/rails_3_2_12/Gemfile +0 -2
- data/fixtures/rails_3_2_12/config/initializers/secure_headers.rb +1 -0
- data/fixtures/rails_3_2_12/spec/controllers/other_things_controller_spec.rb +4 -3
- data/fixtures/rails_3_2_12/spec/spec_helper.rb +1 -4
- data/fixtures/rails_3_2_12_no_init/Gemfile +0 -2
- data/fixtures/rails_3_2_12_no_init/spec/controllers/other_things_controller_spec.rb +1 -1
- data/fixtures/rails_3_2_12_no_init/spec/spec_helper.rb +3 -17
- data/lib/secure_headers/headers/content_security_policy.rb +33 -23
- data/lib/secure_headers/padrino.rb +14 -0
- data/lib/secure_headers/version.rb +1 -1
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +38 -10
- data/spec/spec_helper.rb +9 -23
- metadata +4 -5
- data/fixtures/rails_3_2_12/Guardfile +0 -14
- data/fixtures/rails_3_2_12_no_init/Guardfile +0 -14
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NTdiMjdmYmVhNzk2MWQ3YmEwNDNjOWQ0YmZhZDZkNTAyNDlmYmQ1ZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZTIyYjBjNmM5ZTU5YzRhZjU4MjdmNTcwNDAzMjMyZjJlOTFjOWYxMA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NzRjM2QwM2IwZjIyZDMzYzY3OWE2MGVmZTEyNjU3MmQwMzhiODcxYjRlZDlh
|
10
|
+
ODFmMmExNzgxNDkzN2U5YWFiNGFjYWMwYjUxNGNiMmJiOWM4ZTA0ZmY3Y2Mz
|
11
|
+
MjFlMTRlNzdiMGQ0MDY5NTM1YTkyNGMxOGJjMDRmMjkyZTIyMjA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
N2I3MzExNWM5MGFjZDI3YjBjMDlkNjgyNWUyODcyZGU3N2NmMjVjZTZkMWVi
|
14
|
+
Y2FiYmI4YjY3NzRkYzM3NWNkNjE0MGE4ZWMwMjhlMGJhYTI0NmIwYmY4MGFi
|
15
|
+
YjlhNjdkMTQ1YWQ0NTYwNGJiZmMxMzA3MjlkNmMyMDgyZjhlY2E=
|
data/Gemfile
CHANGED
@@ -7,12 +7,10 @@ group :test do
|
|
7
7
|
gem 'sqlite3', :platform => [:ruby, :mswin, :mingw]
|
8
8
|
gem 'jdbc-sqlite3', :platform => :jruby
|
9
9
|
gem 'rspec-rails'
|
10
|
-
gem 'spork'
|
11
10
|
gem 'rspec'
|
12
11
|
gem 'guard-rspec', :platform => :ruby_19
|
13
12
|
gem 'growl'
|
14
13
|
gem 'rb-fsevent'
|
15
|
-
gem 'simplecov'
|
16
14
|
gem 'debugger', :platform => :ruby_19
|
17
15
|
gem 'ruby-debug', :platform => :ruby_18
|
18
16
|
end
|
data/HISTORY.md
CHANGED
@@ -1,18 +1,14 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
2
2
|
======
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
'//example.com/old_csp'
|
13
|
-
end
|
14
|
-
}
|
15
|
-
}
|
4
|
+
- CSP nonce support was added back and is compliant.
|
5
|
+
- Bugs:
|
6
|
+
-- enforce, disable_fill_missing, and disable_chrome_extension did not accept lambdas for no good reason
|
7
|
+
-- IF a default-src was specified, and an img-src was not, and disable_fill_missing was true, the img-src value would be :data
|
8
|
+
|
9
|
+
1.2.0
|
10
|
+
======
|
11
|
+
- Allow procs to be used as config values.
|
16
12
|
|
17
13
|
1.1.1
|
18
14
|
======
|
data/README.md
CHANGED
@@ -118,9 +118,6 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
|
|
118
118
|
|
119
119
|
```ruby
|
120
120
|
:csp => {
|
121
|
-
|
122
|
-
# All values can be a String of space-delimited values, an Array of Strings, or procs.
|
123
|
-
|
124
121
|
:enforce => false, # sets header to report-only, by default
|
125
122
|
# default_src is required!
|
126
123
|
:default_src => nil, # sets the default-src/allow+options directives
|
@@ -193,19 +190,40 @@ and [Mozilla CSP specification](https://wiki.mozilla.org/Security/CSP/Specificat
|
|
193
190
|
:csp => {
|
194
191
|
:default_src => 'self',
|
195
192
|
:img_src => '*',
|
196
|
-
:connect_src => 'none'
|
197
193
|
:object_src => ['media1.com', 'media2.com', '*.cdn.com'],
|
198
|
-
# alternatively :object_src => 'media1.com media2.com *.cdn.com'
|
199
|
-
:script_src => 'trustedscripts.example.com'
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
194
|
+
# alternatively (NOT csv) :object_src => 'media1.com media2.com *.cdn.com'
|
195
|
+
:script_src => 'trustedscripts.example.com'
|
196
|
+
}
|
197
|
+
"default-src 'self'; img-src *; object-src media1.com media2.com *.cdn.com; script-src trustedscripts.example.com;"
|
198
|
+
```
|
199
|
+
|
200
|
+
### CSP Level 2 features
|
201
|
+
|
202
|
+
script/style-nonce can be used to whitelist inline content. To do this, add "nonce" to your script/style-src configuration, then set the nonce attributes on the various tags.
|
203
|
+
|
204
|
+
*setting a nonce will also set 'unsafe-inline' for browsers that don't support nonces for backwards compatibility. 'unsafe-inline' is ignored if a nonce is present in a directive in compliant browsers.
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
:csp => {
|
208
|
+
:default_src => 'self',
|
209
|
+
:script_src => 'self nonce'
|
207
210
|
}
|
208
|
-
|
211
|
+
```
|
212
|
+
|
213
|
+
> content-security-policy: default-src 'self'; script-src 'self' 'nonce-abc123' 'unsafe-inline'
|
214
|
+
|
215
|
+
```erb
|
216
|
+
<script nonce="<%= @content_security_policy_nonce %>">
|
217
|
+
console.log("whitelisted, will execute")
|
218
|
+
</script>
|
219
|
+
|
220
|
+
<script nonce="lol">
|
221
|
+
console.log("won't execute, not whitelisted")
|
222
|
+
</script>
|
223
|
+
|
224
|
+
<script>
|
225
|
+
console.log("won't execute, not whitelisted")
|
226
|
+
</script>
|
209
227
|
```
|
210
228
|
|
211
229
|
## Note on Firefox handling of CSP
|
@@ -277,22 +295,11 @@ In your `Gemfile`:
|
|
277
295
|
then in your `app.rb` file you can:
|
278
296
|
|
279
297
|
```ruby
|
298
|
+
require 'secure_headers/padrino'
|
299
|
+
|
280
300
|
module Web
|
281
301
|
class App < Padrino::Application
|
282
|
-
|
283
|
-
|
284
|
-
::SecureHeaders::Configuration.configure do |config|
|
285
|
-
config.hsts = {:max_age => 99, :include_subdomains => true}
|
286
|
-
config.x_frame_options = 'DENY'
|
287
|
-
config.x_content_type_options = "nosniff"
|
288
|
-
config.x_xss_protection = {:value => '1', :mode => false}
|
289
|
-
config.csp = {
|
290
|
-
:default_src => "https://* inline eval",
|
291
|
-
:report_uri => '//example.com/uri-directive',
|
292
|
-
:img_src => "https://* data:",
|
293
|
-
:frame_src => "https://* http://*.twimg.com http://itunes.apple.com"
|
294
|
-
}
|
295
|
-
end
|
302
|
+
register SecureHeaders::Padrino
|
296
303
|
|
297
304
|
get '/' do
|
298
305
|
set_csp_header
|
@@ -302,6 +309,25 @@ module Web
|
|
302
309
|
end
|
303
310
|
```
|
304
311
|
|
312
|
+
and in `config/boot.rb`:
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
def before_load
|
316
|
+
::SecureHeaders::Configuration.configure do |config|
|
317
|
+
config.hsts = {:max_age => 99, :include_subdomains => true}
|
318
|
+
config.x_frame_options = 'DENY'
|
319
|
+
config.x_content_type_options = "nosniff"
|
320
|
+
config.x_xss_protection = {:value => '1', :mode => false}
|
321
|
+
config.csp = {
|
322
|
+
:default_src => "https://* inline eval",
|
323
|
+
:report_uri => '//example.com/uri-directive',
|
324
|
+
:img_src => "https://* data:",
|
325
|
+
:frame_src => "https://* http://*.twimg.com http://itunes.apple.com"
|
326
|
+
}
|
327
|
+
end
|
328
|
+
end
|
329
|
+
```
|
330
|
+
|
305
331
|
## Similar libraries
|
306
332
|
|
307
333
|
* Node.js (express) [helmet](https://github.com/evilpacket/helmet) and [hood](https://github.com/seanmonstar/hood)
|
@@ -4,11 +4,9 @@ gem 'rails', '3.2.12'
|
|
4
4
|
gem 'sqlite3'
|
5
5
|
gem 'rspec-rails', '>= 2.0.0'
|
6
6
|
gem 'secure_headers', :path => '../..'
|
7
|
-
gem 'spork'
|
8
7
|
gem 'debugger', :platform => :ruby_19
|
9
8
|
gem 'ruby-debug', :platform => :ruby_18
|
10
9
|
gem 'guard-rspec'
|
11
|
-
gem 'guard-spork'
|
12
10
|
gem 'rb-fsevent'
|
13
11
|
gem 'growl'
|
14
12
|
|
@@ -12,12 +12,13 @@ describe OtherThingsController, :type => :controller do
|
|
12
12
|
expect(response.headers['X-Frame-Options']).to eq('SAMEORIGIN')
|
13
13
|
end
|
14
14
|
|
15
|
-
it "sets the
|
15
|
+
it "sets the CSP header with a local reference to a nonce" do
|
16
16
|
get :index
|
17
|
-
|
17
|
+
nonce = controller.instance_exec { @content_security_policy_nonce }
|
18
|
+
expect(nonce).to match /[a-zA-Z0-9\+\/=]{44}/
|
19
|
+
expect(response.headers['Content-Security-Policy-Report-Only']).to match(/default-src 'self'; img-src 'self' data:; script-src 'self' 'nonce-[a-zA-Z0-9\+\/=]{44}' 'unsafe-inline'; report-uri somewhere;/)
|
18
20
|
end
|
19
21
|
|
20
|
-
#mock ssl
|
21
22
|
it "sets the Strict-Transport-Security header" do
|
22
23
|
request.env['HTTPS'] = 'on'
|
23
24
|
get :index
|
@@ -4,11 +4,9 @@ gem 'rails', '3.2.12'
|
|
4
4
|
gem 'sqlite3'
|
5
5
|
gem 'rspec-rails', '>= 2.0.0'
|
6
6
|
gem 'secure_headers', :path => '../..'
|
7
|
-
gem 'spork'
|
8
7
|
gem 'debugger', :platform => :ruby_19
|
9
8
|
gem 'ruby-debug', :platform => :ruby_18
|
10
9
|
gem 'guard-rspec'
|
11
|
-
gem 'guard-spork'
|
12
10
|
gem 'rb-fsevent'
|
13
11
|
gem 'growl'
|
14
12
|
|
@@ -14,7 +14,7 @@ describe OtherThingsController, :type => :controller do
|
|
14
14
|
|
15
15
|
it "sets the X-WebKit-CSP header" do
|
16
16
|
get :index
|
17
|
-
expect(response.headers['Content-Security-Policy-Report-Only']).to eq("default-src 'self'; img-src data:;")
|
17
|
+
expect(response.headers['Content-Security-Policy-Report-Only']).to eq("default-src 'self'; img-src 'self' data:;")
|
18
18
|
end
|
19
19
|
|
20
20
|
#mock ssl
|
@@ -1,19 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'spork'
|
3
|
-
#uncomment the following line to use spork with the debugger
|
4
|
-
#require 'spork/ext/ruby-debug'
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
# require 'ruby-debug'
|
15
|
-
end
|
16
|
-
|
17
|
-
Spork.each_run do
|
18
|
-
|
19
|
-
end
|
3
|
+
ENV["RAILS_ENV"] ||= 'test'
|
4
|
+
require File.expand_path("../../config/environment", __FILE__)
|
5
|
+
require 'rspec/rails'
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'base64'
|
2
3
|
|
3
4
|
module SecureHeaders
|
4
5
|
class ContentSecurityPolicyBuildError < StandardError; end
|
@@ -8,7 +9,7 @@ module SecureHeaders
|
|
8
9
|
STANDARD_HEADER_NAME = "Content-Security-Policy"
|
9
10
|
FF_CSP_ENDPOINT = "/content_security_policy/forward_report"
|
10
11
|
DIRECTIVES = [:default_src, :script_src, :frame_src, :style_src, :img_src, :media_src, :font_src, :object_src, :connect_src]
|
11
|
-
META = [:
|
12
|
+
META = [:disable_chrome_extension, :disable_fill_missing, :forward_endpoint]
|
12
13
|
end
|
13
14
|
include Constants
|
14
15
|
|
@@ -30,6 +31,7 @@ module SecureHeaders
|
|
30
31
|
def initialize(config=nil, options={})
|
31
32
|
@experimental = !!options.delete(:experimental)
|
32
33
|
@controller = options.delete(:controller)
|
34
|
+
|
33
35
|
if options[:request]
|
34
36
|
parse_request(options[:request])
|
35
37
|
else
|
@@ -45,6 +47,10 @@ module SecureHeaders
|
|
45
47
|
configure(config) if config
|
46
48
|
end
|
47
49
|
|
50
|
+
def nonce
|
51
|
+
@nonce ||= SecureRandom.base64(32).chomp
|
52
|
+
end
|
53
|
+
|
48
54
|
def configure(config)
|
49
55
|
@config = config.dup
|
50
56
|
|
@@ -54,18 +60,24 @@ module SecureHeaders
|
|
54
60
|
@config.merge!(experimental_config)
|
55
61
|
end
|
56
62
|
|
63
|
+
# http_additions will be the only field that still doesn't support
|
64
|
+
# lambdas because it's an ugly api that's showing it's age.
|
65
|
+
@http_additions = @config.delete(:http_additions)
|
66
|
+
|
67
|
+
normalize_csp_options
|
68
|
+
|
57
69
|
META.each do |meta|
|
58
70
|
self.send("#{meta}=", @config.delete(meta))
|
59
71
|
end
|
60
72
|
|
61
|
-
|
73
|
+
@enforce = @config.delete(:enforce)
|
62
74
|
normalize_reporting_endpoint
|
63
75
|
fill_directives unless disable_fill_missing?
|
64
76
|
end
|
65
77
|
|
66
78
|
def name
|
67
79
|
base = STANDARD_HEADER_NAME
|
68
|
-
if
|
80
|
+
if !@enforce || experimental
|
69
81
|
base += "-Report-Only"
|
70
82
|
end
|
71
83
|
base
|
@@ -86,15 +98,9 @@ module SecureHeaders
|
|
86
98
|
raise "Expected to find default_src directive value" unless @config[:default_src]
|
87
99
|
append_http_additions unless ssl_request?
|
88
100
|
header_value = [
|
89
|
-
# ensure default-src is first
|
90
|
-
build_directive(:default_src),
|
91
101
|
generic_directives(@config),
|
92
102
|
report_uri_directive
|
93
|
-
].join
|
94
|
-
|
95
|
-
#store the value for next time
|
96
|
-
@config = header_value
|
97
|
-
header_value.strip
|
103
|
+
].join.strip
|
98
104
|
rescue StandardError => e
|
99
105
|
raise ContentSecurityPolicyBuildError.new("Couldn't build CSP header :( #{e}")
|
100
106
|
end
|
@@ -111,27 +117,27 @@ module SecureHeaders
|
|
111
117
|
end
|
112
118
|
|
113
119
|
def append_http_additions
|
114
|
-
return unless http_additions
|
115
|
-
http_additions.each do |k, v|
|
120
|
+
return unless @http_additions
|
121
|
+
@http_additions.each do |k, v|
|
116
122
|
@config[k] ||= []
|
117
123
|
@config[k] << v
|
118
124
|
end
|
119
125
|
end
|
120
126
|
|
121
127
|
def normalize_csp_options
|
122
|
-
@config = @config.inject({}) do |hash, (
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
v
|
127
|
-
end
|
128
|
-
|
128
|
+
@config = @config.inject({}) do |hash, (key, value)|
|
129
|
+
# lambdas
|
130
|
+
config_val = value.respond_to?(:call) ? value.call : value
|
131
|
+
# space-delimeted strings
|
129
132
|
config_val = config_val.split if config_val.is_a? String
|
130
|
-
|
131
|
-
|
133
|
+
# array of strings
|
134
|
+
if config_val.respond_to?(:map) #skip booleans
|
135
|
+
config_val = config_val.map do |val|
|
136
|
+
translate_dir_value(val)
|
137
|
+
end.flatten.uniq
|
132
138
|
end
|
133
139
|
|
134
|
-
hash[
|
140
|
+
hash[key] = config_val
|
135
141
|
hash
|
136
142
|
end
|
137
143
|
|
@@ -145,6 +151,9 @@ module SecureHeaders
|
|
145
151
|
# self/none are special sources/src-dir-values and need to be quoted in chrome
|
146
152
|
elsif %{self none}.include?(val)
|
147
153
|
"'#{val}'"
|
154
|
+
elsif val == 'nonce'
|
155
|
+
@controller.instance_variable_set(:@content_security_policy_nonce, nonce)
|
156
|
+
["'nonce-#{nonce}'", "'unsafe-inline'"]
|
148
157
|
else
|
149
158
|
val
|
150
159
|
end
|
@@ -192,9 +201,10 @@ module SecureHeaders
|
|
192
201
|
if config[:img_src]
|
193
202
|
config[:img_src] = config[:img_src] + ['data:'] unless config[:img_src].include?('data:')
|
194
203
|
else
|
195
|
-
config[:img_src] = ['data:']
|
204
|
+
config[:img_src] = config[:default_src] + ['data:']
|
196
205
|
end
|
197
206
|
|
207
|
+
header_value = build_directive(:default_src)
|
198
208
|
config.keys.sort_by{|k| k.to_s}.each do |k| # ensure consistent ordering
|
199
209
|
header_value += build_directive(k)
|
200
210
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SecureHeaders
|
2
|
+
module Padrino
|
3
|
+
class << self
|
4
|
+
##
|
5
|
+
# Main class that register this extension.
|
6
|
+
#
|
7
|
+
def registered(app)
|
8
|
+
app.extend SecureHeaders::ClassMethods
|
9
|
+
app.helpers SecureHeaders::InstanceMethods
|
10
|
+
end
|
11
|
+
alias :included :registered
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -91,11 +91,14 @@ module SecureHeaders
|
|
91
91
|
|
92
92
|
it "accepts procs for other fields" do
|
93
93
|
opts = {
|
94
|
-
:default_src => lambda { "http://lambda/result" }
|
94
|
+
:default_src => lambda { "http://lambda/result" },
|
95
|
+
:enforce => lambda { true },
|
96
|
+
:disable_fill_missing => lambda { true }
|
95
97
|
}
|
96
98
|
|
97
|
-
csp = ContentSecurityPolicy.new(opts)
|
98
|
-
expect(csp).to
|
99
|
+
csp = ContentSecurityPolicy.new(opts)
|
100
|
+
expect(csp.value).to eq("default-src http://lambda/result; img-src http://lambda/result data:;")
|
101
|
+
expect(csp.name).to match("Content-Security-Policy")
|
99
102
|
end
|
100
103
|
end
|
101
104
|
end
|
@@ -219,7 +222,7 @@ module SecureHeaders
|
|
219
222
|
context "auto-whitelists data: uris for img-src" do
|
220
223
|
it "sets the value if no img-src specified" do
|
221
224
|
csp = ContentSecurityPolicy.new({:default_src => 'self', :disable_fill_missing => true, :disable_chrome_extension => true}, :request => request_for(CHROME))
|
222
|
-
expect(csp.value).to eq("default-src 'self'; img-src data:;")
|
225
|
+
expect(csp.value).to eq("default-src 'self'; img-src 'self' data:;")
|
223
226
|
end
|
224
227
|
|
225
228
|
it "appends the value if img-src is specified" do
|
@@ -243,14 +246,14 @@ module SecureHeaders
|
|
243
246
|
context "Firefox" do
|
244
247
|
it "builds a csp header for firefox" do
|
245
248
|
csp = ContentSecurityPolicy.new(default_opts, :request => request_for(FIREFOX))
|
246
|
-
expect(csp.value).to eq("default-src https://*; img-src data:; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* about:; report-uri /csp_report;")
|
249
|
+
expect(csp.value).to eq("default-src https://*; img-src https://* data:; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* about:; report-uri /csp_report;")
|
247
250
|
end
|
248
251
|
end
|
249
252
|
|
250
253
|
context "Chrome" do
|
251
254
|
it "builds a csp header for chrome" do
|
252
255
|
csp = ContentSecurityPolicy.new(default_opts, :request => request_for(CHROME))
|
253
|
-
expect(csp.value).to eq("default-src https://*; img-src data:; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* about:; report-uri /csp_report;")
|
256
|
+
expect(csp.value).to eq("default-src https://*; img-src https://* data:; script-src 'unsafe-inline' 'unsafe-eval' https://* data:; style-src 'unsafe-inline' https://* about:; report-uri /csp_report;")
|
254
257
|
end
|
255
258
|
|
256
259
|
it "ignores :forward_endpoint settings" do
|
@@ -259,6 +262,31 @@ module SecureHeaders
|
|
259
262
|
end
|
260
263
|
end
|
261
264
|
|
265
|
+
context "when using a nonce" do
|
266
|
+
it "adds a nonce and unsafe-inline to the script-src value" do
|
267
|
+
header = ContentSecurityPolicy.new(default_opts.merge(:script_src => "self nonce"), :request => request_for(CHROME))
|
268
|
+
expect(header.value).to include("script-src 'self' 'nonce-#{header.nonce}' 'unsafe-inline'")
|
269
|
+
end
|
270
|
+
|
271
|
+
it "adds a nonce and unsafe-inline to the style-src value" do
|
272
|
+
header = ContentSecurityPolicy.new(default_opts.merge(:style_src => "self nonce"), :request => request_for(CHROME))
|
273
|
+
expect(header.value).to include("style-src 'self' 'nonce-#{header.nonce}' 'unsafe-inline'")
|
274
|
+
end
|
275
|
+
|
276
|
+
it "adds an identical nonce to the style and script-src directives" do
|
277
|
+
header = ContentSecurityPolicy.new(default_opts.merge(:style_src => "self nonce", :script_src => "self nonce"), :request => request_for(CHROME))
|
278
|
+
nonce = header.nonce
|
279
|
+
value = header.value
|
280
|
+
expect(value).to include("style-src 'self' 'nonce-#{nonce}' 'unsafe-inline'")
|
281
|
+
expect(value).to include("script-src 'self' 'nonce-#{nonce}' 'unsafe-inline'")
|
282
|
+
end
|
283
|
+
|
284
|
+
it "does not add 'unsafe-inline' twice" do
|
285
|
+
header = ContentSecurityPolicy.new(default_opts.merge(:script_src => "self nonce inline"), :request => request_for(CHROME))
|
286
|
+
expect(header.value).to include("script-src 'self' 'nonce-#{header.nonce}' 'unsafe-inline';")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
262
290
|
context "when supplying a experimental values" do
|
263
291
|
let(:options) {{
|
264
292
|
:disable_chrome_extension => true,
|
@@ -272,7 +300,7 @@ module SecureHeaders
|
|
272
300
|
|
273
301
|
it "returns the original value" do
|
274
302
|
header = ContentSecurityPolicy.new(options, :request => request_for(CHROME))
|
275
|
-
expect(header.value).to eq("default-src 'self'; img-src data:; script-src https://*;")
|
303
|
+
expect(header.value).to eq("default-src 'self'; img-src 'self' data:; script-src https://*;")
|
276
304
|
end
|
277
305
|
|
278
306
|
it "it returns the experimental value if requested" do
|
@@ -333,17 +361,17 @@ module SecureHeaders
|
|
333
361
|
|
334
362
|
it "uses the value in the experimental block over SSL" do
|
335
363
|
csp = ContentSecurityPolicy.new(options, :experimental => true, :request => request_for(FIREFOX, '/', :ssl => true))
|
336
|
-
expect(csp.value).to eq("default-src 'self'; img-src data:; script-src 'self';")
|
364
|
+
expect(csp.value).to eq("default-src 'self'; img-src 'self' data:; script-src 'self';")
|
337
365
|
end
|
338
366
|
|
339
367
|
it "detects the :ssl => true option" do
|
340
368
|
csp = ContentSecurityPolicy.new(options, :experimental => true, :ua => FIREFOX, :ssl => true)
|
341
|
-
expect(csp.value).to eq("default-src 'self'; img-src data:; script-src 'self';")
|
369
|
+
expect(csp.value).to eq("default-src 'self'; img-src 'self' data:; script-src 'self';")
|
342
370
|
end
|
343
371
|
|
344
372
|
it "merges the values from experimental/http_additions when not over SSL" do
|
345
373
|
csp = ContentSecurityPolicy.new(options, :experimental => true, :request => request_for(FIREFOX))
|
346
|
-
expect(csp.value).to eq("default-src 'self'; img-src data:; script-src 'self' https://mycdn.example.com;")
|
374
|
+
expect(csp.value).to eq("default-src 'self'; img-src 'self' data:; script-src 'self' https://mycdn.example.com;")
|
347
375
|
end
|
348
376
|
end
|
349
377
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,24 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
Spork.prefork do
|
12
|
-
require 'rspec'
|
13
|
-
end
|
14
|
-
|
15
|
-
Spork.each_run do
|
16
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'secure_headers')
|
17
|
-
require File.join(File.dirname(__FILE__), '..', 'app', 'controllers', 'content_security_policy_controller')
|
18
|
-
include ::SecureHeaders::StrictTransportSecurity::Constants
|
19
|
-
include ::SecureHeaders::ContentSecurityPolicy::Constants
|
20
|
-
include ::SecureHeaders::XFrameOptions::Constants
|
21
|
-
include ::SecureHeaders::XXssProtection::Constants
|
22
|
-
include ::SecureHeaders::XContentTypeOptions::Constants
|
23
|
-
end
|
24
|
-
|
2
|
+
require 'rspec'
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'secure_headers')
|
5
|
+
require File.join(File.dirname(__FILE__), '..', 'app', 'controllers', 'content_security_policy_controller')
|
6
|
+
include ::SecureHeaders::StrictTransportSecurity::Constants
|
7
|
+
include ::SecureHeaders::ContentSecurityPolicy::Constants
|
8
|
+
include ::SecureHeaders::XFrameOptions::Constants
|
9
|
+
include ::SecureHeaders::XXssProtection::Constants
|
10
|
+
include ::SecureHeaders::XContentTypeOptions::Constants
|
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: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Neil Matatall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -46,7 +46,6 @@ files:
|
|
46
46
|
- config/routes.rb
|
47
47
|
- fixtures/rails_3_2_12/.rspec
|
48
48
|
- fixtures/rails_3_2_12/Gemfile
|
49
|
-
- fixtures/rails_3_2_12/Guardfile
|
50
49
|
- fixtures/rails_3_2_12/README.rdoc
|
51
50
|
- fixtures/rails_3_2_12/Rakefile
|
52
51
|
- fixtures/rails_3_2_12/app/controllers/application_controller.rb
|
@@ -87,7 +86,6 @@ files:
|
|
87
86
|
- fixtures/rails_3_2_12/vendor/plugins/.gitkeep
|
88
87
|
- fixtures/rails_3_2_12_no_init/.rspec
|
89
88
|
- fixtures/rails_3_2_12_no_init/Gemfile
|
90
|
-
- fixtures/rails_3_2_12_no_init/Guardfile
|
91
89
|
- fixtures/rails_3_2_12_no_init/README.rdoc
|
92
90
|
- fixtures/rails_3_2_12_no_init/Rakefile
|
93
91
|
- fixtures/rails_3_2_12_no_init/app/controllers/application_controller.rb
|
@@ -136,6 +134,7 @@ files:
|
|
136
134
|
- lib/secure_headers/headers/x_content_type_options.rb
|
137
135
|
- lib/secure_headers/headers/x_frame_options.rb
|
138
136
|
- lib/secure_headers/headers/x_xss_protection.rb
|
137
|
+
- lib/secure_headers/padrino.rb
|
139
138
|
- lib/secure_headers/railtie.rb
|
140
139
|
- lib/secure_headers/version.rb
|
141
140
|
- secure_headers.gemspec
|
@@ -168,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
167
|
version: '0'
|
169
168
|
requirements: []
|
170
169
|
rubyforge_project:
|
171
|
-
rubygems_version: 2.
|
170
|
+
rubygems_version: 2.1.1
|
172
171
|
signing_key:
|
173
172
|
specification_version: 4
|
174
173
|
summary: Add easily configured browser headers to responses including content security
|
@@ -1,14 +0,0 @@
|
|
1
|
-
guard 'spork', :rspec_port => 1234, :aggressive_kill => false do
|
2
|
-
watch('spec/spec_helper.rb') { :rspec }
|
3
|
-
end
|
4
|
-
|
5
|
-
guard 'rspec', :cli => "--color --drb --drb-port 1234", :keep_failed => true, :all_after_pass => true, :focus_on_failed => true do
|
6
|
-
watch(%r{^spec/.+_spec\.rb$})
|
7
|
-
watch('../../../lib')
|
8
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
9
|
-
watch('spec/spec_helper.rb') { "spec" }
|
10
|
-
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
11
|
-
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
12
|
-
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
13
|
-
end
|
14
|
-
|
@@ -1,14 +0,0 @@
|
|
1
|
-
guard 'spork', :rspec_port => 1235, :aggressive_kill => false do
|
2
|
-
watch('spec/spec_helper.rb') { :rspec }
|
3
|
-
end
|
4
|
-
|
5
|
-
guard 'rspec', :cli => "--color --drb --drb-port 1235", :keep_failed => true, :all_after_pass => true, :focus_on_failed => true do
|
6
|
-
watch(%r{^spec/.+_spec\.rb$})
|
7
|
-
watch('../../../lib')
|
8
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
9
|
-
watch('spec/spec_helper.rb') { "spec" }
|
10
|
-
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
11
|
-
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
12
|
-
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
13
|
-
end
|
14
|
-
|