Skip to content

Commit ce3c737

Browse files
committed
We would like to give users the ability to flag all cookies as secure.
https://www.owasp.org/index.php/SecureFlag
1 parent 79c67f5 commit ce3c737

File tree

5 files changed

+50
-6
lines changed

5 files changed

+50
-6
lines changed

lib/secure_headers/configuration.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def add_noop_configuration
9090

9191
attr_accessor :hsts, :x_frame_options, :x_content_type_options,
9292
:x_xss_protection, :csp, :x_download_options, :x_permitted_cross_domain_policies,
93-
:hpkp
93+
:hpkp, :secure_cookies
9494
attr_reader :cached_headers
9595

9696
def initialize(&block)

lib/secure_headers/middleware.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module SecureHeaders
22
class Middleware
3+
SECURE_COOKIE_REGEXP = /;\s*secure\s*(;|$)/i.freeze
4+
35
def initialize(app)
46
@app = app
57
end
@@ -8,8 +10,32 @@ def initialize(app)
810
def call(env)
911
req = Rack::Request.new(env)
1012
status, headers, response = @app.call(env)
13+
14+
flag_cookies_as_secure!(headers) if config(req).secure_cookies
1115
headers.merge!(SecureHeaders.header_hash_for(req))
1216
[status, headers, response]
1317
end
18+
19+
private
20+
21+
# inspired by https://github.com/tobmatth/rack-ssl-enforcer/blob/6c014/lib/rack/ssl-enforcer.rb#L183-L194
22+
def flag_cookies_as_secure!(headers)
23+
if cookies = headers['Set-Cookie']
24+
# Support Rails 2.3 / Rack 1.1 arrays as headers
25+
cookies = cookies.split("\n") unless cookies.is_a?(Array)
26+
27+
headers['Set-Cookie'] = cookies.map do |cookie|
28+
if cookie !~ SECURE_COOKIE_REGEXP
29+
"#{cookie}; secure"
30+
else
31+
cookie
32+
end
33+
end.join("\n")
34+
end
35+
end
36+
37+
def config(req)
38+
req.env[SECURE_HEADERS_CONFIG] || Configuration.get(Configuration::DEFAULT_CONFIG)
39+
end
1440
end
1541
end

lib/secure_headers/railtie.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Railtie < Rails::Railtie
1010
'Public-Key-Pins', 'Public-Key-Pins-Report-Only']
1111

1212
initializer "secure_headers.middleware" do
13-
Rails.application.config.middleware.use SecureHeaders::Middleware
13+
Rails.application.config.middleware.insert_before 0, SecureHeaders::Middleware
1414
end
1515

1616
initializer "secure_headers.action_controller" do

spec/lib/secure_headers/configuration_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module SecureHeaders
3737
config = Configuration.get(:test_override)
3838
noop = Configuration.get(Configuration::NOOP_CONFIGURATION)
3939
[:hsts, :x_frame_options, :x_content_type_options, :x_xss_protection,
40-
:x_download_options, :x_permitted_cross_domain_policies, :hpkp, :csp].each do |key|
40+
:x_download_options, :x_permitted_cross_domain_policies, :hpkp, :csp, :secure_cookies].each do |key|
4141

4242
expect(config.send(key)).to eq(noop.send(key)), "Value not copied: #{key}."
4343
end

spec/lib/secure_headers/middleware_spec.rb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
module SecureHeaders
44
describe Middleware do
55
let(:app) { ->(env) { [200, env, "app"] } }
6+
let(:cookie_app) { -> (env) { [200, env.merge("Set-Cookie" => "foo=bar"), "app"] } }
67

7-
let :middleware do
8-
Middleware.new(app)
9-
end
8+
let(:middleware) { Middleware.new(app) }
9+
let(:cookie_middleware) { Middleware.new(cookie_app) }
1010

1111
before(:each) do
1212
reset_config
@@ -36,5 +36,23 @@ module SecureHeaders
3636
_, env = middleware.call request.env
3737
expect(env[CSP::HEADER_NAME]).to match("example.org")
3838
end
39+
40+
context "cookies should be flagged" do
41+
it "flags cookies as secure" do
42+
Configuration.default { |config| config.secure_cookies = true }
43+
request = Rack::MockRequest.new(cookie_middleware)
44+
response = request.get '/'
45+
expect(response.headers['Set-Cookie']).to match(Middleware::SECURE_COOKIE_REGEXP)
46+
end
47+
end
48+
49+
context "cookies should not be flagged" do
50+
it "does not flags cookies as secure" do
51+
Configuration.default { |config| config.secure_cookies = false }
52+
request = Rack::MockRequest.new(cookie_middleware)
53+
response = request.get '/'
54+
expect(response.headers['Set-Cookie']).not_to match(Middleware::SECURE_COOKIE_REGEXP)
55+
end
56+
end
3957
end
4058
end

0 commit comments

Comments
 (0)