cookie_crypt 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +46 -34
- data/app/controllers/devise/cookie_crypt_controller.rb +29 -21
- data/lib/cookie_crypt/controllers/helpers.rb +24 -11
- data/lib/cookie_crypt/version.rb +1 -1
- data/lib/generators/active_record/cookie_crypt_generator.rb +16 -2
- data/lib/generators/active_record/templates/migration_complete.rb +11 -0
- data/lib/generators/cookie_crypt/cookie_crypt_generator.rb +0 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ab81907032931a103687c8af34b6a15ba88b053
|
4
|
+
data.tar.gz: e1394c2e8fe187f3b1363aa76cc340bc4eae0357
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbc8b54e05d8a9aeff50f4e89493f169e4d199171f85a9a02accd7f552b2a58e0b2ae8230b894a9d5a8a5a000bf6143b80c1be9e3b75820d23f7e5d3df7eb998
|
7
|
+
data.tar.gz: 8568e107349345aa016964bad0edd7296e82818a8e7ae5ac1ff0c508f0165383d6460d34dcb0f2c4c6134d7beaa4f54d8c0f7c387fc01f60340a14c4eed1da25
|
data/README.md
CHANGED
@@ -44,7 +44,10 @@ Run the migration with:
|
|
44
44
|
|
45
45
|
bundle exec rake db:migrate
|
46
46
|
|
47
|
-
With the 1.1 update, more steps are required
|
47
|
+
With the 1.1 update, more steps are required if you are upgrading from a previous install. If you are installing this gem for
|
48
|
+
the first time, you can disregard everything up to "Customization" as the generator will only install exactly what you need.
|
49
|
+
|
50
|
+
If you are upgrading from a previous version, run the command:
|
48
51
|
|
49
52
|
bundle exec rails g cookie_crypt MODEL
|
50
53
|
|
@@ -56,6 +59,7 @@ This process will move your data (in a dev environment) from the old system to t
|
|
56
59
|
|
57
60
|
### Production Updating from 1.0 to 1.1
|
58
61
|
|
62
|
+
If you do not care about your users having to redo their questions / answers when their cookie expires, you can skip this process.
|
59
63
|
Assuming all files are already on the production box, run
|
60
64
|
|
61
65
|
bundle exec rake db:migrate VERSION=(version of the FIRST migration)
|
@@ -73,7 +77,7 @@ Again to remove the old fields.
|
|
73
77
|
|
74
78
|
### Customization
|
75
79
|
|
76
|
-
By default encrypted cookie two factor authentication is enabled for each user, you can change it with this method in your User model:
|
80
|
+
By default encrypted cookie two factor authentication is enabled for each user, you can change it with this method in your User model (if thats what you chose to Cookie Crypt):
|
77
81
|
|
78
82
|
```ruby
|
79
83
|
def need_two_factor_authentication?(request)
|
@@ -83,7 +87,45 @@ By default encrypted cookie two factor authentication is enabled for each user,
|
|
83
87
|
|
84
88
|
This will disable two factor authentication for local users and just put the code in the logs.
|
85
89
|
|
86
|
-
It is recommended to take a look at the source for the views, they are not complex but the default ones may not suit your design.
|
90
|
+
It is recommended to take a look at the source for the views, they are not overly complex but the default ones may not suit your design.
|
91
|
+
|
92
|
+
You can also customize options set in config/initializers/devise.rb. The default options tend to be best practices but may not suit your needs.
|
93
|
+
|
94
|
+
Question-auth refers to when a user does not have a cookie or their cookie has expired. If they have a valid cookie and user agent as described above, they will bypass
|
95
|
+
the question-auth.
|
96
|
+
* cookie_crypt_auth_through
|
97
|
+
* :one_question_cyclical
|
98
|
+
* The default
|
99
|
+
* Each user must answer only one of their questions at the end of a cookie cycle to authenticate.
|
100
|
+
* The questions are chosen cyclically, the user will not answer the same question the next time they have to question-auth through two-factor
|
101
|
+
* This prevents users logging in on a new machine from always being shown the same questions and is more secure
|
102
|
+
* :one_question_random
|
103
|
+
* The user is shown a random question that was not their previous question every time they question-auth through two-factor, otherwise exactly like cyclical
|
104
|
+
* The question asked in the previous question-auth will never be the next question-auth's question.
|
105
|
+
* :two_questions_cyclical
|
106
|
+
* Exactly like one_question_cyclical except two questions must be answered every question-auth
|
107
|
+
* :two_questions_random
|
108
|
+
* Exactly like one_question_random except two questions must be answered every question-auth
|
109
|
+
* Note: the questions will never be the same question or the FIRST question that was asked last question-auth.
|
110
|
+
* :all_questions
|
111
|
+
* This option is not advised, but is available. It is the old functionality the system had.
|
112
|
+
* The user must answer all authentication questions every question-auth session
|
113
|
+
* cookie_crypt_minimum_questions
|
114
|
+
* Default is 3
|
115
|
+
* Minimum number of questions and answers the user must enter into the system on their initial attempt
|
116
|
+
* Systems upgrading from 1.0 will prompt the user to add the difference in numbers of questions and answers
|
117
|
+
* cycle_question_on_fail_count
|
118
|
+
* Default is 2
|
119
|
+
* Minimum number of failed attempts before the question(s) is(are) cycled to the next question(s)
|
120
|
+
* enable_custom_question_counts
|
121
|
+
* Default is false
|
122
|
+
* Allows users to have more than the minimum number of security question / answer pairs. It should be noted that this enables some ajax functionality on the views page.
|
123
|
+
* max_cookie_crypt_login_attempts
|
124
|
+
* Default is 3
|
125
|
+
* The maximum number of tries a user has before they are locked out of cookie crypt and unable to fully login.
|
126
|
+
* cookie_deletion_time_frame
|
127
|
+
* Default is '30.days.from.now'
|
128
|
+
* Must be a string that evaluates to a date in the future.
|
87
129
|
|
88
130
|
### Rationalle
|
89
131
|
|
@@ -128,34 +170,4 @@ What cookie crypt doesnt prevent:
|
|
128
170
|
|
129
171
|
Afterword: Spoofing a user agent is not that difficult, any modern browser with dev tools can change its user agent rather easily. The catch is that the values
|
130
172
|
need to match with what the user already has which requires additional work on the attacker's part. Also, The system recognizes updates to both the user's OS AND
|
131
|
-
browser.
|
132
|
-
|
133
|
-
|
134
|
-
### Whats new with the 1.1 Update
|
135
|
-
* Reworked security questions and answers to allow for more customization options
|
136
|
-
* cookie_crypt_auth_through
|
137
|
-
* :one_question_cyclical
|
138
|
-
* The default
|
139
|
-
* Each user must answer only one of their questions at the end of a cookie cycle to authenticate.
|
140
|
-
* The questions are chosen cyclically, the user will not answer the same question the next time they have to auth through two-factor
|
141
|
-
* This prevents users logging in on a new machine from always being shown the same questions and is more secure
|
142
|
-
* :one_question_random
|
143
|
-
* The user is shown a random question that was not their previous question every time they auth through two-factor, otherwise exactly like cyclical
|
144
|
-
* :two_questions_cyclical
|
145
|
-
* Exactly like one_question_cyclical except two questions must be answered every auth
|
146
|
-
* :two_questions_random
|
147
|
-
* Exactly like one_question_random except two questions must be answered every auth
|
148
|
-
* :all_questions
|
149
|
-
* This option is not advised, but is available. It is the old functionality the system had.
|
150
|
-
* The user must answer all authentication questions every auth session
|
151
|
-
* cookie_crypt_minimum_questions
|
152
|
-
* Default is 3
|
153
|
-
* Minimum number of questions and answers the user must enter into the system on their initial attempt
|
154
|
-
* Systems upgrading from 1.0 will prompt the user to add the difference in numbers of questions and answers
|
155
|
-
* cycle_question_on_fail_count
|
156
|
-
* Default is 2
|
157
|
-
* Minimum number of failed attempts before the question(s) is(are) cycled to the next question(s)
|
158
|
-
* Works in conjunction with max_cookie_crypt_login_attempts
|
159
|
-
* enable_custom_question_counts
|
160
|
-
* Default is false
|
161
|
-
* Allows users to have more than the minimum number of security question / answer pairs.
|
173
|
+
browser. It should also be noted that cookies served over https are also further encrypted, making it much more difficult for an attacker to get the user's auth-cookie.
|
@@ -47,11 +47,9 @@ class Devise::CookieCryptController < DeviseController
|
|
47
47
|
elsif (h.keys.count/2) < resource.class.cookie_crypt_minimum_questions # Need to update hash from an old install
|
48
48
|
|
49
49
|
((h.keys.count/2)+1..(params[:security].keys.count/2)+((h.keys.count/2))).each do |n|
|
50
|
-
puts "TESTING::#{n}"
|
51
50
|
h["security_question_#{n}"] = sanitize(params[:security]["security_question_#{n}".to_sym])
|
52
51
|
h["security_answer_#{n}"] = Digest::SHA512.hexdigest(sanitize(params[:security]["security_answer_#{n}".to_sym]))
|
53
52
|
end
|
54
|
-
puts "TESTING2::#{h}"
|
55
53
|
resource.security_hash = h.to_s
|
56
54
|
|
57
55
|
resource.save
|
@@ -101,37 +99,46 @@ class Devise::CookieCryptController < DeviseController
|
|
101
99
|
if resource.class.cookie_crypt_auth_through == :one_question_cyclical
|
102
100
|
set_cyclicial_cyclemod(h)
|
103
101
|
elsif resource.class.cookie_crypt_auth_through == :one_question_random
|
104
|
-
set_random_cyclemod
|
102
|
+
set_random_cyclemod(h)
|
105
103
|
elsif resource.class.cookie_crypt_auth_through == :two_questions_cyclical
|
106
104
|
set_cyclicial_cyclemod(h)
|
107
105
|
|
108
106
|
if session[:cyclemod]+resource.security_cycle+1 <= h.keys.count/2
|
109
|
-
next_question_mod = session[:cyclemod]+1
|
107
|
+
next_question_mod = session[:cyclemod]+resource.security_cycle+1
|
110
108
|
else
|
111
|
-
next_question_mod =
|
109
|
+
next_question_mod = 1
|
112
110
|
end
|
113
111
|
|
114
112
|
@questions << h["security_question_#{next_question_mod}"]
|
115
113
|
elsif resource.class.cookie_crypt_auth_through == :two_questions_random
|
116
114
|
if resource.cookie_crypt_attempts_count == 0
|
117
|
-
session[:cyclemod]
|
118
|
-
r = Random.rand(
|
119
|
-
while session[:cyclemod]
|
120
|
-
r = Random.rand(
|
115
|
+
session[:cyclemod] ||= Random.rand(1..(h.keys.count/2))
|
116
|
+
r = Random.rand(1..(h.keys.count/2))
|
117
|
+
while session[:cyclemod] == r || resource.security_cycle == r
|
118
|
+
r = Random.rand(1..(h.keys.count/2))
|
121
119
|
end
|
122
|
-
session[:cyclemod2]
|
123
|
-
elsif resource.cookie_crypt_attempts_count != 0 && resource.cookie_crypt_attempts_count%resource.class.cycle_question_on_fail_count == 0
|
124
|
-
|
125
|
-
|
126
|
-
|
120
|
+
session[:cyclemod2] ||= r
|
121
|
+
elsif resource.cookie_crypt_attempts_count != 0 && resource.cookie_crypt_attempts_count%resource.class.cycle_question_on_fail_count == 0
|
122
|
+
#The tick assists pages that are running redirects to other sources while in two-factor mode. Without it, their
|
123
|
+
#cyclemod would desynch from the expected value on the change event (this if case) and they would be unable to auth unless the randoms matched.
|
124
|
+
session[:cookie_tick] ||= 0
|
125
|
+
session[:cookie_tick] += 1
|
126
|
+
|
127
|
+
if session[:cookie_tick] == 1
|
128
|
+
r = Random.rand(1..(h.keys.count/2))
|
129
|
+
while session[:cyclemod] == r || resource.security_cycle == r
|
130
|
+
r = Random.rand(1..(h.keys.count/2))
|
131
|
+
end
|
132
|
+
session[:cyclemod] = r
|
133
|
+
|
134
|
+
r = Random.rand(1..(h.keys.count/2))
|
135
|
+
while session[:cyclemod] == r || resource.security_cycle == r
|
136
|
+
r = Random.rand(1..(h.keys.count/2))
|
137
|
+
end
|
138
|
+
session[:cyclemod2] = r
|
127
139
|
end
|
128
|
-
|
129
|
-
|
130
|
-
r = Random.rand(0..(h.keys.count/2))
|
131
|
-
while session[:cyclemod] != r && resource.security_cycle != r
|
132
|
-
r = Random.rand(0..(h.keys.count/2))
|
133
|
-
end
|
134
|
-
session[:cyclemod2] = r
|
140
|
+
else #reset the tick
|
141
|
+
session[:cookie_tick] = 0
|
135
142
|
end
|
136
143
|
|
137
144
|
@questions << h["security_question_#{session[:cyclemod2]}"]
|
@@ -145,6 +152,7 @@ class Devise::CookieCryptController < DeviseController
|
|
145
152
|
unless resource.class.cookie_crypt_auth_through == :all_questions
|
146
153
|
if resource.class.cookie_crypt_auth_through == :one_question_cyclical ||
|
147
154
|
resource.class.cookie_crypt_auth_through == :two_questions_cyclical
|
155
|
+
|
148
156
|
@questions << h["security_question_#{resource.security_cycle+session[:cyclemod]}"]
|
149
157
|
else #random cyclemod case
|
150
158
|
@questions << h["security_question_#{session[:cyclemod]}"]
|
@@ -71,6 +71,11 @@ module CookieCrypt
|
|
71
71
|
|
72
72
|
def matching_answers? hash
|
73
73
|
answers = []
|
74
|
+
answers_from_form = []
|
75
|
+
params[:security_answers].each_key do |key|
|
76
|
+
answers_from_form << key
|
77
|
+
end
|
78
|
+
|
74
79
|
unless resource.class.cookie_crypt_auth_through == :all_questions
|
75
80
|
if resource.class.cookie_crypt_auth_through == :one_question_cyclical ||
|
76
81
|
resource.class.cookie_crypt_auth_through == :two_questions_cyclical
|
@@ -83,7 +88,7 @@ module CookieCrypt
|
|
83
88
|
|
84
89
|
if resource.class.cookie_crypt_auth_through == :two_questions_cyclical
|
85
90
|
if session[:cyclemod]+resource.security_cycle+1 <= hash.keys.count/2
|
86
|
-
next_question_mod = session[:cyclemod]+1
|
91
|
+
next_question_mod = session[:cyclemod]+resource.security_cycle+1
|
87
92
|
else
|
88
93
|
next_question_mod = 0
|
89
94
|
end
|
@@ -99,7 +104,7 @@ module CookieCrypt
|
|
99
104
|
|
100
105
|
authed = false
|
101
106
|
a_arr = []
|
102
|
-
answers.
|
107
|
+
answers.each do |key|
|
103
108
|
if hash[key] == Digest::SHA512.hexdigest(sanitize(params[:security_answers][key]))
|
104
109
|
a_arr[answers.index(key)] = true
|
105
110
|
else
|
@@ -123,11 +128,11 @@ module CookieCrypt
|
|
123
128
|
|
124
129
|
def set_random_cyclemod hash
|
125
130
|
if resource.cookie_crypt_attempts_count == 0
|
126
|
-
session[:cyclemod] = Random.rand(
|
131
|
+
session[:cyclemod] = Random.rand(1..(hash.keys.count/2))
|
127
132
|
elsif resource.cookie_crypt_attempts_count != 0 && resource.cookie_crypt_attempts_count%resource.class.cycle_question_on_fail_count == 0
|
128
|
-
r = Random.rand(
|
129
|
-
while session[:cyclemod]
|
130
|
-
r = Random.rand(
|
133
|
+
r = Random.rand(1..(hash.keys.count/2))
|
134
|
+
while session[:cyclemod] == r || resource.security_cycle == r
|
135
|
+
r = Random.rand(1..(hash.keys.count/2))
|
131
136
|
end
|
132
137
|
session[:cyclemod] = r
|
133
138
|
|
@@ -135,12 +140,20 @@ module CookieCrypt
|
|
135
140
|
end
|
136
141
|
|
137
142
|
def update_resource_cycle hash
|
138
|
-
if resource.
|
139
|
-
resource.
|
140
|
-
else
|
141
|
-
resource.security_cycle += 1
|
142
|
-
end
|
143
|
+
if resource.class.cookie_crypt_auth_through == :one_question_cyclical ||
|
144
|
+
resource.class.cookie_crypt_auth_through == :two_questions_cyclical
|
143
145
|
|
146
|
+
if resource.security_cycle+1 > hash.keys.count/2
|
147
|
+
resource.security_cycle = 1
|
148
|
+
else
|
149
|
+
resource.security_cycle += 1
|
150
|
+
end
|
151
|
+
elsif resource.class.cookie_crypt_auth_through == :one_question_random ||
|
152
|
+
resource.class.cookie_crypt_auth_through == :two_questions_random
|
153
|
+
|
154
|
+
resource.security_cycle = session[:cyclemod]
|
155
|
+
end
|
156
|
+
|
144
157
|
resource.save
|
145
158
|
end
|
146
159
|
|
data/lib/cookie_crypt/version.rb
CHANGED
@@ -5,14 +5,28 @@ module ActiveRecord
|
|
5
5
|
class CookieCryptGenerator < ActiveRecord::Generators::Base
|
6
6
|
source_root File.expand_path("../templates", __FILE__)
|
7
7
|
|
8
|
+
#This should only be triggered on a system that has no previous install(s)
|
9
|
+
def copy_cookie_crypt_migration_all
|
10
|
+
if ActiveRecord::Base.class_eval("#{table_name.camelize.singularize}.inspect['security_question_one: string'].blank?") &&
|
11
|
+
ActiveRecord::Base.class_eval("#{table_name.camelize.singularize}.inspect['security_hash: text'].blank?")
|
12
|
+
|
13
|
+
@ignore_other_migrations = true
|
14
|
+
migration_template "migration_complete.rb", "db/migrate/cookie_crypt_complete_install_add_to_#{table_name}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
8
18
|
def copy_cookie_crypt_migration_1_0
|
9
|
-
if ActiveRecord::Base.class_eval("#{table_name.camelize.singularize}.inspect['security_question_one: string'].blank?")
|
19
|
+
if ActiveRecord::Base.class_eval("#{table_name.camelize.singularize}.inspect['security_question_one: string'].blank?") &&
|
20
|
+
!@ignore_other_migrations
|
21
|
+
|
10
22
|
migration_template "migration.rb", "db/migrate/cookie_crypt_add_to_#{table_name}"
|
11
23
|
end
|
12
24
|
end
|
13
25
|
|
14
26
|
def copy_cookie_crypt_migration_1_1
|
15
|
-
if ActiveRecord::Base.class_eval("#{table_name.camelize.singularize}.inspect['security_hash: text'].blank?")
|
27
|
+
if ActiveRecord::Base.class_eval("#{table_name.camelize.singularize}.inspect['security_hash: text'].blank?") &&
|
28
|
+
!@ignore_other_migrations
|
29
|
+
|
16
30
|
migration_template "migration_1_1.rb", "db/migrate/cookie_crypt_1_1_update_to_#{table_name}"
|
17
31
|
end
|
18
32
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CookieCryptCompleteInstallAddTo<%= table_name.camelize %> < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
change_table :<%= table_name %> do |t|
|
4
|
+
<%='t.string :username, null: false, default: ""' if ActiveRecord::Base.class_eval("#{table_name.camelize.singularize}.inspect['username: string'].blank?") %>
|
5
|
+
t.text :security_hash, default: "{}"
|
6
|
+
t.integer :security_cycle, default: 1
|
7
|
+
t.text :agent_list, default: ""
|
8
|
+
t.integer :cookie_crypt_attempts_count, default: 0
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -62,8 +62,6 @@ module CookieCryptable
|
|
62
62
|
copy_file "_extra_fields.html.erb", "app/views/devise/cookie_crypt/_extra_fields.html.erb"
|
63
63
|
File.delete("app/views/devise/cookie_crypt/show.html.erb")
|
64
64
|
copy_file "show.html.erb", "app/views/devise/cookie_crypt/show.html.erb"
|
65
|
-
|
66
|
-
puts "Please run rake db:migrate then run this generator again to cleanup unused fields."
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
@@ -82,8 +80,6 @@ module CookieCryptable
|
|
82
80
|
obj.security_hash = h.to_s
|
83
81
|
|
84
82
|
obj.save
|
85
|
-
|
86
|
-
puts "#{obj.security_hash}"
|
87
83
|
end
|
88
84
|
|
89
85
|
puts "Completed data cleanup, database is now 1.1 ready."
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cookie_crypt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitrii Golub
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-11-
|
12
|
+
date: 2013-11-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- lib/generators/active_record/templates/migration.rb
|
104
104
|
- lib/generators/active_record/templates/migration_1_1.rb
|
105
105
|
- lib/generators/active_record/templates/migration_1_1_cleanup.rb
|
106
|
+
- lib/generators/active_record/templates/migration_complete.rb
|
106
107
|
- lib/generators/cookie_crypt/cookie_crypt_generator.rb
|
107
108
|
homepage: https://github.com/loualrid/CookieCrypt
|
108
109
|
licenses:
|