encrypted-cookies 0.3 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
= Encrypted Cookies
|
2
2
|
|
3
|
+
== Important Notice
|
4
|
+
|
5
|
+
There will be breaking changes from v0.3 -> v1.0. Usage won't change, but any cookies written with v0.3 will not be able to be read by v1.0. This is a security update and it is strongly encouraged that you update your projects accordingly.
|
6
|
+
|
7
|
+
=== What the issue was with 0.3
|
8
|
+
|
9
|
+
ActiveSupport::MessageEncryptor offers two encryption functions, encrypt and encrypt_and_verify. While I intended to use encrypt_and_verify when I released the gem, I accidently left the call to encrypt in the code. Life isn't all bad, though. Your cookie written with v0.3 are still strongly encrypted, and only the holder of the secret (i.e., you) will be able to decrypt them. The problem arises from the fact that there is no verification on the encrypted payload. If someone tampers with the encrypted payload, you won't know it. Well, you will know it becuase the decrypted tampered payload will be gibberish, but that might be hard to recognize under some circumstances. Using encrypt_and_verify will sign the encrypted payload so that if it is tampered with you will know it right away.
|
10
|
+
|
11
|
+
ActiveSupport is actually deprecating encrypt and decrypt in v3.2 becuase of this very issue.
|
12
|
+
|
13
|
+
TL;DR; You data is secure with v0.3, but it is harder to tell if someone is trying to tamper with it.
|
14
|
+
|
15
|
+
Please feel free to contact me with any questions or concerns.
|
16
|
+
|
3
17
|
== Description
|
4
18
|
|
5
19
|
Encrypted cookie jar for Rails 3.
|
data/encrypted-cookies.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Les Fletcher"]
|
10
10
|
s.email = ["les.fletcher@gmail.com"]
|
11
|
-
s.homepage = ""
|
11
|
+
s.homepage = "http://github.com/hmcfletch/encrypted-cookies"
|
12
12
|
s.summary = %q{Encrypted cookies for Rails 3}
|
13
13
|
s.description = %q{Add an encrypted cookie jar for Rails 3 that can be chained with permanent and signed cookies}
|
14
14
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module EncryptedCookies
|
2
4
|
class EncryptedCookieJar < ActionDispatch::Cookies::CookieJar #:nodoc:
|
3
5
|
MAX_COOKIE_SIZE = 4096 # Cookies can typically store 4096 bytes.
|
@@ -11,7 +13,7 @@ module EncryptedCookies
|
|
11
13
|
|
12
14
|
def [](name)
|
13
15
|
if encrypted_message = @parent_jar[name]
|
14
|
-
@encrypter.
|
16
|
+
@encrypter.decrypt_and_verify(encrypted_message)
|
15
17
|
end
|
16
18
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
17
19
|
nil
|
@@ -22,9 +24,9 @@ module EncryptedCookies
|
|
22
24
|
def []=(key, options)
|
23
25
|
if options.is_a?(Hash)
|
24
26
|
options.symbolize_keys!
|
25
|
-
options[:value] = @encrypter.
|
27
|
+
options[:value] = @encrypter.encrypt_and_sign(options[:value])
|
26
28
|
else
|
27
|
-
options = { :value => @encrypter.
|
29
|
+
options = { :value => @encrypter.encrypt_and_sign(options) }
|
28
30
|
end
|
29
31
|
|
30
32
|
raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
|
@@ -50,7 +52,7 @@ module EncryptedCookies
|
|
50
52
|
|
51
53
|
if secret.length < SECRET_MIN_LENGTH
|
52
54
|
raise ArgumentError, "Secret should be something secure, " +
|
53
|
-
"like \"#{
|
55
|
+
"like \"#{SecureRandom.hex(16)}\". The value you " +
|
54
56
|
"provided, \"#{secret}\", is shorter than the minimum length " +
|
55
57
|
"of #{SECRET_MIN_LENGTH} characters"
|
56
58
|
end
|
@@ -10,7 +10,6 @@ module EncryptedCookies
|
|
10
10
|
def set_encrypted_value(name, value)
|
11
11
|
@parent_jar[name] = value
|
12
12
|
end
|
13
|
-
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
@@ -23,9 +22,10 @@ class TestEncryptedCookies < Test::Unit::TestCase
|
|
23
22
|
def setup
|
24
23
|
@cookie_jar = ActionDispatch::Cookies::CookieJar.new
|
25
24
|
@encrypted_cookie_jar = EncryptedCookies::EncryptedCookieJar.new(@cookie_jar, GOOD_SECRET_1)
|
26
|
-
@str = "
|
25
|
+
@str = "nothing to see here"
|
27
26
|
end
|
28
27
|
|
28
|
+
# make sure we detect valid secrets
|
29
29
|
def test_secret
|
30
30
|
assert_raise (ArgumentError) { EncryptedCookies::EncryptedCookieJar.new(@cookie_jar, nil) }
|
31
31
|
assert_raise (ArgumentError) { EncryptedCookies::EncryptedCookieJar.new(@cookie_jar, "") }
|
@@ -33,20 +33,27 @@ class TestEncryptedCookies < Test::Unit::TestCase
|
|
33
33
|
assert_nothing_raised { EncryptedCookies::EncryptedCookieJar.new(@cookie_jar, GOOD_SECRET_1) }
|
34
34
|
end
|
35
35
|
|
36
|
+
# quick test to see if the same thing comes out that goes in
|
36
37
|
def test_basic_encryption_decryption
|
37
38
|
@encrypted_cookie_jar[:test] = @str
|
38
|
-
|
39
|
-
assert @encrypted_cookie_jar.encrypted_value(:test) != @str
|
40
|
-
assert @encrypted_cookie_jar[:test] == @str
|
39
|
+
assert_equal @str, @encrypted_cookie_jar[:test]
|
41
40
|
end
|
42
41
|
|
42
|
+
# monkey with the signature
|
43
43
|
def test_tampered_signature
|
44
44
|
@encrypted_cookie_jar[:test] = @str
|
45
45
|
enc_value = @encrypted_cookie_jar.encrypted_value(:test)
|
46
|
+
enc_value = "#{enc_value}alittleextraattheend"
|
47
|
+
@encrypted_cookie_jar.set_encrypted_value(:test, enc_value)
|
48
|
+
assert @encrypted_cookie_jar[:test].nil?
|
49
|
+
end
|
46
50
|
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
# monkey with the payload
|
52
|
+
def test_tampered_payload
|
53
|
+
@encrypted_cookie_jar[:test] = @str
|
54
|
+
enc_value = @encrypted_cookie_jar.encrypted_value(:test)
|
55
|
+
enc_value = "alittleextraatthefront#{enc_value}"
|
56
|
+
@encrypted_cookie_jar.set_encrypted_value(:test, enc_value)
|
50
57
|
assert @encrypted_cookie_jar[:test].nil?
|
51
58
|
end
|
52
59
|
|
@@ -69,7 +76,39 @@ class TestEncryptedCookies < Test::Unit::TestCase
|
|
69
76
|
encrypted_cookie_jar_2 = EncryptedCookies::EncryptedCookieJar.new(@cookie_jar, GOOD_SECRET_1)
|
70
77
|
encrypted_cookie_jar_2.set_encrypted_value(:test, enc_value)
|
71
78
|
|
72
|
-
|
79
|
+
assert_equal @str, encrypted_cookie_jar_2[:test]
|
80
|
+
end
|
81
|
+
|
82
|
+
# some pieces of this test require checks against the version of ActiveSupport
|
83
|
+
# checking the individual pieces of the cookie payload
|
84
|
+
def test_full_encryption_path
|
85
|
+
@encrypted_cookie_jar[:test] = @str
|
86
|
+
enc_value = @encrypted_cookie_jar.encrypted_value(:test)
|
87
|
+
encryptor = ActiveSupport::MessageEncryptor.new(GOOD_SECRET_1)
|
88
|
+
|
89
|
+
# ActiveSupport 3.2 fixes an issue where the payload is serialized twice during
|
90
|
+
# encryption and verification
|
91
|
+
if ActiveSupport::VERSION::MAJOR == 3 && ActiveSupport::VERSION::MINOR >= 2
|
92
|
+
serializer = ActiveSupport::MessageEncryptor::NullSerializer
|
93
|
+
verifier = ActiveSupport::MessageVerifier.new(GOOD_SECRET_1, :serializer => serializer)
|
94
|
+
else
|
95
|
+
verifier = ActiveSupport::MessageVerifier.new(GOOD_SECRET_1)
|
96
|
+
end
|
97
|
+
|
98
|
+
payload, signature = @encrypted_cookie_jar.encrypted_value(:test).split("--")
|
99
|
+
# ActiveSupport 3.2 deprecates encrypt and decrypt
|
100
|
+
if ActiveSupport::VERSION::MAJOR == 3 && ActiveSupport::VERSION::MINOR >= 2
|
101
|
+
decoded_payload = ActiveSupport::Base64.decode64(payload)
|
102
|
+
decrypted_payload = encryptor.send(:_decrypt, decoded_payload)
|
103
|
+
else
|
104
|
+
# part of the double serialization in ActiveSupport < 3.2
|
105
|
+
decoded_payload = Marshal.load(ActiveSupport::Base64.decode64(payload))
|
106
|
+
decrypted_payload = encryptor.decrypt(decoded_payload)
|
107
|
+
end
|
108
|
+
signature_control = verifier.generate(decoded_payload)
|
109
|
+
|
110
|
+
assert_equal @str, decrypted_payload
|
111
|
+
assert_equal signature_control.split("--")[1], signature
|
73
112
|
end
|
74
113
|
|
75
114
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: encrypted-cookies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: "0
|
5
|
+
version: "1.0"
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Les Fletcher
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-12-04 00:00:00 -08:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -68,7 +68,7 @@ files:
|
|
68
68
|
- test/encryped_cookie_test.rb
|
69
69
|
- test/test_helper.rb
|
70
70
|
has_rdoc: true
|
71
|
-
homepage:
|
71
|
+
homepage: http://github.com/hmcfletch/encrypted-cookies
|
72
72
|
licenses: []
|
73
73
|
|
74
74
|
post_install_message:
|