secure_headers 3.1.2 → 3.2.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.

@@ -1,5 +1,10 @@
1
1
  module SecureHeaders
2
2
  module ViewHelpers
3
+ include SecureHeaders::HashHelper
4
+ SECURE_HEADERS_RAKE_TASK = "rake secure_headers:generate_hashes"
5
+
6
+ class UnexpectedHashedScriptException < StandardError; end
7
+
3
8
  # Public: create a style tag using the content security policy nonce.
4
9
  # Instructs secure_headers to append a nonce to style/script-src directives.
5
10
  #
@@ -29,8 +34,67 @@ module SecureHeaders
29
34
  end
30
35
  end
31
36
 
37
+ ##
38
+ # Checks to see if the hashed code is expected and adds the hash source
39
+ # value to the current CSP.
40
+ #
41
+ # By default, in development/test/etc. an exception will be raised.
42
+ def hashed_javascript_tag(raise_error_on_unrecognized_hash = nil, &block)
43
+ hashed_tag(
44
+ :script,
45
+ :script_src,
46
+ Configuration.instance_variable_get(:@script_hashes),
47
+ raise_error_on_unrecognized_hash,
48
+ block
49
+ )
50
+ end
51
+
52
+ def hashed_style_tag(raise_error_on_unrecognized_hash = nil, &block)
53
+ hashed_tag(
54
+ :style,
55
+ :style_src,
56
+ Configuration.instance_variable_get(:@style_hashes),
57
+ raise_error_on_unrecognized_hash,
58
+ block
59
+ )
60
+ end
61
+
32
62
  private
33
63
 
64
+ def hashed_tag(type, directive, hashes, raise_error_on_unrecognized_hash, block)
65
+ if raise_error_on_unrecognized_hash.nil?
66
+ raise_error_on_unrecognized_hash = ENV["RAILS_ENV"] != "production"
67
+ end
68
+
69
+ content = capture(&block)
70
+ file_path = File.join('app', 'views', self.instance_variable_get(:@virtual_path) + '.html.erb')
71
+
72
+ if raise_error_on_unrecognized_hash
73
+ hash_value = hash_source(content)
74
+ message = unexpected_hash_error_message(file_path, content, hash_value)
75
+
76
+ if hashes.nil? || hashes[file_path].nil? || !hashes[file_path].include?(hash_value)
77
+ raise UnexpectedHashedScriptException.new(message)
78
+ end
79
+ end
80
+
81
+ SecureHeaders.append_content_security_policy_directives(request, directive => hashes[file_path])
82
+
83
+ content_tag type, content
84
+ end
85
+
86
+ def unexpected_hash_error_message(file_path, content, hash_value)
87
+ <<-EOF
88
+ \n\n*** WARNING: Unrecognized hash in #{file_path}!!! Value: #{hash_value} ***
89
+ #{content}
90
+ *** Run #{SECURE_HEADERS_RAKE_TASK} or add the following to config/script_hashes.yml:***
91
+ #{file_path}:
92
+ - #{hash_value}\n\n
93
+ NOTE: dynamic javascript is not supported using script hash integration
94
+ on purpose. It defeats the point of using it in the first place.
95
+ EOF
96
+ end
97
+
34
98
  def nonced_tag(type, content_or_options, block)
35
99
  options = {}
36
100
  content = if block
@@ -1,4 +1,6 @@
1
1
  require "secure_headers/configuration"
2
+ require "secure_headers/hash_helper"
3
+ require "secure_headers/headers/cookie"
2
4
  require "secure_headers/headers/public_key_pins"
3
5
  require "secure_headers/headers/content_security_policy"
4
6
  require "secure_headers/headers/x_frame_options"
@@ -0,0 +1,81 @@
1
+ INLINE_SCRIPT_REGEX = /(<script(\s*(?!src)([\w\-])+=([\"\'])[^\"\']+\4)*\s*>)(.*?)<\/script>/mx
2
+ INLINE_STYLE_REGEX = /(<style[^>]*>)(.*?)<\/style>/mx
3
+ INLINE_HASH_SCRIPT_HELPER_REGEX = /<%=\s?hashed_javascript_tag(.*?)\s+do\s?%>(.*?)<%\s*end\s*%>/mx
4
+ INLINE_HASH_STYLE_HELPER_REGEX = /<%=\s?hashed_style_tag(.*?)\s+do\s?%>(.*?)<%\s*end\s*%>/mx
5
+
6
+ namespace :secure_headers do
7
+ include SecureHeaders::HashHelper
8
+
9
+ def is_erb?(filename)
10
+ filename =~ /\.erb\Z/
11
+ end
12
+
13
+ def is_mustache?(filename)
14
+ filename =~ /\.mustache\Z/
15
+ end
16
+
17
+ def dynamic_content?(filename, inline_script)
18
+ (is_mustache?(filename) && inline_script =~ /\{\{.*\}\}/) ||
19
+ (is_erb?(filename) && inline_script =~ /<%.*%>/)
20
+ end
21
+
22
+ def find_inline_content(filename, regex, hashes)
23
+ file = File.read(filename)
24
+ file.scan(regex) do # TODO don't use gsub
25
+ inline_script = Regexp.last_match.captures.last
26
+ if dynamic_content?(filename, inline_script)
27
+ puts "Looks like there's some dynamic content inside of a tag :-/"
28
+ puts "That pretty much means the hash value will never match."
29
+ puts "Code: " + inline_script
30
+ puts "=" * 20
31
+ end
32
+
33
+ hashes << hash_source(inline_script)
34
+ end
35
+ end
36
+
37
+ def generate_inline_script_hashes(filename)
38
+ hashes = []
39
+
40
+ [INLINE_SCRIPT_REGEX, INLINE_HASH_SCRIPT_HELPER_REGEX].each do |regex|
41
+ find_inline_content(filename, regex, hashes)
42
+ end
43
+
44
+ hashes
45
+ end
46
+
47
+ def generate_inline_style_hashes(filename)
48
+ hashes = []
49
+
50
+ [INLINE_STYLE_REGEX, INLINE_HASH_STYLE_HELPER_REGEX].each do |regex|
51
+ find_inline_content(filename, regex, hashes)
52
+ end
53
+
54
+ hashes
55
+ end
56
+
57
+ task :generate_hashes do |t, args|
58
+ script_hashes = {
59
+ "scripts" => {},
60
+ "styles" => {}
61
+ }
62
+
63
+ Dir.glob("app/{views,templates}/**/*.{erb,mustache}") do |filename|
64
+ hashes = generate_inline_script_hashes(filename)
65
+ if hashes.any?
66
+ script_hashes["scripts"][filename] = hashes
67
+ end
68
+
69
+ hashes = generate_inline_style_hashes(filename)
70
+ if hashes.any?
71
+ script_hashes["styles"][filename] = hashes
72
+ end
73
+ end
74
+
75
+ File.open(SecureHeaders::Configuration::HASH_CONFIG_FILE, 'w') do |file|
76
+ file.write(script_hashes.to_yaml)
77
+ end
78
+
79
+ puts "Script hashes from " + script_hashes.keys.size.to_s + " files added to #{SecureHeaders::Configuration::HASH_CONFIG_FILE}"
80
+ end
81
+ end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "secure_headers"
4
- gem.version = "3.1.2"
4
+ gem.version = "3.2.0"
5
5
  gem.authors = ["Neil Matatall"]
6
6
  gem.email = ["neil.matatall@gmail.com"]
7
7
  gem.description = 'Security related headers all in one gem.'
@@ -36,7 +36,7 @@ module SecureHeaders
36
36
 
37
37
  config = Configuration.get(:test_override)
38
38
  noop = Configuration.get(Configuration::NOOP_CONFIGURATION)
39
- [:csp, :dynamic_csp, :secure_cookies].each do |key|
39
+ [:csp, :dynamic_csp, :cookies].each do |key|
40
40
  expect(config.send(key)).to eq(noop.send(key)), "Value not copied: #{key}."
41
41
  end
42
42
  end
@@ -82,5 +82,13 @@ module SecureHeaders
82
82
  override_config = Configuration.get(:second_override)
83
83
  expect(override_config.csp).to eq(default_src: %w('self'), script_src: %w(example.org))
84
84
  end
85
+
86
+ it "deprecates the secure_cookies configuration" do
87
+ expect(Kernel).to receive(:warn).with(/\[DEPRECATION\]/)
88
+
89
+ Configuration.default do |config|
90
+ config.secure_cookies = true
91
+ end
92
+ end
85
93
  end
86
94
  end
@@ -0,0 +1,164 @@
1
+ require 'spec_helper'
2
+
3
+ module SecureHeaders
4
+ describe Cookie do
5
+ let(:raw_cookie) { "_session=thisisatest" }
6
+
7
+ it "does not tamper with cookies when unconfigured" do
8
+ cookie = Cookie.new(raw_cookie, {})
9
+ expect(cookie.to_s).to eq(raw_cookie)
10
+ end
11
+
12
+ it "preserves existing attributes" do
13
+ cookie = Cookie.new("_session=thisisatest; secure", secure: true)
14
+ expect(cookie.to_s).to eq("_session=thisisatest; secure")
15
+ end
16
+
17
+ it "prevents duplicate flagging of attributes" do
18
+ cookie = Cookie.new("_session=thisisatest; secure", secure: true)
19
+ expect(cookie.to_s.scan(/secure/i).count).to eq(1)
20
+ end
21
+
22
+ context "Secure cookies" do
23
+ context "when configured with a boolean" do
24
+ it "flags cookies as Secure" do
25
+ cookie = Cookie.new(raw_cookie, secure: true)
26
+ expect(cookie.to_s).to eq("_session=thisisatest; secure")
27
+ end
28
+ end
29
+
30
+ context "when configured with a Hash" do
31
+ it "flags cookies as Secure when whitelisted" do
32
+ cookie = Cookie.new(raw_cookie, secure: { only: ["_session"]})
33
+ expect(cookie.to_s).to eq("_session=thisisatest; secure")
34
+ end
35
+
36
+ it "does not flag cookies as Secure when excluded" do
37
+ cookie = Cookie.new(raw_cookie, secure: { except: ["_session"] })
38
+ expect(cookie.to_s).to eq("_session=thisisatest")
39
+ end
40
+ end
41
+ end
42
+
43
+ context "HttpOnly cookies" do
44
+ context "when configured with a boolean" do
45
+ it "flags cookies as HttpOnly" do
46
+ cookie = Cookie.new(raw_cookie, httponly: true)
47
+ expect(cookie.to_s).to eq("_session=thisisatest; HttpOnly")
48
+ end
49
+ end
50
+
51
+ context "when configured with a Hash" do
52
+ it "flags cookies as HttpOnly when whitelisted" do
53
+ cookie = Cookie.new(raw_cookie, httponly: { only: ["_session"]})
54
+ expect(cookie.to_s).to eq("_session=thisisatest; HttpOnly")
55
+ end
56
+
57
+ it "does not flag cookies as HttpOnly when excluded" do
58
+ cookie = Cookie.new(raw_cookie, httponly: { except: ["_session"] })
59
+ expect(cookie.to_s).to eq("_session=thisisatest")
60
+ end
61
+ end
62
+ end
63
+
64
+ context "SameSite cookies" do
65
+ it "flags SameSite=Lax" do
66
+ cookie = Cookie.new(raw_cookie, samesite: { lax: { only: ["_session"] } })
67
+ expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Lax")
68
+ end
69
+
70
+ it "flags SameSite=Lax when configured with a boolean" do
71
+ cookie = Cookie.new(raw_cookie, samesite: { lax: true})
72
+ expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Lax")
73
+ end
74
+
75
+ it "does not flag cookies as SameSite=Lax when excluded" do
76
+ cookie = Cookie.new(raw_cookie, samesite: { lax: { except: ["_session"] } })
77
+ expect(cookie.to_s).to eq("_session=thisisatest")
78
+ end
79
+
80
+ it "flags SameSite=Strict" do
81
+ cookie = Cookie.new(raw_cookie, samesite: { strict: { only: ["_session"] } })
82
+ expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Strict")
83
+ end
84
+
85
+ it "does not flag cookies as SameSite=Strict when excluded" do
86
+ cookie = Cookie.new(raw_cookie, samesite: { strict: { except: ["_session"] } })
87
+ expect(cookie.to_s).to eq("_session=thisisatest")
88
+ end
89
+
90
+ it "flags SameSite=Strict when configured with a boolean" do
91
+ cookie = Cookie.new(raw_cookie, samesite: { strict: true})
92
+ expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Strict")
93
+ end
94
+
95
+ it "flags properly when both lax and strict are configured" do
96
+ raw_cookie = "_session=thisisatest"
97
+ cookie = Cookie.new(raw_cookie, samesite: { strict: { only: ["_session"] }, lax: { only: ["_additional_session"] } })
98
+ expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Strict")
99
+ end
100
+
101
+ it "ignores configuration if the cookie is already flagged" do
102
+ raw_cookie = "_session=thisisatest; SameSite=Strict"
103
+ cookie = Cookie.new(raw_cookie, samesite: { lax: true })
104
+ expect(cookie.to_s).to eq(raw_cookie)
105
+ end
106
+ end
107
+ end
108
+
109
+ context "with an invalid configuration" do
110
+ it "raises an exception when not configured with a Hash" do
111
+ expect do
112
+ Cookie.validate_config!("configuration")
113
+ end.to raise_error(CookiesConfigError)
114
+ end
115
+
116
+ it "raises an exception when configured without a boolean/Hash" do
117
+ expect do
118
+ Cookie.validate_config!(secure: "true")
119
+ end.to raise_error(CookiesConfigError)
120
+ end
121
+
122
+ it "raises an exception when both only and except filters are provided" do
123
+ expect do
124
+ Cookie.validate_config!(secure: { only: [], except: [] })
125
+ end.to raise_error(CookiesConfigError)
126
+ end
127
+
128
+ it "raises an exception when SameSite is not configured with a Hash" do
129
+ expect do
130
+ Cookie.validate_config!(samesite: true)
131
+ end.to raise_error(CookiesConfigError)
132
+ end
133
+
134
+ it "raises an exception when SameSite lax and strict enforcement modes are configured with booleans" do
135
+ expect do
136
+ Cookie.validate_config!(samesite: { lax: true, strict: true})
137
+ end.to raise_error(CookiesConfigError)
138
+ end
139
+
140
+ it "raises an exception when SameSite lax and strict enforcement modes are configured with booleans" do
141
+ expect do
142
+ Cookie.validate_config!(samesite: { lax: true, strict: { only: ["_anything"] } })
143
+ end.to raise_error(CookiesConfigError)
144
+ end
145
+
146
+ it "raises an exception when both only and except filters are provided to SameSite configurations" do
147
+ expect do
148
+ Cookie.validate_config!(samesite: { lax: { only: ["_anything"], except: ["_anythingelse"] } })
149
+ end.to raise_error(CookiesConfigError)
150
+ end
151
+
152
+ it "raises an exception when both lax and strict only filters are provided to SameSite configurations" do
153
+ expect do
154
+ Cookie.validate_config!(samesite: { lax: { only: ["_anything"] }, strict: { only: ["_anything"] } })
155
+ end.to raise_error(CookiesConfigError)
156
+ end
157
+
158
+ it "raises an exception when both lax and strict only filters are provided to SameSite configurations" do
159
+ expect do
160
+ Cookie.validate_config!(samesite: { lax: { except: ["_anything"] }, strict: { except: ["_anything"] } })
161
+ end.to raise_error(CookiesConfigError)
162
+ end
163
+ end
164
+ end
@@ -10,9 +10,7 @@ module SecureHeaders
10
10
 
11
11
  before(:each) do
12
12
  reset_config
13
- Configuration.default do |config|
14
- # use all default provided by the library
15
- end
13
+ Configuration.default
16
14
  end
17
15
 
18
16
  it "sets the headers" do
@@ -38,21 +36,56 @@ module SecureHeaders
38
36
  expect(env[CSP::HEADER_NAME]).to match("example.org")
39
37
  end
40
38
 
41
- context "cookies should be flagged" do
42
- it "flags cookies as secure" do
43
- Configuration.default { |config| config.secure_cookies = true }
44
- request = Rack::MockRequest.new(cookie_middleware)
45
- response = request.get '/'
46
- expect(response.headers['Set-Cookie']).to match(Middleware::SECURE_COOKIE_REGEXP)
39
+ context "secure_cookies" do
40
+ context "cookies should be flagged" do
41
+ it "flags cookies as secure" do
42
+ capture_warning do
43
+ Configuration.default { |config| config.secure_cookies = true }
44
+ end
45
+ request = Rack::Request.new("HTTPS" => "on")
46
+ _, env = cookie_middleware.call request.env
47
+ expect(env['Set-Cookie']).to eq("foo=bar; secure")
48
+ end
49
+ end
50
+
51
+ context "cookies should not be flagged" do
52
+ it "does not flags cookies as secure" do
53
+ capture_warning do
54
+ Configuration.default { |config| config.secure_cookies = false }
55
+ end
56
+ request = Rack::Request.new("HTTPS" => "on")
57
+ _, env = cookie_middleware.call request.env
58
+ expect(env['Set-Cookie']).to eq("foo=bar")
59
+ end
47
60
  end
48
61
  end
49
62
 
50
- context "cookies should not be flagged" do
51
- it "does not flags cookies as secure" do
52
- Configuration.default { |config| config.secure_cookies = false }
53
- request = Rack::MockRequest.new(cookie_middleware)
54
- response = request.get '/'
55
- expect(response.headers['Set-Cookie']).not_to match(Middleware::SECURE_COOKIE_REGEXP)
63
+ context "cookies" do
64
+ it "flags cookies from configuration" do
65
+ Configuration.default { |config| config.cookies = { secure: true, httponly: true } }
66
+ request = Rack::Request.new("HTTPS" => "on")
67
+ _, env = cookie_middleware.call request.env
68
+
69
+ expect(env['Set-Cookie']).to eq("foo=bar; secure; HttpOnly")
70
+ end
71
+
72
+ it "flags cookies with a combination of SameSite configurations" do
73
+ cookie_middleware = Middleware.new(lambda { |env| [200, env.merge("Set-Cookie" => ["_session=foobar", "_guest=true"]), "app"] })
74
+
75
+ Configuration.default { |config| config.cookies = { samesite: { lax: { except: ["_session"] }, strict: { only: ["_session"] } } } }
76
+ request = Rack::Request.new("HTTPS" => "on")
77
+ _, env = cookie_middleware.call request.env
78
+
79
+ expect(env['Set-Cookie']).to match("_session=foobar; SameSite=Strict")
80
+ expect(env['Set-Cookie']).to match("_guest=true; SameSite=Lax")
81
+ end
82
+
83
+ it "disables secure cookies for non-https requests" do
84
+ Configuration.default { |config| config.cookies = { secure: true } }
85
+
86
+ request = Rack::Request.new("HTTPS" => "off")
87
+ _, env = cookie_middleware.call request.env
88
+ expect(env['Set-Cookie']).to eq("foo=bar")
56
89
  end
57
90
  end
58
91
  end
@@ -0,0 +1,125 @@
1
+ require "spec_helper"
2
+ require "erb"
3
+
4
+ class Message < ERB
5
+ include SecureHeaders::ViewHelpers
6
+
7
+ def self.template
8
+ <<-TEMPLATE
9
+ <% hashed_javascript_tag(raise_error_on_unrecognized_hash = true) do %>
10
+ console.log(1)
11
+ <% end %>
12
+
13
+ <% hashed_style_tag do %>
14
+ body {
15
+ background-color: black;
16
+ }
17
+ <% end %>
18
+
19
+ <% nonced_javascript_tag do %>
20
+ body {
21
+ console.log(1)
22
+ }
23
+ <% end %>
24
+
25
+ <% nonced_style_tag do %>
26
+ body {
27
+ background-color: black;
28
+ }
29
+ <% end %>
30
+ <%= @name %>
31
+
32
+ TEMPLATE
33
+ end
34
+
35
+ def initialize(request, options = {})
36
+ @virtual_path = "/asdfs/index"
37
+ @_request = request
38
+ @template = self.class.template
39
+ super(@template)
40
+ end
41
+
42
+ def capture(*args)
43
+ yield(*args)
44
+ end
45
+
46
+ def content_tag(type, content = nil, options = nil, &block)
47
+ content = if block_given?
48
+ capture(block)
49
+ end
50
+
51
+ if options.is_a?(Hash)
52
+ options = options.map {|k,v| " #{k}=#{v}"}
53
+ end
54
+ "<#{type}#{options}>#{content}</#{type}>"
55
+ end
56
+
57
+ def result
58
+ super(binding)
59
+ end
60
+
61
+ def request
62
+ @_request
63
+ end
64
+ end
65
+
66
+ module SecureHeaders
67
+ describe ViewHelpers do
68
+ let(:app) { lambda { |env| [200, env, "app"] } }
69
+ let(:middleware) { Middleware.new(app) }
70
+ let(:request) { Rack::Request.new("HTTP_USER_AGENT" => USER_AGENTS[:chrome]) }
71
+ let(:filename) { "app/views/asdfs/index.html.erb" }
72
+
73
+ before(:all) do
74
+ Configuration.default do |config|
75
+ config.csp[:script_src] = %w('self')
76
+ config.csp[:style_src] = %w('self')
77
+ end
78
+ end
79
+
80
+ after(:each) do
81
+ Configuration.instance_variable_set(:@script_hashes, nil)
82
+ Configuration.instance_variable_set(:@style_hashes, nil)
83
+ end
84
+
85
+ it "raises an error when using hashed content without precomputed hashes" do
86
+ expect {
87
+ Message.new(request).result
88
+ }.to raise_error(ViewHelpers::UnexpectedHashedScriptException)
89
+ end
90
+
91
+ it "raises an error when using hashed content with precomputed hashes, but none for the given file" do
92
+ Configuration.instance_variable_set(:@script_hashes, filename.reverse => ["'sha256-123'"])
93
+ expect {
94
+ Message.new(request).result
95
+ }.to raise_error(ViewHelpers::UnexpectedHashedScriptException)
96
+ end
97
+
98
+ it "raises an error when using previously unknown hashed content with precomputed hashes for a given file" do
99
+ Configuration.instance_variable_set(:@script_hashes, filename => ["'sha256-123'"])
100
+ expect {
101
+ Message.new(request).result
102
+ }.to raise_error(ViewHelpers::UnexpectedHashedScriptException)
103
+ end
104
+
105
+ it "adds known hash values to the corresponding headers when the helper is used" do
106
+ begin
107
+ allow(SecureRandom).to receive(:base64).and_return("abc123")
108
+
109
+ expected_hash = "sha256-3/URElR9+3lvLIouavYD/vhoICSNKilh15CzI/nKqg8="
110
+ Configuration.instance_variable_set(:@script_hashes, filename => ["'#{expected_hash}'"])
111
+ expected_style_hash = "sha256-7oYK96jHg36D6BM042er4OfBnyUDTG3pH1L8Zso3aGc="
112
+ Configuration.instance_variable_set(:@style_hashes, filename => ["'#{expected_style_hash}'"])
113
+
114
+ # render erb that calls out to helpers.
115
+ Message.new(request).result
116
+ _, env = middleware.call request.env
117
+
118
+ expect(env[CSP::HEADER_NAME]).to match(/script-src[^;]*'#{Regexp.escape(expected_hash)}'/)
119
+ expect(env[CSP::HEADER_NAME]).to match(/script-src[^;]*'nonce-abc123'/)
120
+ expect(env[CSP::HEADER_NAME]).to match(/style-src[^;]*'nonce-abc123'/)
121
+ expect(env[CSP::HEADER_NAME]).to match(/style-src[^;]*'#{Regexp.escape(expected_style_hash)}'/)
122
+ end
123
+ end
124
+ end
125
+ end
data/spec/spec_helper.rb CHANGED
@@ -45,3 +45,15 @@ end
45
45
  def reset_config
46
46
  SecureHeaders::Configuration.clear_configurations
47
47
  end
48
+
49
+ def capture_warning
50
+ begin
51
+ old_stderr = $stderr
52
+ $stderr = StringIO.new
53
+ yield
54
+ result = $stderr.string
55
+ ensure
56
+ $stderr = old_stderr
57
+ end
58
+ result
59
+ end
data/upgrading-to-3-0.md CHANGED
@@ -8,6 +8,7 @@ Changes
8
8
  | Global configuration | `SecureHeaders::Configuration.configure` block | `SecureHeaders::Configuration.default` block |
9
9
  | All headers besides HPKP and CSP | Accept hashes as config values | Must be strings (validated during configuration) |
10
10
  | CSP directive values | Accepted space delimited strings OR arrays of strings | Must be arrays of strings |
11
+ | CSP Nonce values in views | `@content_security_policy_nonce` | `content_security_policy_script_nonce` or `content_security_policy_style_nonce`
11
12
  | `self`/`none` source expressions | could be `self` / `none` / `'self'` / `'none'` | Must be `'self'` or `'none'` |
12
13
  | `inline` / `eval` source expressions | could be `inline`, `eval`, `'unsafe-inline'`, or `'unsafe-eval'` | Must be `'unsafe-eval'` or `'unsafe-inline'` |
13
14
  | Per-action configuration | override [`def secure_header_options_for(header, options)`](https://github.com/twitter/secureheaders/commit/bb9ebc6c12a677aad29af8e0f08ffd1def56efec#diff-04c6e90faac2675aa89e2176d2eec7d8R111) | Use [named overrides](https://github.com/twitter/secureheaders#named-overrides) or [per-action helpers](https://github.com/twitter/secureheaders#per-action-configuration) |
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: 3.1.2
4
+ version: 3.2.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: 2016-03-30 00:00:00.000000000 Z
11
+ date: 2016-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -58,7 +58,9 @@ files:
58
58
  - Rakefile
59
59
  - lib/secure_headers.rb
60
60
  - lib/secure_headers/configuration.rb
61
+ - lib/secure_headers/hash_helper.rb
61
62
  - lib/secure_headers/headers/content_security_policy.rb
63
+ - lib/secure_headers/headers/cookie.rb
62
64
  - lib/secure_headers/headers/policy_management.rb
63
65
  - lib/secure_headers/headers/public_key_pins.rb
64
66
  - lib/secure_headers/headers/strict_transport_security.rb
@@ -69,10 +71,13 @@ files:
69
71
  - lib/secure_headers/headers/x_xss_protection.rb
70
72
  - lib/secure_headers/middleware.rb
71
73
  - lib/secure_headers/railtie.rb
74
+ - lib/secure_headers/utils/cookies_config.rb
72
75
  - lib/secure_headers/view_helper.rb
76
+ - lib/tasks/tasks.rake
73
77
  - secure_headers.gemspec
74
78
  - spec/lib/secure_headers/configuration_spec.rb
75
79
  - spec/lib/secure_headers/headers/content_security_policy_spec.rb
80
+ - spec/lib/secure_headers/headers/cookie_spec.rb
76
81
  - spec/lib/secure_headers/headers/policy_management_spec.rb
77
82
  - spec/lib/secure_headers/headers/public_key_pins_spec.rb
78
83
  - spec/lib/secure_headers/headers/strict_transport_security_spec.rb
@@ -82,6 +87,7 @@ files:
82
87
  - spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb
83
88
  - spec/lib/secure_headers/headers/x_xss_protection_spec.rb
84
89
  - spec/lib/secure_headers/middleware_spec.rb
90
+ - spec/lib/secure_headers/view_helpers_spec.rb
85
91
  - spec/lib/secure_headers_spec.rb
86
92
  - spec/spec_helper.rb
87
93
  - upgrading-to-3-0.md
@@ -113,6 +119,7 @@ summary: Add easily configured security headers to responses including content-s
113
119
  test_files:
114
120
  - spec/lib/secure_headers/configuration_spec.rb
115
121
  - spec/lib/secure_headers/headers/content_security_policy_spec.rb
122
+ - spec/lib/secure_headers/headers/cookie_spec.rb
116
123
  - spec/lib/secure_headers/headers/policy_management_spec.rb
117
124
  - spec/lib/secure_headers/headers/public_key_pins_spec.rb
118
125
  - spec/lib/secure_headers/headers/strict_transport_security_spec.rb
@@ -122,5 +129,6 @@ test_files:
122
129
  - spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb
123
130
  - spec/lib/secure_headers/headers/x_xss_protection_spec.rb
124
131
  - spec/lib/secure_headers/middleware_spec.rb
132
+ - spec/lib/secure_headers/view_helpers_spec.rb
125
133
  - spec/lib/secure_headers_spec.rb
126
134
  - spec/spec_helper.rb