beskar 0.0.1 → 0.1.0
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/CHANGELOG.md +143 -0
- data/README.md +987 -21
- data/app/controllers/beskar/application_controller.rb +170 -0
- data/app/controllers/beskar/banned_ips_controller.rb +280 -0
- data/app/controllers/beskar/dashboard_controller.rb +70 -0
- data/app/controllers/beskar/security_events_controller.rb +182 -0
- data/app/controllers/concerns/beskar/controllers/security_tracking.rb +70 -0
- data/app/models/beskar/banned_ip.rb +193 -0
- data/app/models/beskar/security_event.rb +64 -0
- data/app/services/beskar/banned_ip_manager.rb +78 -0
- data/app/views/beskar/banned_ips/edit.html.erb +259 -0
- data/app/views/beskar/banned_ips/index.html.erb +361 -0
- data/app/views/beskar/banned_ips/new.html.erb +310 -0
- data/app/views/beskar/banned_ips/show.html.erb +310 -0
- data/app/views/beskar/dashboard/index.html.erb +280 -0
- data/app/views/beskar/security_events/index.html.erb +309 -0
- data/app/views/beskar/security_events/show.html.erb +307 -0
- data/app/views/layouts/beskar/application.html.erb +647 -5
- data/config/locales/en.yml +10 -0
- data/config/routes.rb +41 -0
- data/db/migrate/20251016000001_create_beskar_security_events.rb +25 -0
- data/db/migrate/20251016000002_create_beskar_banned_ips.rb +23 -0
- data/lib/beskar/configuration.rb +214 -0
- data/lib/beskar/engine.rb +105 -0
- data/lib/beskar/logger.rb +293 -0
- data/lib/beskar/middleware/request_analyzer.rb +305 -0
- data/lib/beskar/middleware.rb +4 -0
- data/lib/beskar/models/security_trackable.rb +25 -0
- data/lib/beskar/models/security_trackable_authenticable.rb +167 -0
- data/lib/beskar/models/security_trackable_devise.rb +82 -0
- data/lib/beskar/models/security_trackable_generic.rb +355 -0
- data/lib/beskar/services/account_locker.rb +263 -0
- data/lib/beskar/services/device_detector.rb +250 -0
- data/lib/beskar/services/geolocation_service.rb +392 -0
- data/lib/beskar/services/ip_whitelist.rb +113 -0
- data/lib/beskar/services/rate_limiter.rb +257 -0
- data/lib/beskar/services/waf.rb +551 -0
- data/lib/beskar/version.rb +1 -1
- data/lib/beskar.rb +32 -1
- data/lib/generators/beskar/install/install_generator.rb +158 -0
- data/lib/generators/beskar/install/templates/initializer.rb.tt +177 -0
- data/lib/tasks/beskar_tasks.rake +121 -4
- metadata +138 -5
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'rails/generators/migration'
|
|
5
|
+
|
|
6
|
+
module Beskar
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
include Rails::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path('templates', __dir__)
|
|
12
|
+
|
|
13
|
+
desc "Creates a Beskar initializer and runs migrations"
|
|
14
|
+
|
|
15
|
+
def self.next_migration_number(path)
|
|
16
|
+
if @prev_migration_nr
|
|
17
|
+
@prev_migration_nr += 1
|
|
18
|
+
else
|
|
19
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
|
20
|
+
end
|
|
21
|
+
@prev_migration_nr.to_s
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def copy_initializer
|
|
25
|
+
template "initializer.rb.tt", "config/initializers/beskar.rb"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def mount_engine
|
|
29
|
+
route_text = "mount Beskar::Engine => '/beskar'"
|
|
30
|
+
|
|
31
|
+
# Check if the route already exists
|
|
32
|
+
if File.read("config/routes.rb").include?(route_text)
|
|
33
|
+
say "Route already mounted, skipping...", :yellow
|
|
34
|
+
else
|
|
35
|
+
route route_text
|
|
36
|
+
say "Mounted Beskar engine at /beskar", :green
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def copy_migrations
|
|
41
|
+
# Copy migrations from the engine to the host app
|
|
42
|
+
migration_source = File.expand_path("../../../../../db/migrate", __dir__)
|
|
43
|
+
|
|
44
|
+
if Dir.exist?(migration_source)
|
|
45
|
+
Dir.glob("#{migration_source}/*.rb").each do |migration|
|
|
46
|
+
migration_name = File.basename(migration).sub(/^\d+_/, '')
|
|
47
|
+
|
|
48
|
+
# Check if migration already exists
|
|
49
|
+
if migration_already_exists?(migration_name)
|
|
50
|
+
say "Migration #{migration_name} already exists, skipping...", :yellow
|
|
51
|
+
else
|
|
52
|
+
migration_template migration, "db/migrate/#{migration_name}"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
say "Migrations copied. Run 'rails db:migrate' to create the tables.", :green
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# CSS Zero is no longer required - styles are embedded in the dashboard
|
|
61
|
+
# def install_css_zero
|
|
62
|
+
# # Removed - dashboard now uses embedded styles
|
|
63
|
+
# end
|
|
64
|
+
|
|
65
|
+
def show_readme
|
|
66
|
+
readme_content = <<~README
|
|
67
|
+
|
|
68
|
+
===============================================================================
|
|
69
|
+
🛡️ Beskar Installation Complete!
|
|
70
|
+
===============================================================================
|
|
71
|
+
|
|
72
|
+
Next steps:
|
|
73
|
+
|
|
74
|
+
1. Run migrations to create the security tables:
|
|
75
|
+
$ rails db:migrate
|
|
76
|
+
|
|
77
|
+
2. Configure authentication for the dashboard in config/initializers/beskar.rb
|
|
78
|
+
|
|
79
|
+
For Devise users:
|
|
80
|
+
config.authenticate_admin = proc do
|
|
81
|
+
authenticate_admin!
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
For custom authentication:
|
|
85
|
+
config.authenticate_admin = proc do
|
|
86
|
+
redirect_to main_app.root_path unless current_user&.admin?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
3. Add Beskar concerns to your User model (or authentication model):
|
|
90
|
+
|
|
91
|
+
class User < ApplicationRecord
|
|
92
|
+
include Beskar::Models::SecurityTrackable
|
|
93
|
+
|
|
94
|
+
# For Devise users, also add:
|
|
95
|
+
include Beskar::Models::SecurityTrackableDevise
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
4. Access the security dashboard at:
|
|
99
|
+
http://localhost:3000/beskar
|
|
100
|
+
|
|
101
|
+
5. Optional: Configure additional settings in config/initializers/beskar.rb
|
|
102
|
+
- IP whitelist
|
|
103
|
+
- WAF rules
|
|
104
|
+
- Rate limiting
|
|
105
|
+
- Geolocation
|
|
106
|
+
- Risk-based locking
|
|
107
|
+
|
|
108
|
+
===============================================================================
|
|
109
|
+
📚 Documentation
|
|
110
|
+
===============================================================================
|
|
111
|
+
|
|
112
|
+
Dashboard Guide: https://github.com/humadroid-io/beskar/blob/main/DASHBOARD.md
|
|
113
|
+
Configuration: https://github.com/humadroid-io/beskar/blob/main/README.md
|
|
114
|
+
|
|
115
|
+
===============================================================================
|
|
116
|
+
⚠️ Important for Production
|
|
117
|
+
===============================================================================
|
|
118
|
+
|
|
119
|
+
1. ALWAYS configure authentication for the dashboard
|
|
120
|
+
2. Set monitor_only = false when ready to block threats
|
|
121
|
+
3. Configure your IP whitelist to prevent locking yourself out
|
|
122
|
+
4. Set up database indexes for large-scale deployments:
|
|
123
|
+
|
|
124
|
+
$ rails generate beskar:indexes
|
|
125
|
+
$ rails db:migrate
|
|
126
|
+
|
|
127
|
+
===============================================================================
|
|
128
|
+
💡 Quick Tips
|
|
129
|
+
===============================================================================
|
|
130
|
+
|
|
131
|
+
- Start with monitor_only = true to observe without blocking
|
|
132
|
+
- Use the dashboard to review security events before enabling blocking
|
|
133
|
+
- Configure email notifications for high-risk events
|
|
134
|
+
- Export security data regularly for analysis
|
|
135
|
+
- Consider implementing custom risk scoring for your use case
|
|
136
|
+
|
|
137
|
+
===============================================================================
|
|
138
|
+
|
|
139
|
+
README
|
|
140
|
+
|
|
141
|
+
say readme_content, :green
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
def migration_already_exists?(migration_name)
|
|
147
|
+
Dir.glob("db/migrate/*_#{migration_name}").any?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def migration_template(source, destination)
|
|
151
|
+
migration_number = self.class.next_migration_number(nil)
|
|
152
|
+
file_name = "#{migration_number}_#{destination}"
|
|
153
|
+
|
|
154
|
+
copy_file source, file_name
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Beskar.configure do |config|
|
|
4
|
+
# ============================================================================
|
|
5
|
+
# DASHBOARD AUTHENTICATION (REQUIRED)
|
|
6
|
+
# ============================================================================
|
|
7
|
+
# Configure how to authenticate access to the Beskar security dashboard.
|
|
8
|
+
# This is REQUIRED for all environments.
|
|
9
|
+
#
|
|
10
|
+
# The authenticate_admin callback receives the request object and is executed
|
|
11
|
+
# in the controller context, giving you access to all controller methods
|
|
12
|
+
# (cookies, session, authenticate_or_request_with_http_basic, etc.).
|
|
13
|
+
# The block should return truthy value to allow access, falsey to deny.
|
|
14
|
+
|
|
15
|
+
# Option 1: Using Devise with admin role (recommended for production)
|
|
16
|
+
# config.authenticate_admin = ->(request) do
|
|
17
|
+
# user = request.env['warden']&.authenticate(scope: :user)
|
|
18
|
+
# user&.admin?
|
|
19
|
+
# end
|
|
20
|
+
|
|
21
|
+
# Option 2: HTTP Basic Authentication (uses controller method)
|
|
22
|
+
# config.authenticate_admin = ->(request) do
|
|
23
|
+
# authenticate_or_request_with_http_basic("Beskar Admin") do |username, password|
|
|
24
|
+
# username == ENV['BESKAR_ADMIN_USERNAME'] &&
|
|
25
|
+
# password == ENV['BESKAR_ADMIN_PASSWORD']
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
|
|
29
|
+
# Option 3: Token-based authentication
|
|
30
|
+
# config.authenticate_admin = ->(request) do
|
|
31
|
+
# request.headers['Authorization'] == "Bearer #{ENV['BESKAR_ADMIN_TOKEN']}"
|
|
32
|
+
# end
|
|
33
|
+
|
|
34
|
+
# Option 4: Cookie-based authentication (uses controller cookies)
|
|
35
|
+
# config.authenticate_admin = ->(request) do
|
|
36
|
+
# cookies.signed[:admin_token] == ENV['BESKAR_ADMIN_TOKEN']
|
|
37
|
+
# end
|
|
38
|
+
|
|
39
|
+
# Option 5: Using CanCanCan (uses controller method)
|
|
40
|
+
# config.authenticate_admin = ->(request) do
|
|
41
|
+
# authorize! :manage, :beskar_dashboard
|
|
42
|
+
# end
|
|
43
|
+
|
|
44
|
+
# Option 6: Using Pundit (uses controller method)
|
|
45
|
+
# config.authenticate_admin = ->(request) do
|
|
46
|
+
# authorize :beskar_dashboard, :access?
|
|
47
|
+
# end
|
|
48
|
+
|
|
49
|
+
# Option 7: For development/testing ONLY (NOT for production!)
|
|
50
|
+
# config.authenticate_admin = ->(request) do
|
|
51
|
+
# Rails.env.development? || Rails.env.test?
|
|
52
|
+
# end
|
|
53
|
+
|
|
54
|
+
# ============================================================================
|
|
55
|
+
# MONITOR-ONLY MODE
|
|
56
|
+
# ============================================================================
|
|
57
|
+
# When enabled, Beskar will log all security events but won't actually block
|
|
58
|
+
# any requests. Useful for testing or initial deployment.
|
|
59
|
+
config.monitor_only = <%= Rails.env.development? ? 'true' : 'false' %>
|
|
60
|
+
|
|
61
|
+
# ============================================================================
|
|
62
|
+
# IP WHITELIST
|
|
63
|
+
# ============================================================================
|
|
64
|
+
# IPs that should never be blocked (your office, monitoring services, etc.)
|
|
65
|
+
config.ip_whitelist = [
|
|
66
|
+
# '192.168.1.0/24', # Local network
|
|
67
|
+
# '10.0.0.0/8', # Private network
|
|
68
|
+
# '127.0.0.1', # Localhost
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
# ============================================================================
|
|
72
|
+
# WAF (WEB APPLICATION FIREWALL) - Score-Based Blocking
|
|
73
|
+
# ============================================================================
|
|
74
|
+
# Enable WAF to protect against common attacks and vulnerability scans.
|
|
75
|
+
# Uses score-based blocking with exponential decay for intelligent threat detection.
|
|
76
|
+
config.waf[:enabled] = true
|
|
77
|
+
|
|
78
|
+
# Optionally customize WAF settings (these are the defaults):
|
|
79
|
+
# config.waf[:auto_block] = true # Automatically block IPs after threshold
|
|
80
|
+
# config.waf[:score_threshold] = 150 # Cumulative risk score before blocking
|
|
81
|
+
# config.waf[:violation_window] = 6.hours # Maximum time window to track violations
|
|
82
|
+
# config.waf[:block_durations] = [1.hour, 6.hours, 24.hours, 7.days] # Escalating durations
|
|
83
|
+
# config.waf[:permanent_block_after] = 500 # Permanent block when cumulative score reaches this
|
|
84
|
+
# config.waf[:create_security_events] = true # Create SecurityEvent records
|
|
85
|
+
#
|
|
86
|
+
# === Exponential Decay Configuration ===
|
|
87
|
+
# Violations decay over time based on severity (reduces false positives)
|
|
88
|
+
# config.waf[:decay_enabled] = true
|
|
89
|
+
# config.waf[:decay_rates] = { # Half-life in minutes
|
|
90
|
+
# critical: 360, # 6 hour half-life (config files, path traversal)
|
|
91
|
+
# high: 120, # 2 hour half-life (WordPress, PHP admin scans)
|
|
92
|
+
# medium: 45, # 45 minute half-life (unknown formats)
|
|
93
|
+
# low: 15 # 15 minute half-life (RecordNotFound/404s)
|
|
94
|
+
# }
|
|
95
|
+
# config.waf[:max_violations_tracked] = 50 # Maximum violations to track per IP
|
|
96
|
+
#
|
|
97
|
+
# === RecordNotFound Exclusions ===
|
|
98
|
+
# Exclude legitimate 404-prone paths from triggering violations
|
|
99
|
+
# config.waf[:record_not_found_exclusions] = [
|
|
100
|
+
# %r{/posts/.*}, # Blog posts with slugs
|
|
101
|
+
# %r{/products/[\w-]+}, # Product URLs with slugs
|
|
102
|
+
# %r{/public/.*} # Public content
|
|
103
|
+
# ]
|
|
104
|
+
#
|
|
105
|
+
# === Pre-configured Profiles ===
|
|
106
|
+
# See WAF_CONFIGURATION_PROFILES.md for complete profile examples:
|
|
107
|
+
# - STRICT: score_threshold = 100 (high-security)
|
|
108
|
+
# - BALANCED: score_threshold = 150 (recommended default)
|
|
109
|
+
# - PERMISSIVE: score_threshold = 200 (high-traffic sites)
|
|
110
|
+
|
|
111
|
+
# ============================================================================
|
|
112
|
+
# SECURITY TRACKING
|
|
113
|
+
# ============================================================================
|
|
114
|
+
# Security tracking is enabled by default. To disable or customize:
|
|
115
|
+
# config.security_tracking[:enabled] = false
|
|
116
|
+
# config.security_tracking[:track_successful_logins] = true
|
|
117
|
+
# config.security_tracking[:track_failed_logins] = true
|
|
118
|
+
# config.security_tracking[:auto_analyze_patterns] = true
|
|
119
|
+
|
|
120
|
+
# ============================================================================
|
|
121
|
+
# RATE LIMITING
|
|
122
|
+
# ============================================================================
|
|
123
|
+
# Rate limiting is configured by default. To customize:
|
|
124
|
+
# config.rate_limiting[:ip_attempts][:limit] = 10
|
|
125
|
+
# config.rate_limiting[:ip_attempts][:period] = 1.hour
|
|
126
|
+
# config.rate_limiting[:ip_attempts][:exponential_backoff] = true
|
|
127
|
+
#
|
|
128
|
+
# config.rate_limiting[:account_attempts][:limit] = 5
|
|
129
|
+
# config.rate_limiting[:account_attempts][:period] = 15.minutes
|
|
130
|
+
# config.rate_limiting[:account_attempts][:exponential_backoff] = true
|
|
131
|
+
#
|
|
132
|
+
# config.rate_limiting[:global_attempts][:limit] = 100
|
|
133
|
+
# config.rate_limiting[:global_attempts][:period] = 1.minute
|
|
134
|
+
# config.rate_limiting[:global_attempts][:exponential_backoff] = false
|
|
135
|
+
|
|
136
|
+
# ============================================================================
|
|
137
|
+
# RISK-BASED ACCOUNT LOCKING
|
|
138
|
+
# ============================================================================
|
|
139
|
+
# Risk-based locking is disabled by default. To enable:
|
|
140
|
+
# config.risk_based_locking[:enabled] = true
|
|
141
|
+
# config.risk_based_locking[:immediate_signout] = false # Sign out users immediately when locked
|
|
142
|
+
# config.risk_based_locking[:risk_threshold] = 75 # Risk score threshold for locking
|
|
143
|
+
# config.risk_based_locking[:auto_unlock_time] = 1.hour # How long to lock the account
|
|
144
|
+
# config.risk_based_locking[:notify_user] = true # Notify user on lock
|
|
145
|
+
# config.risk_based_locking[:log_lock_events] = true # Log lock events
|
|
146
|
+
|
|
147
|
+
# ============================================================================
|
|
148
|
+
# GEOLOCATION
|
|
149
|
+
# ============================================================================
|
|
150
|
+
# Geolocation uses a mock provider by default. To use MaxMind:
|
|
151
|
+
# 1. Download GeoLite2-City database from maxmind.com
|
|
152
|
+
# 2. Place it in config/GeoLite2-City.mmdb
|
|
153
|
+
# 3. Configure:
|
|
154
|
+
# config.geolocation[:provider] = :maxmind
|
|
155
|
+
# config.geolocation[:maxmind_city_db_path] = Rails.root.join('config', 'GeoLite2-City.mmdb').to_s
|
|
156
|
+
# config.geolocation[:cache_ttl] = 4.hours
|
|
157
|
+
|
|
158
|
+
# ============================================================================
|
|
159
|
+
# AUTHENTICATION MODELS
|
|
160
|
+
# ============================================================================
|
|
161
|
+
# Authentication models are auto-detected by default. To customize:
|
|
162
|
+
# config.authentication_models[:auto_detect] = false # Disable auto-detection
|
|
163
|
+
# config.authentication_models[:devise] = [:user, :admin]
|
|
164
|
+
# config.authentication_models[:rails_auth] = [:customer]
|
|
165
|
+
|
|
166
|
+
# ============================================================================
|
|
167
|
+
# EMERGENCY PASSWORD RESET
|
|
168
|
+
# ============================================================================
|
|
169
|
+
# Emergency password reset is disabled by default. To enable:
|
|
170
|
+
# config.emergency_password_reset[:enabled] = true
|
|
171
|
+
# config.emergency_password_reset[:impossible_travel_threshold] = 3
|
|
172
|
+
# config.emergency_password_reset[:suspicious_device_threshold] = 5
|
|
173
|
+
# config.emergency_password_reset[:total_locks_threshold] = 5
|
|
174
|
+
# config.emergency_password_reset[:send_notification] = true
|
|
175
|
+
# config.emergency_password_reset[:notify_security_team] = true
|
|
176
|
+
# config.emergency_password_reset[:require_manual_unlock] = false
|
|
177
|
+
end
|
data/lib/tasks/beskar_tasks.rake
CHANGED
|
@@ -1,4 +1,121 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :beskar do
|
|
4
|
+
desc "Install Beskar: copy migrations and create initializer"
|
|
5
|
+
task install: :environment do
|
|
6
|
+
puts "=" * 80
|
|
7
|
+
puts "Installing Beskar Security..."
|
|
8
|
+
puts "=" * 80
|
|
9
|
+
puts
|
|
10
|
+
|
|
11
|
+
# Copy migrations
|
|
12
|
+
puts "📦 Copying migrations..."
|
|
13
|
+
begin
|
|
14
|
+
Rake::Task["beskar:install:migrations"].invoke
|
|
15
|
+
rescue RuntimeError
|
|
16
|
+
# In development/test within the gem, this task might not exist
|
|
17
|
+
# In a real app using the gem, it will work fine
|
|
18
|
+
puts " (Skipping migration copy in gem development mode)"
|
|
19
|
+
end
|
|
20
|
+
puts "✓ Migrations ready"
|
|
21
|
+
puts
|
|
22
|
+
|
|
23
|
+
# Create initializer
|
|
24
|
+
initializer_path = Rails.root.join("config/initializers/beskar.rb")
|
|
25
|
+
|
|
26
|
+
if File.exist?(initializer_path)
|
|
27
|
+
puts "⚠️ Initializer already exists at config/initializers/beskar.rb"
|
|
28
|
+
print " Overwrite? (y/N): "
|
|
29
|
+
response = $stdin.gets.chomp.downcase
|
|
30
|
+
|
|
31
|
+
unless response == 'y' || response == 'yes'
|
|
32
|
+
puts " Skipping initializer creation"
|
|
33
|
+
puts
|
|
34
|
+
next_steps
|
|
35
|
+
exit
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
puts "📝 Creating initializer..."
|
|
40
|
+
template_path = File.expand_path("../generators/beskar/install/templates/initializer.rb.tt", __dir__)
|
|
41
|
+
|
|
42
|
+
# Read the template and process ERB (Rails will be available in the rake task context)
|
|
43
|
+
template_content = File.read(template_path)
|
|
44
|
+
erb = ERB.new(template_content, trim_mode: '-')
|
|
45
|
+
|
|
46
|
+
# Evaluate the ERB template in a context where Rails is available
|
|
47
|
+
processed_content = erb.result(binding)
|
|
48
|
+
|
|
49
|
+
# Write the processed initializer
|
|
50
|
+
File.write(initializer_path, processed_content)
|
|
51
|
+
puts "✓ Created config/initializers/beskar.rb"
|
|
52
|
+
puts
|
|
53
|
+
|
|
54
|
+
next_steps
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def next_steps
|
|
58
|
+
puts "=" * 80
|
|
59
|
+
puts "Beskar Security has been installed!"
|
|
60
|
+
puts "=" * 80
|
|
61
|
+
puts
|
|
62
|
+
puts "Next steps:"
|
|
63
|
+
puts
|
|
64
|
+
puts "1. Run migrations to create the security tables:"
|
|
65
|
+
puts
|
|
66
|
+
puts " bin/rails db:migrate"
|
|
67
|
+
puts
|
|
68
|
+
puts "2. Add the SecurityTrackable concern to your User model:"
|
|
69
|
+
puts
|
|
70
|
+
puts " # app/models/user.rb"
|
|
71
|
+
puts " class User < ApplicationRecord"
|
|
72
|
+
puts " include Beskar::SecurityTrackable"
|
|
73
|
+
puts " "
|
|
74
|
+
puts " devise :database_authenticatable, :registerable,"
|
|
75
|
+
puts " :recoverable, :rememberable, :validatable"
|
|
76
|
+
puts " # ... rest of your Devise modules"
|
|
77
|
+
puts " end"
|
|
78
|
+
puts
|
|
79
|
+
puts "3. Review the configuration file:"
|
|
80
|
+
puts
|
|
81
|
+
puts " config/initializers/beskar.rb"
|
|
82
|
+
puts
|
|
83
|
+
puts " By default, WAF is enabled in MONITOR-ONLY MODE. This means:"
|
|
84
|
+
puts " - Vulnerability scans are detected and logged"
|
|
85
|
+
puts " - No requests are blocked yet"
|
|
86
|
+
puts " - Security events are created for analysis"
|
|
87
|
+
puts
|
|
88
|
+
puts "4. Monitor WAF activity (recommended for 24-48 hours):"
|
|
89
|
+
puts
|
|
90
|
+
puts " # View all WAF logs"
|
|
91
|
+
puts " tail -f log/production.log | grep \"Beskar::WAF\""
|
|
92
|
+
puts " "
|
|
93
|
+
puts " # Check what would be blocked"
|
|
94
|
+
puts " rails console"
|
|
95
|
+
puts " > Beskar::SecurityEvent.where(event_type: 'waf_violation')"
|
|
96
|
+
puts " .where(\"metadata->>'would_be_blocked' = ?\", 'true').count"
|
|
97
|
+
puts
|
|
98
|
+
puts "5. When ready to enable blocking:"
|
|
99
|
+
puts
|
|
100
|
+
puts " # config/initializers/beskar.rb"
|
|
101
|
+
puts " config.waf = {"
|
|
102
|
+
puts " enabled: true,"
|
|
103
|
+
puts " monitor_only: false, # <-- Change this to false"
|
|
104
|
+
puts " # ... rest of config"
|
|
105
|
+
puts " }"
|
|
106
|
+
puts
|
|
107
|
+
puts "6. Optional: Add IP whitelist for trusted sources:"
|
|
108
|
+
puts
|
|
109
|
+
puts " # config/initializers/beskar.rb"
|
|
110
|
+
puts " config.ip_whitelist = ["
|
|
111
|
+
puts " \"YOUR_OFFICE_IP\","
|
|
112
|
+
puts " \"YOUR_MONITORING_SERVICE_IP\""
|
|
113
|
+
puts " ]"
|
|
114
|
+
puts
|
|
115
|
+
puts "=" * 80
|
|
116
|
+
puts "Documentation:"
|
|
117
|
+
puts " - README: https://github.com/humadroid-io/beskar"
|
|
118
|
+
puts " - WAF Monitor Mode: See MONITOR_ONLY_MODE.md"
|
|
119
|
+
puts "=" * 80
|
|
120
|
+
end
|
|
121
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: beskar
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Maciej Litwiniuk
|
|
@@ -23,6 +23,104 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: 8.0.0
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: csv
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '3.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: maxminddb
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0.1'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0.1'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: debug
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: devise
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: factory_bot_rails
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: mocha
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: ostruct
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
26
124
|
description: |-
|
|
27
125
|
Rails Security Shield is a comprehensive, Rails-native security engine designed to provide multi-layered protection for modern web applications. It actively defends against common threats by integrating a powerful Web Application Firewall (WAF) to block attacks like SQLi and XSS, an advanced bot detection system using JavaScript challenges and honeypots, and robust account takeover prevention to stop brute-force and credential stuffing attacks.
|
|
28
126
|
|
|
@@ -33,27 +131,62 @@ executables: []
|
|
|
33
131
|
extensions: []
|
|
34
132
|
extra_rdoc_files: []
|
|
35
133
|
files:
|
|
134
|
+
- CHANGELOG.md
|
|
36
135
|
- MIT-LICENSE
|
|
37
136
|
- README.md
|
|
38
137
|
- Rakefile
|
|
39
138
|
- app/assets/stylesheets/beskar/application.css
|
|
40
139
|
- app/controllers/beskar/application_controller.rb
|
|
140
|
+
- app/controllers/beskar/banned_ips_controller.rb
|
|
141
|
+
- app/controllers/beskar/dashboard_controller.rb
|
|
142
|
+
- app/controllers/beskar/security_events_controller.rb
|
|
143
|
+
- app/controllers/concerns/beskar/controllers/security_tracking.rb
|
|
41
144
|
- app/helpers/beskar/application_helper.rb
|
|
42
145
|
- app/jobs/beskar/application_job.rb
|
|
43
146
|
- app/mailers/beskar/application_mailer.rb
|
|
44
147
|
- app/models/beskar/application_record.rb
|
|
148
|
+
- app/models/beskar/banned_ip.rb
|
|
149
|
+
- app/models/beskar/security_event.rb
|
|
150
|
+
- app/services/beskar/banned_ip_manager.rb
|
|
151
|
+
- app/views/beskar/banned_ips/edit.html.erb
|
|
152
|
+
- app/views/beskar/banned_ips/index.html.erb
|
|
153
|
+
- app/views/beskar/banned_ips/new.html.erb
|
|
154
|
+
- app/views/beskar/banned_ips/show.html.erb
|
|
155
|
+
- app/views/beskar/dashboard/index.html.erb
|
|
156
|
+
- app/views/beskar/security_events/index.html.erb
|
|
157
|
+
- app/views/beskar/security_events/show.html.erb
|
|
45
158
|
- app/views/layouts/beskar/application.html.erb
|
|
159
|
+
- config/locales/en.yml
|
|
46
160
|
- config/routes.rb
|
|
161
|
+
- db/migrate/20251016000001_create_beskar_security_events.rb
|
|
162
|
+
- db/migrate/20251016000002_create_beskar_banned_ips.rb
|
|
47
163
|
- lib/beskar.rb
|
|
164
|
+
- lib/beskar/configuration.rb
|
|
48
165
|
- lib/beskar/engine.rb
|
|
166
|
+
- lib/beskar/logger.rb
|
|
167
|
+
- lib/beskar/middleware.rb
|
|
168
|
+
- lib/beskar/middleware/request_analyzer.rb
|
|
169
|
+
- lib/beskar/models/security_trackable.rb
|
|
170
|
+
- lib/beskar/models/security_trackable_authenticable.rb
|
|
171
|
+
- lib/beskar/models/security_trackable_devise.rb
|
|
172
|
+
- lib/beskar/models/security_trackable_generic.rb
|
|
173
|
+
- lib/beskar/services/account_locker.rb
|
|
174
|
+
- lib/beskar/services/device_detector.rb
|
|
175
|
+
- lib/beskar/services/geolocation_service.rb
|
|
176
|
+
- lib/beskar/services/ip_whitelist.rb
|
|
177
|
+
- lib/beskar/services/rate_limiter.rb
|
|
178
|
+
- lib/beskar/services/waf.rb
|
|
49
179
|
- lib/beskar/version.rb
|
|
180
|
+
- lib/generators/beskar/install/install_generator.rb
|
|
181
|
+
- lib/generators/beskar/install/templates/initializer.rb.tt
|
|
50
182
|
- lib/tasks/beskar_tasks.rake
|
|
51
|
-
homepage: https://humadroid.io/
|
|
183
|
+
homepage: https://humadroid.io/beskar
|
|
52
184
|
licenses:
|
|
53
185
|
- MIT
|
|
54
186
|
metadata:
|
|
55
|
-
homepage_uri: https://humadroid.io/
|
|
56
|
-
source_code_uri: https://github.com/
|
|
187
|
+
homepage_uri: https://humadroid.io/beskar
|
|
188
|
+
source_code_uri: https://github.com/humadroid-io/beskar
|
|
189
|
+
changelog_uri: https://github.com/humadroid-io/beskar/blob/master/CHANGELOG.md
|
|
57
190
|
rdoc_options: []
|
|
58
191
|
require_paths:
|
|
59
192
|
- lib
|
|
@@ -68,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
68
201
|
- !ruby/object:Gem::Version
|
|
69
202
|
version: '0'
|
|
70
203
|
requirements: []
|
|
71
|
-
rubygems_version: 3.
|
|
204
|
+
rubygems_version: 3.6.9
|
|
72
205
|
specification_version: 4
|
|
73
206
|
summary: An all-in-one security engine for Rails providing WAF, bot detection, and
|
|
74
207
|
account takeover prevention.
|