rack-content_security_policy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1c74e025fe99f4261fae5e2e702595beb9b583e6
4
+ data.tar.gz: 3a7a571e64ff5f6c9c6544cbdafec917a3486534
5
+ SHA512:
6
+ metadata.gz: b7f8a959b4aff650ec3ee02dbe8b58721d3c769b1c41486568a6c92439ead14673d37cede35bc51ee951c444af36e431cd3d029620dc86aabdd6be2e0ae494bd
7
+ data.tar.gz: 98b3604f10022434f6209398afb7bb99839573ddc8d09ac8ff30bd97639b5af1a32fea78c4eaaf61c9563ebdeb6d9db8c014bb540915d7c4576d95561ce0a68d
checksums.yaml.gz.sig ADDED
Binary file
data.tar.gz.sig ADDED
Binary file
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Glenn Rempe
4
+ Copyright (c) 2009-2012 Alexey Rodionov
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # Rack::ContentSecurityPolicy
2
+
3
+ [![Build Status](https://travis-ci.org/grempe/rack-content_security_policy.svg?branch=master)](https://travis-ci.org/grempe/rack-content_security_policy)
4
+ [![Code Climate](https://codeclimate.com/github/grempe/rack-content_security_policy/badges/gpa.svg)](https://codeclimate.com/github/grempe/rack-content_security_policy)
5
+
6
+ ## WARNING
7
+
8
+ This is pre-release software. It is pretty well tested but has not yet
9
+ been used in production. Your feedback is requested.
10
+
11
+ ## About
12
+
13
+ `Rack::ContentSecurityPolicy` is a Rack middleware that makes it easy for your
14
+ Rack based application (Sinatra, Rails) to serve Content Security Policy headers
15
+ for HTML pages.
16
+
17
+ This middleware was inspired by the [p0deje/content-security-policy](https://github.com/p0deje/content-security-policy)
18
+ middleware and borrows quite a bit of code from that gem. This gem also makes
19
+ extensive use of the [contracts](https://egonschiele.github.io/contracts.ruby/)
20
+ gem to enforce strict type checking and validation on all inputs and outputs.
21
+ It is designed to fail-fast on errors.
22
+
23
+ It provides full support for Content Security Policy Level 1/2/3 directives.
24
+
25
+ ## Installation
26
+
27
+ Add this line to your application's `Gemfile`:
28
+
29
+ ```ruby
30
+ gem 'rack-content_security_policy', '~> 0.1'
31
+ ```
32
+
33
+ And then execute:
34
+
35
+ ```
36
+ $ bundle install
37
+ ```
38
+
39
+ Or install it directly with:
40
+
41
+ ```
42
+ $ gem install rack-content_security_policy
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ This middleware can be configured with a block or a hash of config options. It
48
+ accepts two primary configuration options:
49
+
50
+ * `report_only` : boolean `true` or `false`. Returns a `Content-Security-Policy-Report-Only` header instead of `Content-Security-Policy` when `true`. Defaults to true.
51
+ * `directives` : A collection of valid CSP directives provided as key/value pairs. The key must be a lowercase String and must be comprised of the characters [a-z] and the `-`. The value must also be a String but is not limited to remain flexible as the CSP standards evolve. You can use conditional statements within the configuration block to set values dynamically at startup time. Defaults to an empty config that you must configure. An empty config will raise an exception.
52
+
53
+ Learn more about the Content Security Policy at the following sites:
54
+
55
+ * W3C CSP Level 1 (deprecated) : [https://www.w3.org/TR/CSP1/](https://www.w3.org/TR/CSP1/)
56
+ * W3C CSP Level 2 (current) : [https://www.w3.org/TR/CSP2/](https://www.w3.org/TR/CSP2/)
57
+ * W3C CSP Level 3 (draft) : [https://www.w3.org/TR/CSP3/](https://www.w3.org/TR/CSP3/)
58
+ * [https://developer.mozilla.org/en-US/docs/Web/Security/CSP](https://developer.mozilla.org/en-US/docs/Web/Security/CSP)
59
+ * [http://caniuse.com/#search=ContentSecurityPolicy](http://caniuse.com/#search=ContentSecurityPolicy)
60
+ * [http://content-security-policy.com/](http://content-security-policy.com/)
61
+ * [https://securityheaders.io](https://securityheaders.io)
62
+ * [https://scotthelme.co.uk/csp-cheat-sheet/](https://scotthelme.co.uk/csp-cheat-sheet/)
63
+ * [http://www.html5rocks.com/en/tutorials/security/content-security-policy/](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
64
+ * [https://hacks.mozilla.org/2016/02/implementing-content-security-policy/](https://hacks.mozilla.org/2016/02/implementing-content-security-policy/)
65
+
66
+ ### Block Configuration Example
67
+
68
+ ``` ruby
69
+ require 'rack/content_security_policy'
70
+
71
+ Rack::ContentSecurityPolicy.configure do |d|
72
+ d.report_only = ENV.fetch('RACK_ENV') != 'production'
73
+ d['default-src'] = "'none'"
74
+ d['script-src'] = "'self'"
75
+ end
76
+
77
+ use Rack::ContentSecurityPolicy
78
+ ```
79
+
80
+ ### Hash Configuration Example
81
+
82
+ ``` ruby
83
+ require 'rack/content_security_policy'
84
+
85
+ use Rack::ContentSecurityPolicy, report_only: true, directives: { 'default-src' => "'self'" }
86
+ ```
87
+
88
+ ## Development
89
+
90
+ After checking out the repo, run `bundle install` to install dependencies. Then,
91
+ run `bundle exec rake` to run the specs.
92
+
93
+ To install this gem onto your local machine, run `bundle exec rake install`.
94
+
95
+ ### Installation Security : Signed Ruby Gem
96
+
97
+ This gem is cryptographically signed. To be sure the gem you install hasn’t
98
+ been tampered with you can install it using the following method:
99
+
100
+ Add my public key (if you haven’t already) as a trusted certificate
101
+
102
+ ```
103
+ # Caveat: Gem certificates are trusted globally, such that adding a
104
+ # cert.pem for one gem automatically trusts all gems signed by that cert.
105
+ gem cert --add <(curl -Ls https://raw.github.com/grempe/rack-content_security_policy/master/certs/gem-public_cert_grempe_2026.pem)
106
+ ```
107
+
108
+ To install, it is possible to specify either `HighSecurity` or `MediumSecurity`
109
+ mode. Since this gem depends on one or more gems that are not cryptographically
110
+ signed you will likely need to use `MediumSecurity`. You should receive a warning
111
+ if any signed gem does not match its signature.
112
+
113
+ ```
114
+ # All signed dependent gems must be verified.
115
+ gem install rack-content_security_policy -P MediumSecurity
116
+ ```
117
+
118
+ You can [learn more about security and signed Ruby Gems](http://guides.rubygems.org/security/).
119
+
120
+ ### Installation Security : Signed Git Commits
121
+
122
+ Most, if not all, of the commits and tags to this repository are
123
+ signed with my PGP/GPG code signing key. I have uploaded my code signing public
124
+ keys to GitHub and you can now verify those signatures with the GitHub UI.
125
+ See [this list of commits](https://github.com/grempe/rack-content_security_policy/commits/master)
126
+ and look for the `Verified` tag next to each commit. You can click on that tag
127
+ for additional information.
128
+
129
+ You can also clone the repository and verify the signatures locally using your
130
+ own GnuPG installation. You can find my certificates and read about how to conduct
131
+ this verification at [https://www.rempe.us/keys/](https://www.rempe.us/keys/).
132
+
133
+ ### Contributing
134
+
135
+ Bug reports and pull requests are welcome on GitHub
136
+ at [https://github.com/grempe/rack-content_security_policy](https://github.com/grempe/rack-content_security_policy). This project is intended to be a safe, welcoming space for collaboration, and
137
+ contributors are expected to adhere to the
138
+ [Contributor Covenant](http://contributor-covenant.org) code of conduct.
139
+
140
+ ## Legal
141
+
142
+ ### Copyright
143
+
144
+ Copyright (c) 2016 Glenn Rempe <[glenn@rempe.us](mailto:glenn@rempe.us)> ([https://www.rempe.us/](https://www.rempe.us/))
145
+
146
+ Some portions Copyright (c) 2009-2012 Alexey Rodionov
147
+
148
+ ### License
149
+
150
+ The gem is available as open source under the terms of
151
+ the [MIT License](http://opensource.org/licenses/MIT).
152
+
153
+ ### Warranty
154
+
155
+ Unless required by applicable law or agreed to in writing,
156
+ software distributed under the License is distributed on an
157
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
158
+ either express or implied. See the LICENSE.txt file for the
159
+ specific language governing permissions and limitations under
160
+ the License.
161
+
162
+ ## Thank You!
163
+
164
+ Thanks to Alexey Rodionov ([@p0deje](https://github.com/p0deje)) for
165
+ his well written original implementation of CSP.
@@ -0,0 +1,94 @@
1
+ require 'contracts'
2
+ require 'rack/content_security_policy/contracts'
3
+
4
+ module Rack
5
+ class ContentSecurityPolicy
6
+ include Contracts::Core
7
+ include Contracts::Builtin
8
+
9
+ CSP_HEADER = 'Content-Security-Policy'.freeze
10
+ CSP_REPORT_ONLY_HEADER = 'Content-Security-Policy-Report-Only'.freeze
11
+ NO_ARG_DIRECTIVES = ['block-all-mixed-content',
12
+ 'disown-opener',
13
+ 'upgrade-insecure-requests'].freeze
14
+
15
+ Contract Any, KeywordArgs[directives: Optional[Directives], report_only: Optional[Bool]] => Any
16
+ def initialize(app, directives: {}, report_only: false)
17
+ @app = app
18
+
19
+ class_dirs = Rack::ContentSecurityPolicy.directives
20
+ if directives.empty? && class_dirs.empty?
21
+ raise ArgumentError, 'no directives provided'
22
+ end
23
+ @directives = class_dirs.merge(directives)
24
+
25
+ class_report_only = Rack::ContentSecurityPolicy.report_only
26
+ @report_only = report_only || class_report_only ? true : false
27
+ end
28
+
29
+ Contract None => Bool
30
+ def report_only
31
+ @report_only
32
+ end
33
+
34
+ Contract None => Directives
35
+ def directives
36
+ @directives
37
+ end
38
+
39
+ Contract Hash => RackResponse
40
+ def call(env)
41
+ dup._call(env)
42
+ end
43
+
44
+ Contract Hash => RackResponse
45
+ def _call(env)
46
+ status, headers, response = @app.call(env)
47
+
48
+ if headers['Content-Type'].include?('text/html')
49
+ directives = @directives.sort.map do |d|
50
+ if NO_ARG_DIRECTIVES.include?(d[0])
51
+ d[0]
52
+ else
53
+ "#{d[0]} #{d[1]}"
54
+ end
55
+ end.join('; ')
56
+
57
+ csp_hdr = @report_only ? CSP_REPORT_ONLY_HEADER : CSP_HEADER
58
+ headers[csp_hdr] = directives
59
+ end
60
+
61
+ [status, headers, response]
62
+ end
63
+
64
+ ################################
65
+ # CLASS METHODS
66
+ ################################
67
+
68
+ Contract Bool => Bool
69
+ def self.report_only=(ro)
70
+ @report_only = ro
71
+ end
72
+
73
+ Contract None => Bool
74
+ def self.report_only
75
+ @report_only
76
+ end
77
+
78
+ Contract None => Directives
79
+ def self.directives
80
+ @directives
81
+ end
82
+
83
+ Contract Proc => Or[String, Bool, nil]
84
+ def self.configure
85
+ @directives ||= {}
86
+ yield(self)
87
+ end
88
+
89
+ Contract DirectiveKey, DirectiveVal => Or[String, Bool]
90
+ def self.[]=(name, value)
91
+ @directives[name] = value
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,46 @@
1
+ module Rack
2
+ class ContentSecurityPolicy
3
+ # Custom Contracts
4
+ # See : https://egonschiele.github.io/contracts.ruby/
5
+
6
+ class DirectiveKey
7
+ def self.valid?(val)
8
+ Contract.valid?(val, /^[[a-z]+\-?]+$/)
9
+ end
10
+
11
+ def self.to_s
12
+ 'A CSP directive key must be one or more lowercase ASCII (a-z) characters with optional dashes (-)'
13
+ end
14
+ end
15
+
16
+ class DirectiveVal
17
+ def self.valid?(val)
18
+ Contract.valid?(val, Contracts::Or[String, Contracts::Bool])
19
+ end
20
+
21
+ def self.to_s
22
+ 'A CSP directive value must be a String or Boolean'
23
+ end
24
+ end
25
+
26
+ class Directives
27
+ def self.valid?(val)
28
+ Contract.valid?(val, Contracts::HashOf[DirectiveKey => DirectiveVal])
29
+ end
30
+
31
+ def self.to_s
32
+ 'A CSP directive key/value Hash'
33
+ end
34
+ end
35
+
36
+ class RackResponse
37
+ def self.valid?(val)
38
+ Contract.valid?(val, [Contracts::Int, Hash, Contracts::RespondTo[:each]])
39
+ end
40
+
41
+ def self.to_s
42
+ 'A Rack response'
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class ContentSecurityPolicy
3
+ VERSION = '0.1.0'.freeze
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,199 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-content_security_policy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Glenn Rempe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDYDCCAkigAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQ4wDAYDVQQDDAVnbGVu
14
+ bjEVMBMGCgmSJomT8ixkARkWBXJlbXBlMRIwEAYKCZImiZPyLGQBGRYCdXMwHhcN
15
+ MTYxMDEzMDEzMjM5WhcNMjYxMDExMDEzMjM5WjA7MQ4wDAYDVQQDDAVnbGVubjEV
16
+ MBMGCgmSJomT8ixkARkWBXJlbXBlMRIwEAYKCZImiZPyLGQBGRYCdXMwggEiMA0G
17
+ CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrEuLEy11cjgMC4+ldcgLzBrGcfWWg
18
+ nUhdCRn3Arzo2EV1d4V4h6VOHmk4o7kumBeajUMMZ0+xKtu8euRCnbDnlxowfJvT
19
+ S0nzsOt1dm++INeKMpZU84LuH7BbAlyL+B//l1YkI33gsbA8wm06+vV8tUEBuQch
20
+ vBU2xrCyS2+0LQTCaCS+VvHbV97hzIwSIgUFJuFjrcnnpV8Qt1R0Bi8pzDk+2jyN
21
+ AgxaWa41UHn70O0gFRRDGXacRpvy3HRSJrvlHPPAC02CjhKjsOLjZowaHxCv9XIJ
22
+ tCQnVEOUUo9+owG2Gna4k4DMLIjiGChHNFXtO8WyuksukVqcsdc9kvdzAgMBAAGj
23
+ bzBtMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBR68/Ook0uwfe6t
24
+ FbLHXIReYQ2VpzAZBgNVHREEEjAQgQ5nbGVubkByZW1wZS51czAZBgNVHRIEEjAQ
25
+ gQ5nbGVubkByZW1wZS51czANBgkqhkiG9w0BAQUFAAOCAQEAI27KUzTE9BoD2irI
26
+ CkMVPC0YS6iANrzQy3zIJI4yLKEZmI1jDE+W2APL11Woo5+sttgqY7148W84ZWdK
27
+ mD9ueqH5hPC8NOd3wYXVMNwmyLhnyh80cOzGeurW1SJ0VV3BqSKEE8q4EFjCzUK9
28
+ Oq8dW9i9Bxn8qgcOSFTYITJZ/mNyy2shHs5gg0MIz0uOsKaHqrrMseVfG7ZoTgV1
29
+ kkyRaYAHI1MSDNGFNwgURPQsgnxQrX8YG48q0ypFC1gOl/l6D0e/oF4SKMS156uc
30
+ vprF5QiDz8HshVP9DjJT2I1wyGyvxEdU3cTRo0upMP/VZLcgyBVFy90N2XYWWk2D
31
+ GIxGSw==
32
+ -----END CERTIFICATE-----
33
+ date: 2016-11-10 00:00:00.000000000 Z
34
+ dependencies:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rack
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ - !ruby/object:Gem::Dependency
50
+ name: contracts
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.14'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0.14'
63
+ - !ruby/object:Gem::Dependency
64
+ name: bundler
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.13'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.13'
77
+ - !ruby/object:Gem::Dependency
78
+ name: rake
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '11.0'
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '11.0'
91
+ - !ruby/object:Gem::Dependency
92
+ name: rspec
93
+ requirement: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3.0'
98
+ type: :development
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '3.0'
105
+ - !ruby/object:Gem::Dependency
106
+ name: rack-test
107
+ requirement: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '0.6'
112
+ type: :development
113
+ prerelease: false
114
+ version_requirements: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '0.6'
119
+ - !ruby/object:Gem::Dependency
120
+ name: simplecov
121
+ requirement: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '0.12'
126
+ type: :development
127
+ prerelease: false
128
+ version_requirements: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: '0.12'
133
+ - !ruby/object:Gem::Dependency
134
+ name: rubocop
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '0.41'
140
+ type: :development
141
+ prerelease: false
142
+ version_requirements: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - "~>"
145
+ - !ruby/object:Gem::Version
146
+ version: '0.41'
147
+ - !ruby/object:Gem::Dependency
148
+ name: wwtd
149
+ requirement: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '1.3'
154
+ type: :development
155
+ prerelease: false
156
+ version_requirements: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '1.3'
161
+ description: Rack middleware for declaratively setting the HTTP ContentSecurityPolicy
162
+ (W3C CSP Level 2/3) security header to help prevent against XSS and other browser
163
+ based attacks.
164
+ email:
165
+ - glenn@rempe.us
166
+ executables: []
167
+ extensions: []
168
+ extra_rdoc_files: []
169
+ files:
170
+ - LICENSE.txt
171
+ - README.md
172
+ - lib/rack/content_security_policy.rb
173
+ - lib/rack/content_security_policy/contracts.rb
174
+ - lib/rack/content_security_policy/version.rb
175
+ homepage: https://github.com/grempe/rack-content_security_policy
176
+ licenses:
177
+ - MIT
178
+ metadata: {}
179
+ post_install_message:
180
+ rdoc_options: []
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: 2.2.5
188
+ required_rubygems_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ requirements: []
194
+ rubyforge_project:
195
+ rubygems_version: 2.5.1
196
+ signing_key:
197
+ specification_version: 4
198
+ summary: Rack middleware for setting Content Security Policy (CSP) security headers
199
+ test_files: []
metadata.gz.sig ADDED
Binary file