sqreen 1.17.2.rc1-java → 1.18.0-java

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: f062d7ef72850413e24e2af4a34475c0af5a11c85ae21757e8d220cdd5569ee8
4
- data.tar.gz: d6da283f4041d0c1d72bb2ebeb3517ef9b27d3988c49907765f35416a11c7976
3
+ metadata.gz: 922051da24f2022f3a83abf7f948dc5736755b1470e3c07e51ea620b4ad79d38
4
+ data.tar.gz: 286a940f0c898061965af56bc612cff127123743c81f29460bdb50b74f336cac
5
5
  SHA512:
6
- metadata.gz: 94b0d8203e361dc77843055305250b14ebd084949be572baf7b581c478b4ed2a0af7e8eba06459aa2b1fda16e053ae7b9836b7fc5fbda04f81c55106b814d05f
7
- data.tar.gz: 954ba804f9105405a31405cb54caec93ed2f96232d313cfa475fe35aec7e681027d72497920e886205a667a63fb2742a5847c2d3227f25038cf9f59c7f94a368
6
+ metadata.gz: 366be041f989a6668942f1e7f41be437572a9b128ff8622f916b5482aaf21b5f45f0ecdd7df11c44f1fa69b4823abc518e8c200fcc6b421d394f98e2b942c426
7
+ data.tar.gz: aec4842b37b82db5d7603a225fd1b14ece321793cf5d0f9e52f96be4acfc335427ea8056144bd3a8f0bfe960a8709b990e407c6329f746fe7a3aa03ebc30957e
@@ -1,23 +1,15 @@
1
- ## 1.17.2.beta4
1
+ ## 1.18.0
2
2
 
3
- * Improve output of logging
4
- * Fix user signup tracking issue
3
+ * Support In-App WAF
5
4
 
6
- ## 1.17.2.beta3
5
+ ## 1.17.2
7
6
 
7
+ * Support Rails 6.0 (single database)
8
+ * Improve output of logging
9
+ * Fix user signup tracking issue
8
10
  * Improve performance of user tracking
9
11
  * Improve reliability of user tracking against performance budget
10
- * Restore compatibility with Ruby 1.9.3, 2.0, and 2.1 and JRuby 9.2
11
-
12
- ## 1.17.2.beta2
13
-
14
- * Important note: this beta release supports Ruby 2.2 or above only
15
12
  * Add support for Sinatra 2.0
16
-
17
- ## 1.17.2.beta1
18
-
19
- * Important note: this beta release supports Rails only, and notably excludes Sinatra support
20
- * Important note: this beta release supports Ruby 2.2 or above only
21
13
  * Improve Sqreen thread boot when using Unicorn, Rainbows, Puma, Passenger, Thin, Webrick
22
14
  * Improve performance cap consistency with specification
23
15
  * Improve consistency of rule precondition argument passing
@@ -0,0 +1,22 @@
1
+ module Sqreen
2
+ class EncodingSanitizer
3
+ def self.sanitize(obj)
4
+ case obj
5
+ when String
6
+ sanitize_string(obj)
7
+ when Array
8
+ obj.map { |e| sanitize(e) }
9
+ when Hash
10
+ obj.each_with_object({}) { |(k, v), h| h[k] = sanitize(v) }
11
+ else
12
+ obj
13
+ end
14
+ end
15
+
16
+ def self.sanitize_string(s)
17
+ return s if s.encoding.name == 'UTF-8' && s.valid_encoding?
18
+
19
+ s.encode('UTF-16', :invalid => :replace, :undef => :replace).encode('UTF-8')
20
+ end
21
+ end
22
+ end
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'json'
5
5
  require 'sqreen/event'
6
+ require 'sqreen/encoding_sanitizer'
6
7
 
7
8
  module Sqreen
8
9
  # When a request is deeemed worthy of being sent to the backend
@@ -115,27 +116,6 @@ module Sqreen
115
116
  end
116
117
  end
117
118
 
118
- class EncodingSanitizer
119
- def self.sanitize(obj)
120
- case obj
121
- when String
122
- sanitize_string(obj)
123
- when Array
124
- obj.map { |e| sanitize(e) }
125
- when Hash
126
- obj.each_with_object({}) { |(k, v), h| h[k] = sanitize(v) }
127
- else
128
- obj
129
- end
130
- end
131
-
132
- def self.sanitize_string(s)
133
- return s if s.encoding.name == 'UTF-8' && s.valid_encoding?
134
-
135
- s.encode('UTF-16', :invalid => :replace, :undef => :replace).encode('UTF-8')
136
- end
137
- end
138
-
139
119
  # For redacting sensitive data and avoid having it sent to our servers
140
120
  class SensitiveDataRedactor
141
121
  DEFAULT_SENSITIVE_KEYS = Set.new(%w[password secret passwd authorization api_key apikey access_token]).freeze
@@ -62,6 +62,10 @@ module Sqreen
62
62
 
63
63
  # Wrapper class for sqreen logging
64
64
  class Logger
65
+ SEVERITY_TO_METHOD = ::Logger::Severity.constants.each_with_object({}) do |s, h|
66
+ h[::Logger::Severity.const_get(s)] = s.downcase
67
+ end
68
+
65
69
  def initialize(desired_level, log_location, force_logger = nil)
66
70
  if force_logger
67
71
  @logger = force_logger
@@ -90,6 +94,10 @@ module Sqreen
90
94
  @logger.error(msg, &block)
91
95
  end
92
96
 
97
+ def add(severity, msg = nil, &block)
98
+ send(SEVERITY_TO_METHOD[severity], msg, &block)
99
+ end
100
+
93
101
  protected
94
102
 
95
103
  def init_logger_output(path)
@@ -135,6 +143,10 @@ module Sqreen
135
143
 
136
144
  def error(_msg = nil); end
137
145
 
146
+ def fatal(_msg = nil); end
147
+
148
+ def add(_severity, _msg = nil); end
149
+
138
150
  def formatter=(_); end
139
151
  end
140
152
 
@@ -162,6 +174,14 @@ module Sqreen
162
174
  @logger.error(msg, &block)
163
175
  end
164
176
 
177
+ def fatal(msg = nil, &block)
178
+ @logger.error(msg, &block)
179
+ end
180
+
181
+ def add(severity, msg = nil, &block)
182
+ send(Sqreen::Logger::SEVERITY_TO_METHOD[severity], msg, &block)
183
+ end
184
+
165
185
  def formatter=(value)
166
186
  @logger.formatter = value
167
187
  end
@@ -31,3 +31,4 @@ require 'sqreen/rules_callbacks/devise_auth_track'
31
31
  require 'sqreen/rules_callbacks/devise_signup_track'
32
32
 
33
33
  require 'sqreen/rules_callbacks/custom_error'
34
+ require 'sqreen/rules_callbacks/waf'
@@ -0,0 +1,102 @@
1
+ require 'securerandom'
2
+ require 'sqreen/rule_attributes'
3
+ require 'sqreen/binding_accessor'
4
+ require 'sqreen/rule_callback'
5
+ require 'sqreen/safe_json'
6
+
7
+ module Sqreen
8
+ module Rules
9
+ class WAFCB < RuleCB
10
+ BUDGET_MAX = 5000
11
+
12
+ # TODO: move to Dependency
13
+ begin
14
+ require 'libsqreen'
15
+ @libsqreen = true
16
+ rescue LoadError
17
+ Sqreen.log.warn('libsqreen gem not found')
18
+ @libsqreen = false
19
+ end
20
+
21
+ def self.libsqreen?
22
+ @libsqreen
23
+ end
24
+
25
+ attr_reader :binding_accessors, :budget, :waf_rule_name
26
+
27
+ def initialize(*args)
28
+ super(*args)
29
+ @overtimeable = false
30
+
31
+ unless WAFCB.libsqreen?
32
+ Sqreen.log.warn('libsqreen gem not found')
33
+ return
34
+ end
35
+
36
+ unless @data['values']
37
+ Sqreen.log.warn('no values in data')
38
+ return
39
+ end
40
+
41
+ ::LibSqreen::WAF.logger = Sqreen.log
42
+
43
+ name = format("%s_%s", SecureRandom.uuid, rule_name)
44
+ unless @data['values']['waf_rules'] && (::LibSqreen::WAF[name] = @data['values']['waf_rules'])
45
+ Sqreen.log.error("WAF rule #{name} failed to be set, from #<#{self.class.name}:0x#{object_id.to_s(16).rjust(16, '0')}>")
46
+ return
47
+ end
48
+ @waf_rule_name = name
49
+ Sqreen.log.debug("WAF rule #{name} set, from #<#{self.class.name}:0x#{object_id.to_s(16).rjust(16, '0')}>")
50
+
51
+ @binding_accessors = @data['values'].fetch('binding_accessors', []).each_with_object({}) do |e, h|
52
+ h[e] = BindingAccessor.new(e)
53
+ end
54
+ @budget = @data['values'].fetch('budget', BUDGET_MAX)
55
+
56
+ ObjectSpace.define_finalizer(self, WAFCB.finalizer(@waf_rule_name.dup))
57
+ end
58
+
59
+ def pre(instance, args, _budget)
60
+ unless WAFCB.libsqreen?
61
+ Sqreen.log.warn('libsqreen not required')
62
+ return
63
+ end
64
+
65
+ request = framework.request
66
+ return if !waf_rule_name || !request
67
+
68
+ env = [binding, framework, instance, args]
69
+
70
+ waf_args = Hash[binding_accessors.map { |e, b| [e, b.resolve(*env)] }]
71
+ waf_args = Sqreen::EncodingSanitizer.sanitize(waf_args)
72
+ action, data = ::LibSqreen::WAF.run(waf_rule_name, waf_args, budget)
73
+
74
+ case action
75
+ when :monitor
76
+ record_event({ 'waf_data' => data })
77
+ advise_action(nil)
78
+ when :block
79
+ record_event({ 'waf_data' => data })
80
+ advise_action(:raise)
81
+ when :good
82
+ advise_action(nil)
83
+ when :timeout, :invalid_call, :invalid_rule, :invalid_flow, :no_rule
84
+ Sqreen.log.warn("error from waf: #{action}")
85
+ advise_action(nil)
86
+ else
87
+ Sqreen.log.warn("unexpected action returned from waf")
88
+ advise_action(nil)
89
+ end
90
+ end
91
+
92
+ def self.finalizer(rule_name)
93
+ lambda do |object_id|
94
+ return unless WAFCB.libsqreen?
95
+
96
+ ::LibSqreen::WAF.delete(waf_rule_name, waf_args, budget)
97
+ Sqreen.log.debug("WAF rule #{rule_name} deleted, from #<#{name}:0x#{object_id.to_s(16).rjust(16, '0')}>")
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -65,7 +65,32 @@ module Sqreen
65
65
  {
66
66
  :agent_type => :ruby,
67
67
  :agent_version => ::Sqreen::VERSION,
68
- }
68
+ }.tap do |h|
69
+ h[:libsqreen_version] = libsqreen_version if libsqreen?
70
+ end
71
+ end
72
+
73
+ def libsqreen?
74
+ libsqreen_loaded? && !libsqreen_stub?
75
+ end
76
+
77
+ def libsqreen_loaded?
78
+ Kernel.const_defined?('LibSqreen')
79
+ end
80
+
81
+ def libsqreen_stub?
82
+ !::LibSqreen.respond_to?(:version)
83
+ end
84
+
85
+ def libsqreen_version
86
+ return unless libsqreen?
87
+
88
+ @libsqreen_version ||= case (version = ::LibSqreen.version)
89
+ when Array
90
+ version.map(&:to_s).join('.')
91
+ else
92
+ version
93
+ end
69
94
  end
70
95
 
71
96
  def os
@@ -100,7 +100,7 @@ module Sqreen
100
100
  rescue StandardError => e
101
101
  Sqreen.log.debug { "Caught exception during request: #{e.inspect}" }
102
102
  Sqreen.log.debug { e.backtrace }
103
- Sqreen.log.debug "Cannot connect, retry in #{RETRY_CONNECT_SECONDS} seconds"
103
+ Sqreen.log.debug { "Cannot connect, retry in #{RETRY_CONNECT_SECONDS} seconds" }
104
104
  sleep RETRY_CONNECT_SECONDS
105
105
  @conn_retry += 1
106
106
  retry
@@ -129,7 +129,7 @@ module Sqreen
129
129
  raise e if max_retry != RETRY_FOREVER && current_retry >= max_retry || e.is_a?(Sqreen::NotImplementedYet) || e.is_a?(Sqreen::Unauthorized)
130
130
 
131
131
  sleep_delay = [MAX_DELAY, retry_request_seconds * current_retry].min
132
- Sqreen.log.debug format("Sleeping %ds before retry #{current_retry}/#{max_retry}", sleep_delay)
132
+ Sqreen.log.debug { format("Sleeping %ds before retry #{current_retry}/#{max_retry}", sleep_delay) }
133
133
  sleep(sleep_delay)
134
134
 
135
135
  retry
@@ -164,10 +164,10 @@ module Sqreen
164
164
  @req_nb += 1
165
165
 
166
166
  path = prefix_path(path)
167
- Sqreen.log.debug format('%s %s (%s)', method, path, @token)
168
167
 
169
168
  payload = {}
170
169
  resiliently(RETRY_REQUEST_SECONDS, max_retry) do
170
+ Sqreen.log.debug { format('%s %s %s %s (%s)', method, path, JSON.dump(data), headers.inspect, @token) }
171
171
  res = nil
172
172
  MUTEX.synchronize do
173
173
  res = case method.upcase
@@ -181,7 +181,7 @@ module Sqreen
181
181
  end
182
182
  @con.post(path, json_data, headers)
183
183
  else
184
- Sqreen.log.debug format('unknown method %s', method)
184
+ Sqreen.log.debug { format('unknown method %s', method) }
185
185
  raise Sqreen::NotImplementedYet
186
186
  end
187
187
  end
@@ -192,17 +192,17 @@ module Sqreen
192
192
  if res['Content-Type'] && res['Content-Type'].start_with?('application/json')
193
193
  payload = JSON.parse(res.body)
194
194
  unless payload['status']
195
- Sqreen.log.debug(format('Cannot %s %s. Parsed response body was: %s', method, path, payload.inspect))
195
+ Sqreen.log.debug { format('Cannot %s %s. Parsed response body was: %s', method, path, payload.inspect) }
196
196
  end
197
197
  else
198
- Sqreen.log.debug "Unexpected response Content-Type: #{res['Content-Type']}"
199
- Sqreen.log.debug "Unexpected response body: #{res.body.inspect}"
198
+ Sqreen.log.debug { "Unexpected response Content-Type: #{res['Content-Type']}" }
199
+ Sqreen.log.debug { "Unexpected response body: #{res.body.inspect}" }
200
200
  end
201
201
  else
202
- Sqreen.log.debug 'warning: empty return value'
202
+ Sqreen.log.debug { 'warning: empty return value' }
203
203
  end
204
+ Sqreen.log.debug { format('%s %s (DONE: %s in %f ms)', method, path, res && res.code, (Time.now.utc - now) * 1000) }
204
205
  end
205
- Sqreen.log.debug format('%s %s (DONE in %f ms)', method, path, (Time.now.utc - now) * 1000)
206
206
  payload
207
207
  end
208
208
 
@@ -233,7 +233,7 @@ module Sqreen
233
233
  end
234
234
  Sqreen.log.info 'Login success.'
235
235
  @session_id = res['session_id']
236
- Sqreen.log.debug "received session_id #{@session_id}"
236
+ Sqreen.log.debug { "received session_id #{@session_id}" }
237
237
  Sqreen.logged_in = true
238
238
  res
239
239
  end
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
  module Sqreen
4
- VERSION = '1.17.2.rc1'.freeze
4
+ VERSION = '1.18.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqreen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.2.rc1
4
+ version: 1.18.0
5
5
  platform: java
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-29 00:00:00.000000000 Z
11
+ date: 2019-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -78,6 +78,7 @@ files:
78
78
  - lib/sqreen/dependency/rails.rb
79
79
  - lib/sqreen/dependency/sentry.rb
80
80
  - lib/sqreen/dependency/sinatra.rb
81
+ - lib/sqreen/encoding_sanitizer.rb
81
82
  - lib/sqreen/event.rb
82
83
  - lib/sqreen/events/attack.rb
83
84
  - lib/sqreen/events/remote_exception.rb
@@ -140,6 +141,7 @@ files:
140
141
  - lib/sqreen/rules_callbacks/shell_env.rb
141
142
  - lib/sqreen/rules_callbacks/url_matches.rb
142
143
  - lib/sqreen/rules_callbacks/user_agent_matches.rb
144
+ - lib/sqreen/rules_callbacks/waf.rb
143
145
  - lib/sqreen/rules_signature.rb
144
146
  - lib/sqreen/runner.rb
145
147
  - lib/sqreen/runtime_infos.rb
@@ -163,9 +165,7 @@ files:
163
165
  homepage: https://www.sqreen.io/
164
166
  licenses: []
165
167
  metadata: {}
166
- post_install_message: |2
167
- This is a Sqreen rc release and may not work in all situations.
168
- Make sure to review CHANGELOG.md for important details.
168
+ post_install_message:
169
169
  rdoc_options: []
170
170
  require_paths:
171
171
  - lib
@@ -176,9 +176,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
176
176
  version: 1.9.3
177
177
  required_rubygems_version: !ruby/object:Gem::Requirement
178
178
  requirements:
179
- - - ">"
179
+ - - ">="
180
180
  - !ruby/object:Gem::Version
181
- version: 1.3.1
181
+ version: '0'
182
182
  requirements: []
183
183
  rubyforge_project:
184
184
  rubygems_version: 2.7.7