secure_headers 3.1.2 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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