ezcsp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ezcsp.rb +400 -0
  3. metadata +44 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a64098cd248945d8710812f3321c933b2369eeea
4
+ data.tar.gz: 057154fe542773f16ef047ecce002dc0882a08b0
5
+ SHA512:
6
+ metadata.gz: b8d006493d6446008a8beb09c8cd5c425365fb1583d07f8ecd152695524dbfc2859a7d6398ebd1f55107c056729a15f23ccf5701bc5faf30d377c01cedc3c739
7
+ data.tar.gz: e453772110f23a06a30f94c91465433ac36e8e8b2a1f79c1fd0dc877f830e6f439b8b9c426be7bcef38a66a03a2526f98be08b8c1f713e022d7bc5230c5e2624
data/lib/ezcsp.rb ADDED
@@ -0,0 +1,400 @@
1
+ require 'json'
2
+
3
+ #===============================================================================
4
+ # EzCSP
5
+ #
6
+
7
+ ##
8
+ # EzCSP provides a simple object-oriented way to generate
9
+ # <tt>Content-Security-Policy</tt> HTTP headers. For documentation on CSP,
10
+ # see {Mozilla's Content-Security-Policy page}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy].
11
+ #
12
+ # Basic usage:
13
+ #
14
+ # require 'ezcsp'
15
+ # csp = EzCSP.new()
16
+ #
17
+ # Then, depending on how you output HTTP headers, you could output the CSP header
18
+ # something like this:
19
+ #
20
+ # headers['Content-Security-Policy'] = csp.to_s
21
+ #
22
+ # <tt>csp.to_s</tt>, by default, returns this string:
23
+ #
24
+ # default-src 'self'; frame-src 'self'; object-src 'none'; form-action 'self'; frame-ancestors 'self'; base-uri 'none'; block-all-mixed-content;
25
+ #
26
+ # By default, the header value is very restrictive. It basically states that no
27
+ # resources — scripts, styles, images, etc. — from outside the current web site
28
+ # can be used. Expand that set of allowed resources by adding to the accessors
29
+ # listed below, usually by using the #cdn method. So, for example, to
30
+ # allow the browser to get scripts and styles from <tt>code.jquery.com</tt>,
31
+ # you would do this:
32
+ #
33
+ # csp.cdn 'code.jquery.com', 'script_src', 'style_src'
34
+ #
35
+ # which would produce this header value:
36
+ #
37
+ # default-src 'self'; script-src 'self' code.jquery.com; style-src 'self' code.jquery.com; frame-src 'self'; object-src 'none'; form-action 'self'; frame-ancestors 'self'; base-uri 'none'; block-all-mixed-content;
38
+ #
39
+ # EzCSP isn't a substitute for understanding content security policies. Make
40
+ # sure you
41
+ # {read up on CSP}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy]
42
+ # before using this class.
43
+ #
44
+ # In the array attributes listed below, if the value <tt>none</tt> is in the
45
+ # array, then all other values are ignored.
46
+
47
+ class EzCSP
48
+ # Array. Holds the list of
49
+ # {default-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src]
50
+ # hosts.
51
+ # By default, <tt>default_src</tt> is an empty array.
52
+ attr_accessor :default_src
53
+
54
+ # By default nil. If an array, this attribute holds the list of hosts in
55
+ # {img-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src].
56
+ attr_accessor :img_src
57
+
58
+ # By default nil. If an array, this attribute holds the list of hosts in
59
+ # {script-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src].
60
+ attr_accessor :script_src
61
+
62
+ # By default nil. If an array, this attribute holds the list of hosts in
63
+ # {style-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src].
64
+ attr_accessor :style_src
65
+
66
+ # Array. Holds the list of
67
+ # {frame-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src]
68
+ # hosts.
69
+ # By default, <tt>all_src</tt> consists of <tt>['self']</tt>.
70
+ attr_accessor :frame_src
71
+
72
+ # By default nil. If an array, this attribute holds the list of hosts in
73
+ # {font-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src].
74
+ attr_accessor :font_src
75
+
76
+ # Array. Holds the list of
77
+ # {object-src}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/object-src]
78
+ # hosts.
79
+ # By default, <tt>object_src</tt> consists of <tt>['none']</tt>.
80
+ attr_accessor :object_src
81
+
82
+ # Array. <tt>all_src</tt> is a shortcut for indicating that a host is to be
83
+ # included in all other *_src arrays.
84
+ # By default, <tt>all_src</tt> consists of <tt>['self']</tt>.
85
+ attr_accessor :all_src
86
+
87
+ # Array. Holds the list of
88
+ # {form-action}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action]
89
+ # hosts.
90
+ # By default, <tt>form_action</tt> consists of <tt>['self']</tt>.
91
+ attr_accessor :form_action
92
+
93
+ # Array. Holds the list of
94
+ # {frame-ancestors}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors]
95
+ # hosts.
96
+ # By default, <tt>frame_ancestors</tt> consists of <tt>['self']</tt>.
97
+ attr_accessor :frame_ancestors
98
+
99
+ # Array. Holds the list of
100
+ # {base-uri}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri]
101
+ # hosts.
102
+ # By default, <tt>base_uri</tt> consists of <tt>['none']</tt>.
103
+ attr_accessor :base_uri
104
+
105
+ # Boolean, defaults to true. Sets the value for
106
+ # {block-all-mixed-content}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/block-all-mixed-content].
107
+ attr_accessor :block_all_mixed_content
108
+
109
+ # Boolean, defaults to nil. Sets the value for
110
+ # {upgrade-insecure-requests}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests].
111
+ # If this value is set then #block_all_mixed_content is ignored.
112
+ attr_accessor :upgrade_insecure_requests
113
+
114
+ # This attribute is used to set two different things. It sets the
115
+ # {report-uri}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri]
116
+ # value, which is being phased out. It is also used in
117
+ # #report_to_header_value to generate a
118
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
119
+ # HTTP header. See details in #report_to_header_value.
120
+ attr_accessor :report_to
121
+
122
+ # Sets the name of the report-to group in the
123
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
124
+ # HTTP header.
125
+ # Defaults to <tt>csp-endpoint</tt>.
126
+ # See details in #report_to_header_value.
127
+ attr_accessor :report_to_group
128
+
129
+ # Sets the maximum age of the group in the
130
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
131
+ # HTTP header.
132
+ # Defaults to <tt>10886400</tt>.
133
+ attr_accessor :report_to_max_age
134
+
135
+
136
+ #---------------------------------------------------------------------------
137
+ # initialize
138
+ #
139
+
140
+ ##
141
+ # <tt>new()</tt> takes no parameters.
142
+
143
+ def initialize
144
+ # $tm.hrm
145
+
146
+ # all and default
147
+ @all_src = ['self']
148
+ @default_src = []
149
+
150
+ # inherit from default
151
+ @img_src = nil
152
+ @script_src = nil
153
+ @style_src = nil
154
+ @font_src = nil
155
+ @object_src = ['none']
156
+
157
+ # do not inherit from default
158
+ @frame_src = ['self']
159
+ @frame_ancestors = ['self']
160
+ @form_action = ['self']
161
+ @base_uri = ['none']
162
+
163
+ # booleans
164
+ @block_all_mixed_content = true
165
+ @upgrade_insecure_requests = nil
166
+ @default_to_explicit = true
167
+
168
+ # report_to
169
+ @report_to = nil
170
+ @report_to_group = 'csp-endpoint'
171
+ @report_to_max_age = 10886400
172
+ end
173
+ #
174
+ # initialize
175
+ #---------------------------------------------------------------------------
176
+
177
+
178
+ #---------------------------------------------------------------------------
179
+ # to_s
180
+ #
181
+
182
+ ##
183
+ # Returns the value of the cont
184
+ # {Content-Security-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy]
185
+ # HTTP header.
186
+ # Note that this method only returns the value, i.e., the stuff after the
187
+ # colon in the HTTP header.
188
+
189
+ def to_s
190
+ # $tm.hrm
191
+
192
+ # initialize return value
193
+ rv = []
194
+
195
+ # add some sources
196
+ src_to_str rv, 'default-src', @default_src, true
197
+ src_to_str rv, 'img-src', @img_src, true
198
+ src_to_str rv, 'script-src', @script_src, true
199
+ src_to_str rv, 'style-src', @style_src, true
200
+ src_to_str rv, 'frame-src', @frame_src, true
201
+ src_to_str rv, 'font-src', @font_src, true
202
+ src_to_str rv, 'object-src', @object_src, true
203
+ src_to_str rv, 'form-action', @form_action, false
204
+ src_to_str rv, 'frame-ancestors', @frame_ancestors, false
205
+ src_to_str rv, 'base-uri', @base_uri, false
206
+
207
+ # block all mixed content
208
+ if @upgrade_insecure_requests.nil?
209
+ if @block_all_mixed_content
210
+ rv.push 'block-all-mixed-content'
211
+ end
212
+ else
213
+ if @upgrade_insecure_requests
214
+ rv.push 'upgrade-insecure-requests'
215
+ end
216
+ end
217
+
218
+ # report-uri
219
+ if @report_to
220
+ rv.push 'report-uri ' + @report_to
221
+ rv.push 'report-to ' + @report_to_group
222
+ end
223
+
224
+ # initiilaze return string
225
+ rv_str = rv.join('; ')
226
+
227
+ # collapse rv_str
228
+ rv_str.sub!(/\A\s+/imu, '')
229
+ rv_str.sub!(/\s+\z/imu, '')
230
+ rv_str.gsub!(/\s+/imu, ' ')
231
+
232
+ # add trailing semicolon
233
+ if rv_str.length > 0
234
+ rv_str += ';'
235
+ end
236
+
237
+ # return
238
+ return rv_str
239
+ end
240
+ #
241
+ # to_s
242
+ #---------------------------------------------------------------------------
243
+
244
+
245
+ #---------------------------------------------------------------------------
246
+ # report_to_header_value
247
+ #
248
+
249
+ ##
250
+ # This method returns the value of a
251
+ # {report-to}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to]
252
+ # HTTP header. It is only useful if you set the #report_to property. For
253
+ # example, if you set #report_to like this:
254
+ #
255
+ # csp.report_to = 'https://www.example.com/csp'
256
+ #
257
+ # Then <tt>report_to_header_value</tt> returns a value like this:
258
+ #
259
+ # {"group":"csp-endpoint","max-age":10886400,"endpoints":[{"url":"https://www.example.com/csp"}]}
260
+ #
261
+ # So, depending on how you set your HTTP headers, you might set the Report-To
262
+ # header like this:
263
+ #
264
+ # headers['Report-To'] = csp.report_to_header_value
265
+
266
+ def report_to_header_value
267
+ # $tm.hrm
268
+
269
+ # initialize value struct
270
+ struct = {}
271
+
272
+ # group name
273
+ struct['group'] = @report_to_group
274
+
275
+ # max age
276
+ struct['max-age'] = @report_to_max_age
277
+
278
+ # endpoints
279
+ struct['endpoints'] = [{'url'=>@report_to}]
280
+
281
+ # return
282
+ # return 'Report-To: ' + JSON.generate(struct)
283
+ return JSON.generate(struct)
284
+ end
285
+ #
286
+ # report_to_header_value
287
+ #---------------------------------------------------------------------------
288
+
289
+
290
+ #---------------------------------------------------------------------------
291
+ # cdn
292
+ #
293
+
294
+ ##
295
+ # This method allows you to add a host to multiple source arrays at once.
296
+ # The first param is the host you would like to set. Follow that with a
297
+ # list of arrays to add it to. The list should consist of the names of the
298
+ # arrays, e.g. <tt>img_src</tt>.
299
+ #
300
+ # So, for example, this code:
301
+ #
302
+ # csp.cdn 'code.jquery.com', 'script_src', 'style_src'
303
+ #
304
+ # adds <tt>code.jquery.com</tt> to the #script_src and #style_src arrays,
305
+ # creating those arrays if necessary.
306
+
307
+ def cdn(uri, *srcs)
308
+ # $tm.hrm
309
+
310
+ # img
311
+ if srcs.include?('img_src')
312
+ @img_src ||= []
313
+ @img_src.push uri
314
+ end
315
+
316
+ # script
317
+ if srcs.include?('script_src')
318
+ @script_src ||= []
319
+ @script_src.push uri
320
+ end
321
+
322
+ # style
323
+ if srcs.include?('style_src')
324
+ @style_src ||= []
325
+ @style_src.push uri
326
+ end
327
+
328
+ # frame
329
+ if srcs.include?('frame_src')
330
+ @frame_src ||= []
331
+ @frame_src.push uri
332
+ end
333
+
334
+ # font
335
+ if srcs.include?('font_src')
336
+ @font_src ||= []
337
+ @font_src.push uri
338
+ end
339
+ end
340
+ #
341
+ # cdn
342
+ #---------------------------------------------------------------------------
343
+
344
+
345
+ # private
346
+ private
347
+
348
+
349
+ #---------------------------------------------------------------------------
350
+ # src_to_str
351
+ #
352
+ @@quote_values = %w{self none unsafe-inline unsafe-eval}
353
+
354
+ def src_to_str(rv, key, src, use_all)
355
+ # $tm.hrm
356
+ # $tm.debug key
357
+ # $tm.debug src
358
+
359
+ # early exit: if nil, nothing to do
360
+ src.nil? and return
361
+
362
+ # new src
363
+ srcs = []
364
+
365
+ # special case: src includes "none"
366
+ if src.include?('none')
367
+ src = ['none']
368
+ else
369
+ # add @all_src if necessary
370
+ if use_all and @all_src
371
+ srcs += @all_src
372
+ end
373
+ end
374
+
375
+ # add src
376
+ srcs += src
377
+
378
+ # map some values so that they have single quotes
379
+ srcs.map! do |itm|
380
+ if @@quote_values.include?(itm)
381
+ itm = "'#{itm}'"
382
+ end
383
+
384
+ # Collapse spaces, which actually shouldn't be there to begin with.
385
+ # Doing so helps avoid HTTP header injection.
386
+ itm = itm.gsub(/\s+/mu, ' ')
387
+
388
+ itm
389
+ end
390
+
391
+ # add to return values
392
+ rv.push key + ' ' + srcs.uniq.join(' ')
393
+ end
394
+ #
395
+ # src_to_str
396
+ #---------------------------------------------------------------------------
397
+ end
398
+ #
399
+ # EzCSP
400
+ #===============================================================================
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ezcsp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mike O'Sullivan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Simplifies creating a content security policy for use as an HTTP header
14
+ email: miko@idocs.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/ezcsp.rb
20
+ homepage: https://rubygems.org/gems/ezcsp
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubyforge_project:
40
+ rubygems_version: 2.5.2.1
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: Content security policy HTTP header builder
44
+ test_files: []