ezcsp 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|