encrypted-cookies 0.3 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.
@@ -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.decrypt(encrypted_message)
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.encrypt(options[:value])
27
+ options[:value] = @encrypter.encrypt_and_sign(options[:value])
26
28
  else
27
- options = { :value => @encrypter.encrypt(options) }
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 \"#{ActiveSupport::SecureRandom.hex(16)}\". The value you " +
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
@@ -1,3 +1,3 @@
1
1
  module EncryptedCookies
2
- VERSION = "0.3"
2
+ VERSION = "1.0"
3
3
  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 = "test string"
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
- data, digest = enc_value.split("--")
48
- @encrypted_cookie_jar.set_encrypted_value(:test, "#{data}--sdgsad")
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
- assert encrypted_cookie_jar_2[:test] == @str
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.3"
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-06-17 00:00:00 -07:00
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: