rack-response-signature 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.rdoc +81 -0
  2. data/lib/rack/response_signature.rb +142 -0
  3. metadata +63 -0
data/README.rdoc ADDED
@@ -0,0 +1,81 @@
1
+ == Rack::ResponseSignature
2
+
3
+ Rack::ResponseSignature is a Rack middleware which can drop into any
4
+ Rack-compliant application an add transparent response signing. Response
5
+ signing is done to verify to clients that the response is coming from a
6
+ trusted source. The signature is currently based on RSA Public/Private key
7
+ pair signing.
8
+
9
+ Primarily, this is useful when verified-SSL is not an option. This may occur
10
+ when you are working on a shared host or other environment which utilizes
11
+ wildcard certificates (like Heroku). In this case, while the SSL certificate
12
+ may be verified with the Certificate Authority, it doesn't not ensure the
13
+ identity of the serving party.
14
+
15
+ With this implementation:
16
+
17
+ * RSA keys of any strength may be used,
18
+ * SSL certificates are optional,
19
+ * Response signing is transparent,
20
+ * Response verification is simple
21
+
22
+ === Installation
23
+
24
+ From the gem:
25
+
26
+ $ sudo gem install rack-response-signature
27
+
28
+ From source:
29
+
30
+ $ git clone http://github.com/nbibler/rack_response_signature.git
31
+ $ rake package && sudo rake install
32
+
33
+ === Basic Usage
34
+
35
+ ==== Rack
36
+
37
+ Rack::ResponseSignature is implemented as a piece of Rack middleware and can
38
+ be used with any Rack-based application. If your application includes a
39
+ rackup file (`config.ru`, for example) or uses Rack::Builder to construct the
40
+ application stack, then require and use, like so:
41
+
42
+ require 'rack/response_signature'
43
+
44
+ use Rack::ResponseSignature, "my-private-ssh-key-for-signing"
45
+
46
+ run app
47
+
48
+ The SSH key may also be read from a file with `File.read('private.key')`, as
49
+ well.
50
+
51
+ ==== Rails
52
+
53
+ To use this middleware with Rails, add this to your `config/environment.rb`,
54
+ to `config/environments/production.rb`, or to an initializer:
55
+
56
+ config.middleware.use Rack::ResponseSignature, "my-private-ssh-key..."
57
+
58
+ You should now see `Rack::ResponseSignature` listed in the middleware stack:
59
+
60
+ $ rake middleware
61
+
62
+ === License
63
+
64
+ Copyright (c) 2010 Nathaniel Bibler <http://www.nathanielbibler.com/>
65
+
66
+ Permission is hereby granted, free of charge, to any person obtaining a copy
67
+ of this software and associated documentation files (the "Software"), to
68
+ deal in the Software without restriction, including without limitation the
69
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
70
+ sell copies of the Software, and to permit persons to whom the Software is
71
+ furnished to do so, subject to the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be included in
74
+ all copies or substantial portions of the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
77
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
78
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
79
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
80
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
81
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,142 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+ require 'cgi'
4
+
5
+ module Rack
6
+
7
+ ##
8
+ # Rack::ResponseSignature is a middleware which will manipulate the server
9
+ # response by signing the response body against an RSA private key. Your
10
+ # clients may then validate the response against a known-good public key
11
+ # to verify server authenticity against a man-in-the-middle attack.
12
+ #
13
+ # The signature, if generated, is placed in a "Response-Signature" HTTP
14
+ # header. Currently, signatures are only generated for HTTP SUCCESS (200)
15
+ # responses.
16
+ #
17
+ # Obviously, it would be more straightforward to simply use an SSL
18
+ # certificate provided by a trusted CA and just enable SSL verification
19
+ # per request. However, the use of SSL accrues significate overhead both for
20
+ # the server, the client, and the network in general. Not only that, but
21
+ # in some cases (like Heroku) using a custom, verifiable SSL certificate
22
+ # is either not reasonable or not possible.
23
+ #
24
+ # === Using Rack::ResponseSignature
25
+ #
26
+ # To use this middleware, simply:
27
+ #
28
+ # use Rack::ResponseSignature, "--- BEGIN PRIVATE KEY ----\nabc123....."
29
+ #
30
+ # Or, for Rails,
31
+ #
32
+ # config.middleware.use "Rack::ResponseSignature", "--- BEGIN PRIVATE KEY ----\nabc123....."
33
+ #
34
+ # Or, a somewhat more secure approach would be to utilize environment
35
+ # variables on the production system to define your private key. This
36
+ # keeps your private keys out of your source code manager and away from
37
+ # prying eyes:
38
+ #
39
+ # config.middleware.use "Rack::ResponseSignature", ENV['PRIVATE_RESPONSE_KEY']
40
+ #
41
+ # This is especially useful for Heroku deployments.
42
+ #
43
+ # === Manual Verification of Signature
44
+ #
45
+ # Using curl, you can manually inspect to be sure that your signatures are
46
+ # being generated with:
47
+ #
48
+ # $ curl -is http://myserver.com
49
+ #
50
+ # Which would return something similar to:
51
+ #
52
+ # HTTP/1.1 200 OK
53
+ # Server: nginx/0.6.39
54
+ # Date: Tue, 23 Feb 2010 05:15:25 GMT
55
+ # Content-Type: application/xml; charset=utf-8
56
+ # Transfer-Encoding: chunked
57
+ # Connection: keep-alive
58
+ # ETag: "54a2096d2c361907b3f9cc7ec9a2231d"
59
+ # Response-Signature: JywymlJfA90Q4x52LKt4J8Tb8p4rXI%2BptKDNm3NC7F495...
60
+ # Cache-Control: private, max-age=0, must-revalidate
61
+ #
62
+ # === Client Verification
63
+ #
64
+ # To verify your signatures on the client, simply share your public RSA key
65
+ # with your client and verify the response:
66
+ #
67
+ # require 'net/http'
68
+ # require 'base64'
69
+ # require 'cgi'
70
+ #
71
+ # uri = URI.parse("http://myserver.com/")
72
+ # response = nil
73
+ # Net::HTTP.start(uri.host, uri.port) do |http|
74
+ # response = http.get(uri.path)
75
+ # end
76
+ #
77
+ # puts "Response valid? %s" % [OpenSSL::PKey::RSA.new(PublicKey).
78
+ # verify(OpenSSL::Digest::SHA256.new,
79
+ # Base64.decode64(CGI.unescape(response['Response-Signature'])),
80
+ # response.body.strip)]
81
+ #
82
+ # === Options
83
+ #
84
+ # You may pass an optional, third, hash argument into the middleware. This
85
+ # argument allows you to override defaults.
86
+ #
87
+ # digest::
88
+ # Set the digest to use when generating the signature (Default: OpenSSL::Digest::SHA256)
89
+ #
90
+ class ResponseSignature
91
+
92
+ VERSION = '0.1.0'
93
+
94
+ def initialize(app, private_key, options = {})
95
+ options[:digest] ||= OpenSSL::Digest::SHA256
96
+ @app = app
97
+ @private_key = private_key && private_key != '' ? private_key : nil
98
+ @options = options
99
+ end
100
+
101
+ def call(env)
102
+ status, headers, response = @app.call(env)
103
+
104
+ if set_signature_header?(status)
105
+ [status, add_signature(headers, value_of(response)), value_of(response)]
106
+ else
107
+ [status, headers, response]
108
+ end
109
+ end
110
+
111
+
112
+ private
113
+
114
+
115
+ def set_signature_header?(status)
116
+ @private_key && status.to_i == 200
117
+ end
118
+
119
+ def add_signature(headers, body)
120
+ headers['Response-Signature'] = CGI.escape(Base64.encode64(sign(body)))
121
+ headers
122
+ end
123
+
124
+ def rsa
125
+ @rsa ||= OpenSSL::PKey::RSA.new(@private_key)
126
+ end
127
+
128
+ def sign(data)
129
+ rsa.sign(digest, data)
130
+ end
131
+
132
+ def digest
133
+ @options.has_key?(:digest) ? @options[:digest].new : OpenSSL::Digest::SHA256.new
134
+ end
135
+
136
+ def value_of(response)
137
+ (response.respond_to?(:body) ? response.body : response).strip
138
+ end
139
+
140
+ end
141
+
142
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-response-signature
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Nathaniel Bibler
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-15 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Rack::ResponseSignature uses RSA key pairs to transparently sign the outgoing responses from any Rack-compliant application.
22
+ email: gem@nathanielbibler.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/rack/response_signature.rb
31
+ - README.rdoc
32
+ has_rdoc: true
33
+ homepage: http://github.com/nbibler/rack_response_signature
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.3.6
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Rack middleware to add transparent response signing
62
+ test_files: []
63
+