wafris 1.1.11 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2fcb2f6f87a3f5fe3f89091437cad264aa10b8a8e0440ab6568e172674fc9a7
4
- data.tar.gz: 1713ee535af2200d1c8b9b0512456c2a96544942e552fbe487a77690d66ac262
3
+ metadata.gz: f0dfe47e533d91f974d391af755f1bd8e148808cbfe86dd6755b839201282b47
4
+ data.tar.gz: bd7135922d96fa7789cc65dbd47635c4b1e84a4e7b27a6b4dde5a1a00cc15ac8
5
5
  SHA512:
6
- metadata.gz: 0312e05a8cf9687dd222263a75a3fcec4590bdd325b3d3f01d80ed211c6810b99bcaa9cfd1b682767f6cba9ba7f97240f7faf6d78d549a7cc03df4d9c40fad68
7
- data.tar.gz: 5e897f2ea32786c2b82e39f2f5b9385bd862b255294f92e59f405a8327d16e96efeb6d38194ba0490b8b9020e22931dae06c7d28112e7bd71efc456b4841ccc8
6
+ metadata.gz: 0c1e66690ca97e6f9a9349f1960f92f5376175660bebc9a172eabe849af6806d4c5f278f1765a22b36ce75797a757bf9cb3719a58446aaa5fa8fe0356c348cf0
7
+ data.tar.gz: 35a3e86f1f3c63ec38c3d67adbfb952fa89a062dad78450bfd365f45c1a1607f689e104e2c7ef6faac3a00461e07022d041e5d2f667396ad81baa3af30be8acf
@@ -1,56 +1,140 @@
1
- # frozen_string_literal: true
2
1
 
3
2
  require_relative 'version'
4
3
 
5
4
  module Wafris
6
5
  class Configuration
7
- attr_accessor :redis
8
- attr_accessor :redis_pool_size
9
- attr_accessor :maxmemory
10
- attr_accessor :quiet_mode
6
+
7
+ attr_accessor :api_key
8
+ attr_accessor :db_file_path
9
+ attr_accessor :db_file_name
10
+ attr_accessor :downsync_custom_rules_interval
11
+ attr_accessor :downsync_data_subscriptions_interval
12
+ attr_accessor :downsync_url
13
+ attr_accessor :upsync_url
14
+ attr_accessor :upsync_interval
15
+ attr_accessor :upsync_queue_limit
16
+ attr_accessor :upsync_status
17
+ attr_accessor :upsync_queue
18
+ attr_accessor :local_only
19
+ attr_accessor :last_upsync_timestamp
20
+ attr_accessor :max_body_size_mb
21
+ attr_accessor :rate_limiters
11
22
 
12
23
  def initialize
13
- @redis_pool_size = 20
14
- @maxmemory = 25
15
- @quiet_mode = false
16
- end
17
24
 
18
- def connection_pool
19
- @connection_pool ||=
20
- ConnectionPool.new(size: redis_pool_size) { redis }
21
- end
25
+ # API Key - Required
26
+ if ENV['WAFRIS_API_KEY']
27
+ @api_key = ENV['WAFRIS_API_KEY']
28
+ else
29
+ unless @api_key
30
+ LogSuppressor.puts_log("Firewall disabled as neither local only or API key set")
31
+ end
32
+ end
22
33
 
23
- def create_settings
24
- redis.hset('waf-settings',
25
- 'version', Wafris::VERSION,
26
- 'client', 'ruby',
27
- 'maxmemory', @maxmemory)
28
- LogSuppressor.puts_log(
29
- "[Wafris] firewall enabled. Connected to Redis on #{redis.connection[:host]}. Ready to process requests. Set rules at: https://wafris.org/hub"
30
- ) unless @quiet_mode
31
- end
34
+ # DB FILE PATH LOCATION - Optional
35
+ if ENV['WAFRIS_DB_FILE_PATH']
36
+ @db_file_path = ENV['WAFRIS_DB_FILE_PATH']
37
+ else
38
+ #@db_file_path = Rails.root.join('tmp', 'wafris').to_s
39
+ @db_file_path = './tmp/wafris'
40
+ end
32
41
 
33
- def core_sha
34
- @core_sha ||= redis.script(:load, wafris_core)
35
- end
42
+ # Ensure that the db_file_path exists
43
+ unless File.directory?(@db_file_path)
44
+ LogSuppressor.puts_log("DB File Path does not exist - creating it now.")
45
+ FileUtils.mkdir_p(@db_file_path) unless File.exist?(@db_file_path)
46
+ end
47
+
48
+ # DB FILE NAME - For local
49
+ if ENV['WAFRIS_DB_FILE_NAME']
50
+ @db_file_name = ENV['WAFRIS_DB_FILE_NAME']
51
+ else
52
+ @db_file_name = 'wafris.db'
53
+ end
54
+
55
+ # DOWNSYNC
56
+ # Custom Rules are checked often (default 1 minute) - Optional
57
+ if ENV['WAFRIS_DOWNSYNC_CUSTOM_RULES_INTERVAL']
58
+ @downsync_custom_rules_interval = ENV['WAFRIS_DOWNSYNC_CUSTOM_RULES_INTERVAL'].to_i
59
+ else
60
+ @downsync_custom_rules_interval = 60
61
+ end
62
+
63
+ # Data Subscriptions are checked rarely (default 1 day) - Optional
64
+ if ENV['WAFRIS_DOWNSYNC_DATA_SUBSCRIPTIONS_INTERVAL']
65
+ @downsync_data_subscriptions_interval = ENV['WAFRIS_DOWNSYNC_DATA_SUBSCRIPTIONS_INTERVAL'].to_i
66
+ else
67
+ @downsync_data_subscriptions_interval = 60
68
+ end
69
+
70
+ # Set Downsync URL - Optional
71
+ # Used for both DataSubscription and CustomRules
72
+ if ENV['WAFRIS_DOWNSYNC_URL']
73
+ @downsync_url = ENV['WAFRIS_DOWNSYNC_URL']
74
+ else
75
+ @downsync_url = 'https://distributor.wafris.org/v2/downsync'
76
+ end
77
+
78
+ # UPSYNC - Optional
79
+ # Set Upsync URL
80
+ if ENV['WAFRIS_UPSYNC_URL']
81
+ @upsync_url = ENV['WAFRIS_UPSYNC_URL']
82
+ else
83
+ @upsync_url = 'https://collector.wafris.org/v2/upsync'
84
+ end
85
+
86
+ # Set Upsync Interval - Optional
87
+ if ENV['WAFRIS_UPSYNC_INTERVAL']
88
+ @upsync_interval = ENV['WAFRIS_UPSYNC_INTERVAL'].to_i
89
+ else
90
+ @upsync_interval = 10
91
+ end
92
+
93
+ # Set Upsync Queued Request Limit - Optional
94
+ if ENV['WAFRIS_UPSYNC_QUEUE_LIMIT']
95
+ @upsync_queue_limit = ENV['WAFRIS_UPSYNC_QUEUE_LIMIT'].to_i
96
+ else
97
+ @upsync_queue_limit = 250
98
+ end
99
+
100
+ # Set Maximium Body Size for Requests - Optional (in Megabytes)
101
+ if ENV['WAFRIS_MAX_BODY_SIZE_MB'] && ENV['WAFRIS_MAX_BODY_SIZE_MB'].to_i > 0
102
+ @max_body_size_mb = ENV['WAFRIS_MAX_BODY_SIZE_MB'].to_i
103
+ else
104
+ @max_body_size_mb = 10
105
+ end
36
106
 
37
- def wafris_core
38
- read_lua_dist("wafris_core")
107
+ # Upsync Queue Defaults
108
+ @upsync_queue = []
109
+ @last_upsync_timestamp = Time.now.to_i
110
+
111
+ # Memory structure for rate limiting
112
+ @rate_limiters = {}
113
+
114
+ # Disable Upsync if Downsync API Key is invalid
115
+ # This prevents the client from sending upsync requests
116
+ # if the API key is known bad
117
+ @upsync_status = 'Disabled'
118
+
119
+ return true
120
+
39
121
  end
40
122
 
41
- private
123
+ def current_config
124
+
125
+ output = {}
126
+
127
+ instance_variables.each do |var|
128
+ output[var.to_s] = instance_variable_get(var)
129
+ end
130
+
131
+ return output
42
132
 
43
- def read_lua_dist(filename)
44
- File.read(
45
- file_path(filename)
46
- )
47
133
  end
48
134
 
49
- def file_path(filename)
50
- File.join(
51
- File.dirname(__FILE__),
52
- "../lua/dist/#{filename}.lua"
53
- )
135
+ def create_settings
136
+ @version = Wafris::VERSION
54
137
  end
138
+
55
139
  end
56
140
  end
@@ -3,11 +3,12 @@
3
3
  module Wafris
4
4
  class LogSuppressor
5
5
  def self.puts_log(message)
6
- puts(message) unless suppress_logs?
6
+ puts("[Wafris] " + message) unless suppress_logs?
7
7
  end
8
8
 
9
9
  def self.suppress_logs?
10
- suppressed_environments.include?(current_environment)
10
+ suppressed_environments.include?(current_environment) ||
11
+ (ENV['WAFRIS_LOG_LEVEL'] && ENV['WAFRIS_LOG_LEVEL'] == 'silent')
11
12
  end
12
13
 
13
14
  def self.suppressed_environments
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+
3
4
  module Wafris
4
5
  class Middleware
5
6
  def initialize(app)
6
7
  @app = app
7
8
  end
8
9
 
10
+
9
11
  def call(env)
12
+
10
13
  user_defined_proxies = ENV['TRUSTED_PROXY_RANGES'].split(',') if ENV['TRUSTED_PROXY_RANGES']
11
14
 
12
15
  valid_ipv4_octet = /\.(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])/
@@ -25,34 +28,53 @@ module Wafris
25
28
  Rack::Request.ip_filter = lambda { |ip| trusted_proxies.match?(ip) }
26
29
 
27
30
  request = Rack::Request.new(env)
31
+ # Forcing UTF-8 encoding on all strings for Sqlite3 compatibility
28
32
 
29
- if Wafris.allow_request?(request)
30
- @app.call(env)
31
- else
32
- LogSuppressor.puts_log(
33
- "[Wafris] Blocked: #{request.ip} #{request.request_method} #{request.host} #{request.url}}"
34
- )
35
- [403, {}, ['Blocked']]
36
- end
37
- rescue Redis::TimeoutError
38
- LogSuppressor.puts_log(
39
- "[Wafris] Wafris timed out during processing. Request passed without rules check."
40
- )
41
- @app.call(env)
42
- rescue NoMethodError => e
43
- if e.message.include?("undefined method `connection_pool'")
44
- LogSuppressor.puts_log(
45
- "[Wafris] Wafris is not configured. Please check your configuration settings. Request passed without rules check. More info can be found at: https://github.com/Wafris/wafris-rb"
46
- )
33
+ # List of possible IP headers in order of priority
34
+ ip_headers = [
35
+ 'HTTP_X_REAL_IP',
36
+ 'HTTP_X_TRUE_CLIENT_IP',
37
+ 'HTTP_FLY_CLIENT_IP',
38
+ 'HTTP_CF_CONNECTING_IP'
39
+ ]
40
+
41
+ # Find the first header that is present in the environment
42
+ ip_header = ip_headers.find { |header| env[header] }
43
+
44
+ # Use the found header or fallback to remote_ip if none of the headers are present
45
+ ip = (ip_header ? env[ip_header] : request.ip).force_encoding('UTF-8')
46
+
47
+ user_agent = request.user_agent ? request.user_agent.force_encoding('UTF-8') : nil
48
+ path = request.path.force_encoding('UTF-8')
49
+ parameters = Rack::Utils.build_query(request.params).force_encoding('UTF-8')
50
+ host = request.host.to_s.force_encoding('UTF-8')
51
+ request_method = String.new(request.request_method).force_encoding('UTF-8')
52
+
53
+ # Submitted for evaluation
54
+ headers = env.each_with_object({}) { |(k, v), h| h[k] = v.force_encoding('UTF-8') if k.start_with?('HTTP_') }
55
+ body = request.body.read
56
+
57
+ request_id = env.fetch('action_dispatch.request_id', SecureRandom.uuid.to_s)
58
+ request_timestamp = Time.now.utc.to_i
59
+
60
+ treatment = Wafris.evaluate(ip, user_agent, path, parameters, host, request_method, headers, body, request_id, request_timestamp)
61
+
62
+ # These values match what the client tests expect (200, 404, 403, 500
63
+ if treatment == 'Allowed' || treatment == 'Passed'
64
+ @app.call(env)
65
+ elsif treatment == 'Blocked'
66
+ [403, { 'content-type' => 'text/plain' }, ['Blocked']]
47
67
  else
48
- raise e
68
+ #ap request
69
+ [500, { 'content-type' => 'text/plain' }, ['Error']]
49
70
  end
50
- @app.call(env)
71
+
51
72
  rescue StandardError => e
52
- LogSuppressor.puts_log(
53
- "[Wafris] Redis connection error: #{e.message}. Request passed without rules check."
54
- )
73
+
74
+ LogSuppressor.puts_log "[Wafris] Detailed Error: #{e.class} - #{e.message}"
75
+ LogSuppressor.puts_log "[Wafris] Backtrace: #{e.backtrace.join("\n")}"
55
76
  @app.call(env)
77
+
56
78
  end
57
79
  end
58
80
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wafris
4
- VERSION = "1.1.11"
4
+ VERSION = "2.0.0"
5
5
  end