devise_sqreener 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CODE_OF_CONDUCT.md +1 -1
- data/LICENSE +1 -1
- data/README.md +95 -64
- data/config/locales/en.yml +7 -0
- data/lib/devise_sqreener/model.rb +1 -1
- data/lib/devise_sqreener/sqreen.rb +4 -1
- data/lib/devise_sqreener/version.rb +1 -1
- data/lib/generators/active_record/devise_sqreener_generator.rb +7 -1
- data/lib/generators/active_record/migration.rb +1 -1
- data/lib/generators/devise_sqreener/{devise_enricher_generator.rb → devise_sqreener_generator.rb} +0 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd8c549f4b58bc36ce9472751ee058c68c380770
|
4
|
+
data.tar.gz: e10015a600e3ccf712f6f6da8e8e4ad6fbe76f4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6979035b284d536e6aa2f92625dbd64d7095f6517f73d754b34ea7d443cace06130fa73345275a1f4ba149ceb35c730b627ceea609b29aeac445932145010d8
|
7
|
+
data.tar.gz: cc2cf0503cc100fca46049a3ac7837dfcc16e6e8e104402dd93278c47d9c58b2352a8e71caebee9252a22efda9909b7599d5edc8bece946af7c1b34ba49efd3e
|
data/CODE_OF_CONDUCT.md
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
# devise\_sqreener
|
2
2
|
|
3
|
-
|
3
|
+
Not everyone who signs up for your app wants to use your service. Wouldn’t it be nice if there was an easy way to automatically block abusers? This project adds the ability to block or flag potentially malicious users of your Rails app to the Devise user authentication module.
|
4
|
+
|
5
|
+
Whenever a new user signs up or signs in, their IP address and email address are compared against Sqreen's extensive database of bad apples; you get back a chunk of actionable metadata on those addresses that can be used to set user policies. You can, for example:
|
6
|
+
|
7
|
+
* Block users with a history of malicious abuse from signing up
|
8
|
+
* Prevent users from signing in over TOR.
|
9
|
+
* Discover whether someone is logging in from two distinct geographic locations at the same time.
|
10
|
+
* Flag users signing up with disposable email addresses.
|
11
|
+
|
12
|
+
Such fun!
|
4
13
|
|
5
14
|
## Installation
|
6
15
|
|
7
|
-
Add this line to your application Gemfile:
|
16
|
+
Of course, the best way to install is with RubyGems! Add this line to your application's Gemfile:
|
8
17
|
|
9
18
|
```ruby
|
10
19
|
gem 'devise_sqreener'
|
@@ -15,106 +24,128 @@ and then execute
|
|
15
24
|
$ bundle
|
16
25
|
```
|
17
26
|
|
18
|
-
|
27
|
+
to download the latest version and install it.
|
19
28
|
|
20
|
-
|
29
|
+
## Install devise_sqreener
|
21
30
|
|
22
|
-
|
31
|
+
Let's assume your user model is called `User`.
|
32
|
+
|
33
|
+
First we should note that `devise_sqreened` relies on the Devise `:trackable` strategy for tracking IP addresses. By default, `:trackable` is enabled, but if your use model doesn't include `:trackable`, and you want to enable the IP address filtering features, then you'll need to re-enable `:trackable`. Doing that is a bit beyond the scope of this tutorial, unfortunately. Anyway, the default Devise User model looks something like this, for reference purposes.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
class User < ActiveRecord::Base
|
37
|
+
# Include default devise modules. Others available are:
|
38
|
+
# :confirmable, :lockable, :timeoutable and :omniauthable
|
39
|
+
devise :database_authenticatable, :registerable,
|
40
|
+
:recoverable, :rememberable, :trackable, :validatable
|
41
|
+
end
|
42
|
+
```
|
43
|
+
OK, so that out of the way, let's add `devise\_sqreener` to the `User` model using the following generator:
|
23
44
|
|
24
45
|
```bash
|
25
|
-
$ rails generate devise_sqreener
|
46
|
+
$ rails generate devise_sqreener User
|
26
47
|
```
|
27
48
|
|
28
|
-
|
49
|
+
This will add the `:sqreenable` flag to your `User` model, and some new fields in the User table of your database. The generator will also create a migration file. Currently only ActiveRecord is supported.
|
50
|
+
|
51
|
+
Let's get that migration knocked out, then? Run:
|
29
52
|
|
30
53
|
```bash
|
31
54
|
$ rails db:migrate
|
32
55
|
```
|
33
56
|
|
34
|
-
|
57
|
+
## Get your API token
|
58
|
+
|
59
|
+
For the automatic sqreening to work you need to provide [your Sqreen API token](https://my.sqreen.io) in your Devise configuration, `config/initializers/devise.rb`. You might need to create an account on Sqreen—and once you do you can choose between the 14-day free trial for the full product; if you just want to get straight to the API, however, create a new API Sandbox instead. The API Sandboxes are free forever, albeit rate-limited and with a limited number of requests per month. That will do for our purposes nicely.
|
60
|
+
|
61
|
+
Anyway, we're not going to advocate for just leaving service credentials in your code, did you? Ha, of course not. No, we're going to pass it in as an environment variable. So add the following *_verbatim_* to the bottom of your Devise configuration.
|
62
|
+
|
35
63
|
```ruby
|
36
64
|
Devise.setup do |config|
|
37
65
|
#...
|
38
|
-
config.sqreen_api_token="TOKEN
|
66
|
+
config.sqreen_api_token=ENV["SQREEN_API_TOKEN"] # <- DO NOT PUT YOUR API TOKEN HERE!
|
39
67
|
#...
|
40
68
|
end
|
41
69
|
```
|
42
70
|
|
43
|
-
|
44
|
-
|
45
|
-
First if you want IP addresses to be sqreened (as it were) ensure your model use Devise `:trackable`.
|
46
|
-
|
47
|
-
Add `:sqreenable` to the devise call in your model:
|
71
|
+
And pass it in to your app's runtime environment with something like
|
48
72
|
|
49
|
-
```ruby
|
50
|
-
class User < ActiveRecord
|
51
|
-
devise :database_authenticable, :confirmable, :sqreenable
|
52
|
-
end
|
53
73
|
```
|
54
|
-
|
55
|
-
|
56
|
-
```ruby
|
57
|
-
class DeviseSqreenerAddToUser < ActiveRecord::Migration
|
58
|
-
def change
|
59
|
-
add_column :user, :sqreened_email, :text
|
60
|
-
# only if you use devise's :trackable
|
61
|
-
add_column :user, :current_sqreened_sign_in_ip, :text
|
62
|
-
# only if you use devise's :trackable
|
63
|
-
add_column :user, :last_sqreened_sign_in_ip, :text
|
64
|
-
end
|
65
|
-
end
|
74
|
+
export SQREEN_API_TOKEN="PASTE_YOUR_TOKEN_HERE"
|
66
75
|
```
|
67
|
-
Then run:
|
68
76
|
|
69
|
-
|
70
|
-
$ rails db:migrate
|
71
|
-
```
|
77
|
+
There are lots of ways to get environment variables into your Rails app, of course—you should follow the practices used for your particular app if they aren't set in this way.
|
72
78
|
|
73
|
-
For the automatic sqreening to work you need to provide [your API token](https://my.sqreen.io) into you devise configuration (in `config/initializers/devise.rb`):
|
74
|
-
```ruby
|
75
|
-
Devise.setup do |config|
|
76
|
-
#...
|
77
|
-
config.sqreen_api_token="TOKEN"
|
78
|
-
#...
|
79
|
-
end
|
80
|
-
```
|
81
79
|
|
82
|
-
##
|
80
|
+
## Looking at security metadata
|
83
81
|
|
84
|
-
|
82
|
+
Sign-ups and sign-ins are automatically sqreened whenever needed. [Sqreened metada](https://www.sqreen.io/developers.html) are automatically added to your model as serialized fields.
|
85
83
|
![Activeadmin Screenshor](/doc/activeadmin.png)
|
86
84
|
|
87
|
-
##
|
85
|
+
## Configuring your user Sqreening policy
|
86
|
+
|
87
|
+
Policies are implemented as predicates in your Devise configuration, `config/initializers/devise.rb`. There are two predicates, one for signing up and one for signing in. The predicates can do really anything you like, including firing off notifications, or flagging the user in some way. But the most important thing is deciding whether to block the user from completing the sign-up or sign-in action.
|
88
|
+
|
89
|
+
The arguments to the predicates are:
|
90
|
+
* `email`: Current email sqreened metadata (a Hash or nil)
|
91
|
+
* `ip`: Current ip address sqreened metadata (a Hash or nil)
|
92
|
+
* `user`: The current instance of your MODEL class trying to sign in/up.
|
88
93
|
|
89
|
-
|
94
|
+
The return value should be a boolean. If your predicate returns `true`, the action will be blocked. If your predicate returns `false`, the action will not be blocked.
|
95
|
+
|
96
|
+
The `email` hash passed to the predicate has the following structure:
|
97
|
+
|
98
|
+
* `email`: string The email address queried.
|
99
|
+
* `risk_score`: number The assessed risk that this email address is being used by a malevolent actor. Values range from 0 to 100. Anything greater than 80 is really bad and should be dropped; anything greater than about 40 is worth flagging and keeping an eye on.
|
100
|
+
* `is_email_harmful`: boolean Does the email address itself pose a direct security risk? E.g., does the email address contain embedded JavaScript?
|
101
|
+
* `is_known_attacker`: boolean Was this email address used as part of a security attack?
|
102
|
+
* `high_risk_security_events_count`: number The number of high-risk security events (e.g. SQL injection attacks) involving this email address.
|
103
|
+
* `security_events_count`: number The number of all security events (both high-risk and low-risk) involving this email address.
|
104
|
+
* `is_disposable`: boolean Does this email's domain belong to a known vendor of disposable, temporary, or anonymized email addresses?
|
105
|
+
* `is_email_malformed`: boolean Is the email malformed according to RFC 5322?
|
106
|
+
|
107
|
+
The `ip` hash passed to the predicate has the following structure:
|
108
|
+
|
109
|
+
* `ip`: string The IP address queried.
|
110
|
+
* `ip_version`: number The version of the IP address queried. Either 4 or 6.
|
111
|
+
* `risk_score`: number The assessed risk that this IP address is being used by a malevolent actor. Values range from 0 to 100. Anything greater than 80 is really bad and should be dropped; anything greater than about 40 is worth flagging and keeping an eye on.
|
112
|
+
* `is_known_attacker`: boolean Was this IP address used as part of a security attack?
|
113
|
+
* `high_risk_security_events_count`: number The number of high-risk security events (e.g. SQL injection attacks) originating from this IP address.
|
114
|
+
* `security_events_count`: number The number of all security events (both high-risk and low-risk) originating from this IP address.
|
115
|
+
* `ip_geo`: object The geographical location associated with this IP address.
|
116
|
+
* `ip_geo.latitude` number The latitude of the location.
|
117
|
+
* `ip_geo.longitude `number The longitude of the location.
|
118
|
+
* `ip_geo.country_code` string The ISO ALPHA-3 Code for the country that this location exists within.
|
119
|
+
* `is_datacenter`: boolean Does this IP address belong to a known datacenter, such as AWS or Google Cloud?
|
120
|
+
* `is_vpn`: boolean Does this IP address belong to a known VPN?
|
121
|
+
* `is_proxy`: boolean Does this IP address belong to a known proxy server?
|
122
|
+
* `is_tor`: boolean Is this IP address a known Tor exit point?
|
123
|
+
|
124
|
+
Let's suppose that we want to block all sign-ups and sign-ins over TOR:
|
90
125
|
|
91
126
|
```ruby
|
92
127
|
Devise.setup do |config|
|
93
128
|
#...
|
94
129
|
# Block signing in from TOR
|
95
130
|
config.sqreen_block_sign_in = -> (email, ip, user) {ip && ip["is_tor"] }
|
96
|
-
# Block signing up
|
97
|
-
config.sqreen_block_sign_up = -> (email, ip, user) {
|
131
|
+
# Block signing up from TOR
|
132
|
+
config.sqreen_block_sign_up = -> (email, ip, user) {ip && ip["is_tor"] }
|
98
133
|
#...
|
99
134
|
end
|
100
135
|
```
|
101
136
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
* Fork the project.
|
112
|
-
* Start a feature/bugfix branch.
|
113
|
-
* Commit and push until you are happy with your contribution.
|
114
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
115
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
137
|
+
Or perhaps you just want to look at Sqreen's pre-calculated risk score for the email address to make this determination:
|
138
|
+
```ruby
|
139
|
+
Devise.setup do |config|
|
140
|
+
#...
|
141
|
+
# Block signing up with a risky email address
|
142
|
+
config.sqreen_block_sign_up = -> (email, ip, user) {email && email["risk_score"] > 70 }
|
143
|
+
#...
|
144
|
+
end
|
145
|
+
```
|
116
146
|
|
117
|
-
|
147
|
+
The possibilities are...well, let's be honest, they're not exactly endless, but there is a great deal of flexibility in crafting these policies.
|
118
148
|
|
119
|
-
|
149
|
+
## Let us know how it works for you
|
120
150
|
|
151
|
+
So, that's about all there is to it! Having a problem? Have an idea for how we could improve this Devise plugin? [Open an issue](https://github.com/sqreen/devise_sqreener/issues/new), and let us know what we can do better.
|
@@ -63,7 +63,7 @@ module Devise
|
|
63
63
|
return false if oracle.blank? || !oracle.respond_to?(:call)
|
64
64
|
if oracle.call(current_sqreened_email,
|
65
65
|
current_sqreened_ip_address, self)
|
66
|
-
errors[:base]
|
66
|
+
errors[:base] << I18n.t(:forbidden, :scope => %i(devise registrations))
|
67
67
|
return true
|
68
68
|
end
|
69
69
|
false
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'net/http'
|
2
|
+
require 'devise_sqreener/version'
|
3
|
+
|
2
4
|
module DeviseSqreener
|
3
5
|
# sqreen an email of ip
|
4
6
|
class Sqreen
|
@@ -28,9 +30,10 @@ module DeviseSqreener
|
|
28
30
|
|
29
31
|
def sqreen(kind, value)
|
30
32
|
uri = URI(format(BASE_URL, kind, value))
|
33
|
+
user_agent = "DeviseSqreener/#{DeviseSqreener::VERSION} #{Gem::Platform.local.os}/#{Gem::Platform.local.version} Rails/#{Rails::VERSION::STRING} Ruby/#{RUBY_VERSION}"
|
31
34
|
response = Net::HTTP.start(uri.hostname, uri.port,
|
32
35
|
:use_ssl => uri.scheme == 'https') do |http|
|
33
|
-
http.request_get(uri, 'x-api-key' => sqreen_api_token.to_s)
|
36
|
+
http.request_get(uri, 'x-api-key' => sqreen_api_token.to_s, 'User-Agent' => user_agent)
|
34
37
|
end
|
35
38
|
|
36
39
|
handle_response(kind, value, response)
|
@@ -6,7 +6,13 @@ module ActiveRecord
|
|
6
6
|
source_root File.expand_path("../", __FILE__)
|
7
7
|
|
8
8
|
def copy_devise_migration
|
9
|
-
migration_template "migration.rb", "db/migrate/devise_sqreener_add_to_#{table_name}.rb"
|
9
|
+
migration_template "migration.rb", "db/migrate/devise_sqreener_add_to_#{table_name}.rb", migration_version: migration_version
|
10
|
+
end
|
11
|
+
|
12
|
+
def migration_version
|
13
|
+
if Rails::VERSION::MAJOR >= 5
|
14
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
15
|
+
end
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class DeviseSqreenerAddTo<%= table_name.camelize %> < ActiveRecord::Migration
|
1
|
+
class DeviseSqreenerAddTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
3
|
add_column :<%= table_name %>, :sqreened_email, :text
|
4
4
|
if <%= class_name %>.devise_modules.include?(:trackable)
|
data/lib/generators/devise_sqreener/{devise_enricher_generator.rb → devise_sqreener_generator.rb}
RENAMED
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise_sqreener
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benoit Larroque
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-06-
|
13
|
+
date: 2017-06-05 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description: Sqreen emails/ips that are seen by Devise through the Sqreen API, and
|
16
16
|
block bad actors from signing up to your Rails app.
|
@@ -23,6 +23,7 @@ files:
|
|
23
23
|
- LICENSE
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
|
+
- config/locales/en.yml
|
26
27
|
- lib/devise_sqreener.rb
|
27
28
|
- lib/devise_sqreener/hook.rb
|
28
29
|
- lib/devise_sqreener/model.rb
|
@@ -30,7 +31,7 @@ files:
|
|
30
31
|
- lib/devise_sqreener/version.rb
|
31
32
|
- lib/generators/active_record/devise_sqreener_generator.rb
|
32
33
|
- lib/generators/active_record/migration.rb
|
33
|
-
- lib/generators/devise_sqreener/
|
34
|
+
- lib/generators/devise_sqreener/devise_sqreener_generator.rb
|
34
35
|
homepage: https://github.com/sqreen/devise_sqreener
|
35
36
|
licenses:
|
36
37
|
- MIT
|