sqreen 1.17.2.rc1-java → 1.18.0-java

Sign up to get free protection for your applications and to get access to all the features.
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