secure_headers 2.2.4 → 3.0.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.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG.md +205 -0
  6. data/Gemfile +9 -10
  7. data/Guardfile +12 -0
  8. data/README.md +172 -274
  9. data/Rakefile +2 -36
  10. data/lib/secure_headers/configuration.rb +189 -0
  11. data/lib/secure_headers/headers/content_security_policy.rb +362 -211
  12. data/lib/secure_headers/headers/public_key_pins.rb +43 -57
  13. data/lib/secure_headers/headers/strict_transport_security.rb +21 -47
  14. data/lib/secure_headers/headers/x_content_type_options.rb +19 -32
  15. data/lib/secure_headers/headers/x_download_options.rb +18 -31
  16. data/lib/secure_headers/headers/x_frame_options.rb +24 -32
  17. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +19 -32
  18. data/lib/secure_headers/headers/x_xss_protection.rb +17 -46
  19. data/lib/secure_headers/middleware.rb +15 -0
  20. data/lib/secure_headers/padrino.rb +1 -2
  21. data/lib/secure_headers/railtie.rb +9 -6
  22. data/lib/secure_headers/view_helper.rb +27 -44
  23. data/lib/secure_headers.rb +245 -150
  24. data/secure_headers.gemspec +7 -11
  25. data/spec/lib/secure_headers/configuration_spec.rb +80 -0
  26. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +175 -262
  27. data/spec/lib/secure_headers/headers/public_key_pins_spec.rb +17 -17
  28. data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +11 -43
  29. data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +13 -18
  30. data/spec/lib/secure_headers/headers/x_download_options_spec.rb +13 -17
  31. data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +15 -17
  32. data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +22 -39
  33. data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +22 -30
  34. data/spec/lib/secure_headers/middleware_spec.rb +40 -0
  35. data/spec/lib/secure_headers_spec.rb +204 -278
  36. data/spec/spec_helper.rb +32 -28
  37. data/upgrading-to-3-0.md +37 -0
  38. metadata +14 -94
  39. data/fixtures/rails_3_2_12/.rspec +0 -1
  40. data/fixtures/rails_3_2_12/Gemfile +0 -6
  41. data/fixtures/rails_3_2_12/README.rdoc +0 -261
  42. data/fixtures/rails_3_2_12/Rakefile +0 -7
  43. data/fixtures/rails_3_2_12/app/controllers/application_controller.rb +0 -4
  44. data/fixtures/rails_3_2_12/app/controllers/other_things_controller.rb +0 -5
  45. data/fixtures/rails_3_2_12/app/controllers/things_controller.rb +0 -5
  46. data/fixtures/rails_3_2_12/app/models/.gitkeep +0 -0
  47. data/fixtures/rails_3_2_12/app/views/layouts/application.html.erb +0 -11
  48. data/fixtures/rails_3_2_12/app/views/other_things/index.html.erb +0 -2
  49. data/fixtures/rails_3_2_12/app/views/things/index.html.erb +0 -1
  50. data/fixtures/rails_3_2_12/config/application.rb +0 -14
  51. data/fixtures/rails_3_2_12/config/boot.rb +0 -6
  52. data/fixtures/rails_3_2_12/config/environment.rb +0 -5
  53. data/fixtures/rails_3_2_12/config/environments/test.rb +0 -37
  54. data/fixtures/rails_3_2_12/config/initializers/secure_headers.rb +0 -17
  55. data/fixtures/rails_3_2_12/config/routes.rb +0 -4
  56. data/fixtures/rails_3_2_12/config/script_hashes.yml +0 -5
  57. data/fixtures/rails_3_2_12/config.ru +0 -7
  58. data/fixtures/rails_3_2_12/lib/assets/.gitkeep +0 -0
  59. data/fixtures/rails_3_2_12/lib/tasks/.gitkeep +0 -0
  60. data/fixtures/rails_3_2_12/log/.gitkeep +0 -0
  61. data/fixtures/rails_3_2_12/spec/controllers/other_things_controller_spec.rb +0 -83
  62. data/fixtures/rails_3_2_12/spec/controllers/things_controller_spec.rb +0 -54
  63. data/fixtures/rails_3_2_12/spec/spec_helper.rb +0 -15
  64. data/fixtures/rails_3_2_12/vendor/assets/javascripts/.gitkeep +0 -0
  65. data/fixtures/rails_3_2_12/vendor/assets/stylesheets/.gitkeep +0 -0
  66. data/fixtures/rails_3_2_12/vendor/plugins/.gitkeep +0 -0
  67. data/fixtures/rails_3_2_12_no_init/.rspec +0 -1
  68. data/fixtures/rails_3_2_12_no_init/Gemfile +0 -5
  69. data/fixtures/rails_3_2_12_no_init/README.rdoc +0 -261
  70. data/fixtures/rails_3_2_12_no_init/Rakefile +0 -7
  71. data/fixtures/rails_3_2_12_no_init/app/controllers/application_controller.rb +0 -4
  72. data/fixtures/rails_3_2_12_no_init/app/controllers/other_things_controller.rb +0 -20
  73. data/fixtures/rails_3_2_12_no_init/app/controllers/things_controller.rb +0 -5
  74. data/fixtures/rails_3_2_12_no_init/app/models/.gitkeep +0 -0
  75. data/fixtures/rails_3_2_12_no_init/app/views/layouts/application.html.erb +0 -12
  76. data/fixtures/rails_3_2_12_no_init/app/views/other_things/index.html.erb +0 -1
  77. data/fixtures/rails_3_2_12_no_init/app/views/things/index.html.erb +0 -0
  78. data/fixtures/rails_3_2_12_no_init/config/application.rb +0 -17
  79. data/fixtures/rails_3_2_12_no_init/config/boot.rb +0 -6
  80. data/fixtures/rails_3_2_12_no_init/config/environment.rb +0 -5
  81. data/fixtures/rails_3_2_12_no_init/config/environments/test.rb +0 -37
  82. data/fixtures/rails_3_2_12_no_init/config/routes.rb +0 -4
  83. data/fixtures/rails_3_2_12_no_init/config.ru +0 -4
  84. data/fixtures/rails_3_2_12_no_init/lib/assets/.gitkeep +0 -0
  85. data/fixtures/rails_3_2_12_no_init/lib/tasks/.gitkeep +0 -0
  86. data/fixtures/rails_3_2_12_no_init/log/.gitkeep +0 -0
  87. data/fixtures/rails_3_2_12_no_init/spec/controllers/other_things_controller_spec.rb +0 -56
  88. data/fixtures/rails_3_2_12_no_init/spec/controllers/things_controller_spec.rb +0 -54
  89. data/fixtures/rails_3_2_12_no_init/spec/spec_helper.rb +0 -5
  90. data/fixtures/rails_3_2_12_no_init/vendor/assets/javascripts/.gitkeep +0 -0
  91. data/fixtures/rails_3_2_12_no_init/vendor/assets/stylesheets/.gitkeep +0 -0
  92. data/fixtures/rails_3_2_12_no_init/vendor/plugins/.gitkeep +0 -0
  93. data/fixtures/rails_4_1_8/Gemfile +0 -5
  94. data/fixtures/rails_4_1_8/README.rdoc +0 -28
  95. data/fixtures/rails_4_1_8/Rakefile +0 -6
  96. data/fixtures/rails_4_1_8/app/controllers/application_controller.rb +0 -4
  97. data/fixtures/rails_4_1_8/app/controllers/concerns/.keep +0 -0
  98. data/fixtures/rails_4_1_8/app/controllers/other_things_controller.rb +0 -5
  99. data/fixtures/rails_4_1_8/app/controllers/things_controller.rb +0 -5
  100. data/fixtures/rails_4_1_8/app/models/.keep +0 -0
  101. data/fixtures/rails_4_1_8/app/models/concerns/.keep +0 -0
  102. data/fixtures/rails_4_1_8/app/views/layouts/application.html.erb +0 -11
  103. data/fixtures/rails_4_1_8/app/views/other_things/index.html.erb +0 -2
  104. data/fixtures/rails_4_1_8/app/views/things/index.html.erb +0 -1
  105. data/fixtures/rails_4_1_8/config/application.rb +0 -15
  106. data/fixtures/rails_4_1_8/config/boot.rb +0 -4
  107. data/fixtures/rails_4_1_8/config/environment.rb +0 -5
  108. data/fixtures/rails_4_1_8/config/environments/test.rb +0 -10
  109. data/fixtures/rails_4_1_8/config/initializers/secure_headers.rb +0 -17
  110. data/fixtures/rails_4_1_8/config/routes.rb +0 -4
  111. data/fixtures/rails_4_1_8/config/script_hashes.yml +0 -5
  112. data/fixtures/rails_4_1_8/config/secrets.yml +0 -22
  113. data/fixtures/rails_4_1_8/config.ru +0 -4
  114. data/fixtures/rails_4_1_8/lib/assets/.keep +0 -0
  115. data/fixtures/rails_4_1_8/lib/tasks/.keep +0 -0
  116. data/fixtures/rails_4_1_8/log/.keep +0 -0
  117. data/fixtures/rails_4_1_8/spec/controllers/other_things_controller_spec.rb +0 -83
  118. data/fixtures/rails_4_1_8/spec/controllers/things_controller_spec.rb +0 -59
  119. data/fixtures/rails_4_1_8/spec/spec_helper.rb +0 -15
  120. data/fixtures/rails_4_1_8/vendor/assets/javascripts/.keep +0 -0
  121. data/fixtures/rails_4_1_8/vendor/assets/stylesheets/.keep +0 -0
  122. data/lib/secure_headers/hash_helper.rb +0 -7
  123. data/lib/secure_headers/header.rb +0 -5
  124. data/lib/secure_headers/headers/content_security_policy/script_hash_middleware.rb +0 -22
  125. data/lib/secure_headers/version.rb +0 -3
  126. data/lib/tasks/tasks.rake +0 -48
  127. data/spec/lib/secure_headers/headers/content_security_policy/script_hash_middleware_spec.rb +0 -47
@@ -0,0 +1,189 @@
1
+ module SecureHeaders
2
+ class Configuration
3
+ DEFAULT_CONFIG = :default
4
+ NOOP_CONFIGURATION = "secure_headers_noop_config"
5
+ class NotYetConfiguredError < StandardError; end
6
+ class << self
7
+ # Public: Set the global default configuration.
8
+ #
9
+ # Optionally supply a block to override the defaults set by this library.
10
+ #
11
+ # Returns the newly created config.
12
+ def default(&block)
13
+ config = new(&block)
14
+ add_noop_configuration
15
+ add_configuration(DEFAULT_CONFIG, config)
16
+ end
17
+ alias_method :configure, :default
18
+
19
+ # Public: create a named configuration that overrides the default config.
20
+ #
21
+ # name - use an idenfier for the override config.
22
+ # base - override another existing config, or override the default config
23
+ # if no value is supplied.
24
+ #
25
+ # Returns: the newly created config
26
+ def override(name, base = DEFAULT_CONFIG)
27
+ unless get(base)
28
+ raise NotYetConfiguredError, "#{base} policy not yet supplied"
29
+ end
30
+ override = @configurations[base].dup
31
+ yield(override)
32
+ add_configuration(name, override)
33
+ end
34
+
35
+ # Public: retrieve a global configuration object
36
+ #
37
+ # Returns the configuration with a given name or raises a
38
+ # NotYetConfiguredError if `default` has not been called.
39
+ def get(name = DEFAULT_CONFIG)
40
+ if @configurations.nil?
41
+ raise NotYetConfiguredError, "Default policy not yet supplied"
42
+ end
43
+ @configurations[name]
44
+ end
45
+
46
+ # Public: perform a basic deep dup. The shallow copy provided by dup/clone
47
+ # can lead to modifying parent objects.
48
+ def deep_copy(config)
49
+ config.each_with_object({}) do |(key, value), hash|
50
+ hash[key] = if value.is_a?(Array)
51
+ value.dup
52
+ else
53
+ value
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Private: add a valid configuration to the global set of named configs.
61
+ #
62
+ # config - the config to store
63
+ # name - the lookup value for this config
64
+ #
65
+ # Raises errors if the config is invalid or if a config named `name`
66
+ # already exists.
67
+ #
68
+ # Returns the config, if valid
69
+ def add_configuration(name, config)
70
+ config.validate_config!
71
+ @configurations ||= {}
72
+ config.send(:cache_headers!)
73
+ config.freeze
74
+ @configurations[name] = config
75
+ end
76
+
77
+ # Private: Automatically add an "opt-out of everything" override.
78
+ #
79
+ # Returns the noop config
80
+ def add_noop_configuration
81
+ noop_config = new do |config|
82
+ ALL_HEADER_CLASSES.each do |klass|
83
+ config.send("#{klass::CONFIG_KEY}=", OPT_OUT)
84
+ end
85
+ end
86
+
87
+ add_configuration(NOOP_CONFIGURATION, noop_config)
88
+ end
89
+ end
90
+
91
+ attr_accessor :hsts, :x_frame_options, :x_content_type_options,
92
+ :x_xss_protection, :csp, :x_download_options, :x_permitted_cross_domain_policies,
93
+ :hpkp
94
+ attr_reader :cached_headers
95
+
96
+ def initialize(&block)
97
+ self.hpkp = OPT_OUT
98
+ self.csp = self.class.deep_copy(CSP::DEFAULT_CONFIG)
99
+ instance_eval &block if block_given?
100
+ end
101
+
102
+ # Public: copy everything but the cached headers
103
+ #
104
+ # Returns a deep-dup'd copy of this configuration.
105
+ def dup
106
+ copy = self.class.new
107
+ copy.hsts = hsts
108
+ copy.x_frame_options = x_frame_options
109
+ copy.x_content_type_options = x_content_type_options
110
+ copy.x_xss_protection = x_xss_protection
111
+ copy.x_download_options = x_download_options
112
+ copy.x_permitted_cross_domain_policies = x_permitted_cross_domain_policies
113
+ copy.csp = if csp.is_a?(Hash)
114
+ self.class.deep_copy(csp)
115
+ else
116
+ csp
117
+ end
118
+
119
+ copy.hpkp = if hpkp.is_a?(Hash)
120
+ self.class.deep_copy(hpkp)
121
+ else
122
+ hpkp
123
+ end
124
+ copy
125
+ end
126
+
127
+ # Public: Retrieve a config based on the CONFIG_KEY for a class
128
+ #
129
+ # Returns the value if available, and returns a dup of any hash values.
130
+ def fetch(key)
131
+ config = send(key)
132
+ config = self.class.deep_copy(config) if config.is_a?(Hash)
133
+ config
134
+ end
135
+
136
+ # Public: validates all configurations values.
137
+ #
138
+ # Raises various configuration errors if any invalid config is detected.
139
+ #
140
+ # Returns nothing
141
+ def validate_config!
142
+ StrictTransportSecurity.validate_config!(hsts)
143
+ ContentSecurityPolicy.validate_config!(csp)
144
+ XFrameOptions.validate_config!(x_frame_options)
145
+ XContentTypeOptions.validate_config!(x_content_type_options)
146
+ XXssProtection.validate_config!(x_xss_protection)
147
+ XDownloadOptions.validate_config!(x_download_options)
148
+ XPermittedCrossDomainPolicies.validate_config!(x_permitted_cross_domain_policies)
149
+ PublicKeyPins.validate_config!(hpkp)
150
+ end
151
+
152
+ # Public: Precompute the header names and values for this configuraiton.
153
+ # Ensures that headers generated at configure time, not on demand.
154
+ #
155
+ # Returns the cached headers
156
+ def cache_headers!
157
+ # generate defaults for the "easy" headers
158
+ headers = (ALL_HEADERS_BESIDES_CSP).each_with_object({}) do |klass, hash|
159
+ config = fetch(klass::CONFIG_KEY)
160
+ unless config == OPT_OUT
161
+ hash[klass::CONFIG_KEY] = klass.make_header(config).freeze
162
+ end
163
+ end
164
+
165
+ generate_csp_headers(headers)
166
+
167
+ headers.freeze
168
+ @cached_headers = headers
169
+ end
170
+
171
+ # Private: adds CSP headers for each variation of CSP support.
172
+ #
173
+ # headers - generated headers are added to this hash namespaced by The
174
+ # different variations
175
+ #
176
+ # Returns nothing
177
+ def generate_csp_headers(headers)
178
+ unless csp == OPT_OUT
179
+ headers[CSP::CONFIG_KEY] = {}
180
+
181
+ CSP::VARIATIONS.each do |name, _|
182
+ csp_config = fetch(CSP::CONFIG_KEY)
183
+ csp = CSP.make_header(csp_config, UserAgent.parse(name))
184
+ headers[CSP::CONFIG_KEY][name] = csp.freeze
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end