ezcsp 0.0.1
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.
- checksums.yaml +7 -0
- data/lib/ezcsp.rb +400 -0
- 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: []
|