sqreen 1.11.0-java → 1.11.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sqreen.rb +0 -1
- data/lib/sqreen/callback_tree.rb +38 -20
- data/lib/sqreen/callbacks.rb +6 -4
- data/lib/sqreen/conditionable.rb +3 -3
- data/lib/sqreen/frameworks/generic.rb +38 -18
- data/lib/sqreen/frameworks/request_recorder.rb +0 -2
- data/lib/sqreen/instrumentation.rb +217 -160
- data/lib/sqreen/performance_notifications.rb +10 -36
- data/lib/sqreen/performance_notifications/log.rb +1 -2
- data/lib/sqreen/performance_notifications/log_performance.rb +1 -2
- data/lib/sqreen/performance_notifications/metrics.rb +1 -2
- data/lib/sqreen/performance_notifications/newrelic.rb +1 -2
- data/lib/sqreen/remote_command.rb +7 -7
- data/lib/sqreen/rule_callback.rb +4 -0
- data/lib/sqreen/rules.rb +2 -2
- data/lib/sqreen/rules_callbacks/binding_accessor_matcher.rb +7 -1
- data/lib/sqreen/rules_callbacks/binding_accessor_metrics.rb +3 -3
- data/lib/sqreen/rules_callbacks/blacklist_ips.rb +1 -1
- data/lib/sqreen/rules_callbacks/count_http_codes.rb +7 -6
- data/lib/sqreen/rules_callbacks/crawler_user_agent_matches.rb +1 -1
- data/lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb +1 -1
- data/lib/sqreen/rules_callbacks/custom_error.rb +2 -5
- data/lib/sqreen/rules_callbacks/execjs.rb +76 -37
- data/lib/sqreen/rules_callbacks/headers_insert.rb +1 -1
- data/lib/sqreen/rules_callbacks/inspect_rule.rb +3 -3
- data/lib/sqreen/rules_callbacks/matcher_rule.rb +18 -17
- data/lib/sqreen/rules_callbacks/rails_parameters.rb +1 -1
- data/lib/sqreen/rules_callbacks/record_request_context.rb +9 -8
- data/lib/sqreen/rules_callbacks/reflected_xss.rb +40 -34
- data/lib/sqreen/rules_callbacks/regexp_rule.rb +13 -4
- data/lib/sqreen/rules_callbacks/shell_env.rb +2 -2
- data/lib/sqreen/rules_callbacks/url_matches.rb +1 -1
- data/lib/sqreen/rules_callbacks/user_agent_matches.rb +1 -1
- data/lib/sqreen/session.rb +1 -1
- data/lib/sqreen/shared_storage.rb +16 -12
- data/lib/sqreen/{stats.rb → shared_storage23.rb} +3 -11
- data/lib/sqreen/version.rb +1 -1
- metadata +4 -4
@@ -7,7 +7,7 @@ module Sqreen
|
|
7
7
|
module Rules
|
8
8
|
# Display sqreen presence
|
9
9
|
class HeadersInsertCB < RuleCB
|
10
|
-
def post(rv, _inst,
|
10
|
+
def post(rv, _inst, _args, _budget = nil, &_block)
|
11
11
|
return unless rv && rv.respond_to?(:[]) && rv[1].is_a?(Hash)
|
12
12
|
return nil unless @data
|
13
13
|
headers = @data['values'] || []
|
@@ -6,17 +6,17 @@ require 'sqreen/rule_callback'
|
|
6
6
|
module Sqreen
|
7
7
|
module Rules
|
8
8
|
class InspectRuleCB < RuleCB
|
9
|
-
def pre(_inst,
|
9
|
+
def pre(_inst, args, _budget = nil, &_block)
|
10
10
|
Sqreen.log.debug { "<< #{@klass} #{@method} #{Thread.current}" }
|
11
11
|
Sqreen.log.debug { args.map(&:inspect).join(' ') }
|
12
12
|
end
|
13
13
|
|
14
|
-
def post(rv, _inst,
|
14
|
+
def post(rv, _inst, _args, _budget = nil, &_block)
|
15
15
|
Sqreen.log.debug { ">> #{rv.inspect} #{@klass} #{@method} #{Thread.current}" }
|
16
16
|
byebug if defined? byebug && @data.is_a?(Hash) && @data[:break] == 1
|
17
17
|
end
|
18
18
|
|
19
|
-
def failing(rv, _inst,
|
19
|
+
def failing(rv, _inst, _args, _budget = nil, &_block)
|
20
20
|
Sqreen.log.debug { "># #{rv.inspect} #{@klass} #{@method} #{Thread.current}" }
|
21
21
|
byebug if defined? byebug && @data.is_a?(Hash) && @data[:break] == 1
|
22
22
|
end
|
@@ -13,11 +13,12 @@ module Sqreen
|
|
13
13
|
res |= Regexp::MULTILINE if options.include?('multiline')
|
14
14
|
res |= Regexp::IGNORECASE unless case_sensitive
|
15
15
|
r = Regexp.compile(value, res)
|
16
|
-
r.match(
|
16
|
+
r.match('')
|
17
17
|
r
|
18
18
|
end
|
19
19
|
|
20
20
|
ANYWHERE_OPT = 'anywhere'.freeze
|
21
|
+
MATCH_PREDICATE = Regexp.new('').respond_to?(:match?)
|
21
22
|
def prepare(patterns)
|
22
23
|
@string = {}
|
23
24
|
@regexp_patterns = []
|
@@ -52,12 +53,13 @@ module Sqreen
|
|
52
53
|
val.downcase!
|
53
54
|
end
|
54
55
|
|
55
|
-
|
56
|
+
way = @funs[opt]
|
57
|
+
unless way
|
56
58
|
Sqreen.log.debug { "Error: unknown string option '#{opt}' " }
|
57
59
|
next
|
58
60
|
end
|
59
|
-
@string[
|
60
|
-
@string[
|
61
|
+
@string[way] = { :ci => [], :cs => [] } unless @string.key?(way)
|
62
|
+
@string[way][case_type] << val
|
61
63
|
sizes << entry.fetch('min_length') { val.size }
|
62
64
|
when 'regexp'
|
63
65
|
pattern = Matcher.prepare_re_pattern(val, opt, case_sensitive)
|
@@ -81,17 +83,9 @@ module Sqreen
|
|
81
83
|
str = enforce_encoding(str) unless str.ascii_only?
|
82
84
|
istr = str.downcase unless @string.empty?
|
83
85
|
|
84
|
-
@string.each do |
|
85
|
-
fun = @funs[type]
|
86
|
-
if fun.nil?
|
87
|
-
Sqreen.log.debug { "no matching function found for type #{type}" }
|
88
|
-
end
|
86
|
+
@string.each do |fun, cases|
|
89
87
|
cases.each do |case_type, patterns|
|
90
|
-
input_str =
|
91
|
-
istr
|
92
|
-
else
|
93
|
-
str
|
94
|
-
end
|
88
|
+
input_str = case_type == :ci ? istr : str
|
95
89
|
patterns.each do |pat|
|
96
90
|
return pat if fun.call(pat, input_str)
|
97
91
|
end
|
@@ -99,9 +93,16 @@ module Sqreen
|
|
99
93
|
end
|
100
94
|
|
101
95
|
if defined?(Encoding)
|
102
|
-
|
103
|
-
|
104
|
-
|
96
|
+
if MATCH_PREDICATE
|
97
|
+
@regexp_patterns.each do |p|
|
98
|
+
next unless Encoding.compatible?(p, str)
|
99
|
+
return p if p.match?(str)
|
100
|
+
end
|
101
|
+
else
|
102
|
+
@regexp_patterns.each do |p|
|
103
|
+
next unless Encoding.compatible?(p, str)
|
104
|
+
return p if p.match(str)
|
105
|
+
end
|
105
106
|
end
|
106
107
|
else
|
107
108
|
@regexp_patterns.each do |p|
|
@@ -2,39 +2,40 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
require 'sqreen/rule_callback'
|
5
|
-
require 'sqreen/instrumentation'
|
6
5
|
|
7
6
|
module Sqreen
|
8
7
|
module Rules
|
9
8
|
# Save request context for handling further down
|
10
9
|
class RecordRequestContext < RuleCB
|
11
|
-
|
12
|
-
|
10
|
+
WHITELISTED_METRIC = 'whitelisted'.freeze
|
11
|
+
def initialize(*args)
|
12
|
+
super(*args)
|
13
|
+
@overtimeable = false
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
+
def whitelisted?
|
16
17
|
false
|
17
18
|
end
|
18
19
|
|
19
|
-
def pre(_inst,
|
20
|
+
def pre(_inst, args, _budget = nil, &_block)
|
20
21
|
framework.store_request(args[0])
|
21
22
|
wh = framework.whitelisted_match
|
22
23
|
if wh
|
23
24
|
unless Sqreen.features.key?('whitelisted_metric') &&
|
24
25
|
!Sqreen.features['whitelisted_metric']
|
25
|
-
record_observation(
|
26
|
+
record_observation(WHITELISTED_METRIC, wh, 1)
|
26
27
|
end
|
27
28
|
Sqreen.log.debug { "Request was whitelisted because of #{wh}" }
|
28
29
|
end
|
29
30
|
advise_action(nil)
|
30
31
|
end
|
31
32
|
|
32
|
-
def post(_rv, _inst,
|
33
|
+
def post(_rv, _inst, _args, _budget = nil, &_block)
|
33
34
|
framework.clean_request
|
34
35
|
advise_action(nil)
|
35
36
|
end
|
36
37
|
|
37
|
-
def failing(_exception, _inst,
|
38
|
+
def failing(_exception, _inst, _args, _budget = nil, &_block)
|
38
39
|
framework.clean_request
|
39
40
|
advise_action(nil)
|
40
41
|
end
|
@@ -37,7 +37,7 @@ module Sqreen
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
class ReflectedUnsafeXSSCB < XSSCB
|
40
|
-
def pre(_inst,
|
40
|
+
def pre(_inst, args, _budget = nil, &_block)
|
41
41
|
value = args[0]
|
42
42
|
|
43
43
|
return unless value.is_a?(String)
|
@@ -61,7 +61,7 @@ module Sqreen
|
|
61
61
|
end
|
62
62
|
# look for reflected XSS with erb template engine
|
63
63
|
class ReflectedXSSCB < XSSCB
|
64
|
-
def pre(_inst,
|
64
|
+
def pre(_inst, args, _budget = nil, &_block)
|
65
65
|
value = args[0]
|
66
66
|
|
67
67
|
return unless value.is_a?(String)
|
@@ -90,7 +90,7 @@ module Sqreen
|
|
90
90
|
# escape_html, nuke_inner_whitespace,
|
91
91
|
# interpolated, ugly)
|
92
92
|
class ReflectedXSSHamlCB < XSSCB
|
93
|
-
def post(ret, _inst,
|
93
|
+
def post(ret, _inst, _args, _budget = nil, &_block)
|
94
94
|
value = ret
|
95
95
|
return unless value.is_a?(String)
|
96
96
|
|
@@ -109,7 +109,12 @@ module Sqreen
|
|
109
109
|
|
110
110
|
# Hook into haml4 script parser
|
111
111
|
class Haml4ParserScriptHookCB < RuleCB
|
112
|
-
def
|
112
|
+
def initialize(*args)
|
113
|
+
super(*args)
|
114
|
+
@overtimeable = false
|
115
|
+
end
|
116
|
+
|
117
|
+
def pre(_inst, args, _budget = nil, &_block)
|
113
118
|
return unless args.size > 1
|
114
119
|
return unless Haml::VERSION < '5'
|
115
120
|
text = args[0]
|
@@ -121,15 +126,16 @@ module Sqreen
|
|
121
126
|
end
|
122
127
|
nil
|
123
128
|
end
|
124
|
-
|
125
|
-
def overtime!
|
126
|
-
false
|
127
|
-
end
|
128
129
|
end
|
129
130
|
|
130
131
|
# Hook into haml4 tag parser
|
131
132
|
class Haml4ParserTagHookCB < RuleCB
|
132
|
-
def
|
133
|
+
def initialize(*args)
|
134
|
+
super(*args)
|
135
|
+
@overtimeable = false
|
136
|
+
end
|
137
|
+
|
138
|
+
def post(ret, _inst, _args, _budget = nil, &_block)
|
133
139
|
return unless Haml::VERSION < '5'
|
134
140
|
tag = ret
|
135
141
|
if tag.value[:escape_html] == false &&
|
@@ -140,14 +146,15 @@ module Sqreen
|
|
140
146
|
end
|
141
147
|
nil
|
142
148
|
end
|
143
|
-
|
144
|
-
def overtime!
|
145
|
-
false
|
146
|
-
end
|
147
149
|
end
|
148
150
|
|
149
151
|
class Haml4UtilInterpolationHookCB < RuleCB
|
150
|
-
def
|
152
|
+
def initialize(*args)
|
153
|
+
super(*args)
|
154
|
+
@overtimeable = false
|
155
|
+
end
|
156
|
+
|
157
|
+
def pre(_inst, args, _budget = nil, &_block)
|
151
158
|
# Also work in haml5
|
152
159
|
str = args[0]
|
153
160
|
escape_html = args[1]
|
@@ -167,15 +174,16 @@ module Sqreen
|
|
167
174
|
end
|
168
175
|
{ :status => :skip, :new_return_value => res + rest }
|
169
176
|
end
|
170
|
-
|
171
|
-
def overtime!
|
172
|
-
false
|
173
|
-
end
|
174
177
|
end
|
175
178
|
|
176
179
|
# Hook build attributes
|
177
180
|
class Haml4CompilerBuildAttributeCB < XSSCB
|
178
|
-
def
|
181
|
+
def initialize(*args)
|
182
|
+
super(*args)
|
183
|
+
@overtimeable = false
|
184
|
+
end
|
185
|
+
|
186
|
+
def pre(inst, args, _budget = nil, &_block)
|
179
187
|
return unless Haml::VERSION < '5'
|
180
188
|
attrs = args[-1]
|
181
189
|
params = xss_params
|
@@ -217,38 +225,36 @@ module Sqreen
|
|
217
225
|
end
|
218
226
|
[new_h, has_xss]
|
219
227
|
end
|
220
|
-
|
221
|
-
def overtime!
|
222
|
-
false
|
223
|
-
end
|
224
228
|
end
|
225
229
|
|
226
230
|
class Haml5EscapableHookCB < RuleCB
|
227
|
-
def
|
228
|
-
|
229
|
-
|
231
|
+
def initialize(*args)
|
232
|
+
super(*args)
|
233
|
+
@overtimeable = false
|
230
234
|
end
|
231
235
|
|
232
|
-
def
|
233
|
-
|
236
|
+
def pre(_inst, args, _budget = nil, &_block)
|
237
|
+
args[0] = "Sqreen.escape_haml((#{args[0]}))"
|
238
|
+
{ :status => :modify_args, :args => args }
|
234
239
|
end
|
235
240
|
end
|
236
241
|
|
237
242
|
# Hook into temple template rendering
|
238
243
|
class TempleEscapableHookCB < RuleCB
|
239
|
-
def
|
240
|
-
|
241
|
-
|
244
|
+
def initialize(*args)
|
245
|
+
super(*args)
|
246
|
+
@overtimeable = false
|
242
247
|
end
|
243
248
|
|
244
|
-
def
|
245
|
-
|
249
|
+
def post(ret, _inst, _args, _budget = nil, &_block)
|
250
|
+
ret[1] = "Sqreen.escape_temple((#{ret[1]}))"
|
251
|
+
{ :status => :override, :new_return_value => ret }
|
246
252
|
end
|
247
253
|
end
|
248
254
|
|
249
255
|
# Hook into temple template rendering
|
250
256
|
class SlimSplatBuilderCB < XSSCB
|
251
|
-
def pre(inst,
|
257
|
+
def pre(inst, args, _budget = nil, &_block)
|
252
258
|
value = args[0]
|
253
259
|
return if value.nil?
|
254
260
|
|
@@ -25,11 +25,20 @@ module Sqreen
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
if Regexp.new('').respond_to?(:match?)
|
29
|
+
def match_regexp(str)
|
30
|
+
@patterns.each do |pattern|
|
31
|
+
return pattern if pattern.match?(str)
|
32
|
+
end
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
else
|
36
|
+
def match_regexp(str)
|
37
|
+
@patterns.each do |pattern|
|
38
|
+
return pattern if pattern.match(str)
|
39
|
+
end
|
40
|
+
nil
|
31
41
|
end
|
32
|
-
nil
|
33
42
|
end
|
34
43
|
end
|
35
44
|
end
|
@@ -7,7 +7,7 @@ module Sqreen
|
|
7
7
|
module Rules
|
8
8
|
# Callback that detect nifty env in system calls
|
9
9
|
class ShellEnvCB < RegexpRuleCB
|
10
|
-
def pre(_inst,
|
10
|
+
def pre(_inst, args, _budget = nil, &_block)
|
11
11
|
return if args.size == 0
|
12
12
|
env = args.first
|
13
13
|
return unless env.is_a?(Hash)
|
@@ -23,7 +23,7 @@ module Sqreen
|
|
23
23
|
:variable_value => value,
|
24
24
|
:found => found,
|
25
25
|
}
|
26
|
-
Sqreen.log.warn "presence of a shell env tampering: #{infos.inspect}"
|
26
|
+
Sqreen.log.warn { "presence of a shell env tampering: #{infos.inspect}" }
|
27
27
|
record_event(infos)
|
28
28
|
advise_action(:raise)
|
29
29
|
end
|
@@ -11,7 +11,7 @@ module Sqreen
|
|
11
11
|
# - the path is a typical bot scanning request
|
12
12
|
# Then we deny the ressource and record the attack.
|
13
13
|
class URLMatchesCB < RegexpRuleCB
|
14
|
-
def post(rv, _inst,
|
14
|
+
def post(rv, _inst, args, _budget = nil, &_block)
|
15
15
|
return unless rv.is_a?(Array) && rv.size > 0 && rv[0] == 404
|
16
16
|
env = args[0]
|
17
17
|
path = env['SCRIPT_NAME'].to_s + env['PATH_INFO'].to_s
|
@@ -7,7 +7,7 @@ module Sqreen
|
|
7
7
|
module Rules
|
8
8
|
# Look for badly behaved clients
|
9
9
|
class UserAgentMatchesCB < RegexpRuleCB
|
10
|
-
def pre(_inst,
|
10
|
+
def pre(_inst, _args, _budget = nil, &_block)
|
11
11
|
ua = framework.client_user_agent
|
12
12
|
return unless ua
|
13
13
|
found = match_regexp(ua)
|
data/lib/sqreen/session.rb
CHANGED
@@ -2,30 +2,34 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
module Sqreen
|
5
|
+
# dedicated local storage
|
5
6
|
module SharedStorage
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
unless RUBY_VERSION >= '2.3.0'
|
8
|
+
def self.get(key)
|
9
|
+
h = Thread.current[:sqreen_shared_storage]
|
10
|
+
h[key] if h
|
11
|
+
end
|
11
12
|
end
|
12
13
|
|
13
|
-
def self
|
14
|
-
Thread.current[
|
15
|
-
Thread.current[
|
14
|
+
def self.set(key, obj)
|
15
|
+
Thread.current[:sqreen_shared_storage] ||= {}
|
16
|
+
Thread.current[:sqreen_shared_storage][key] = obj
|
16
17
|
end
|
17
18
|
|
18
19
|
def self.clear
|
19
|
-
return unless Thread.current[
|
20
|
-
Thread.current[
|
20
|
+
return unless Thread.current[:sqreen_shared_storage].is_a?(Hash)
|
21
|
+
Thread.current[:sqreen_shared_storage].clear
|
21
22
|
end
|
22
23
|
|
23
24
|
def self.inc(value)
|
24
|
-
set(value, get(value
|
25
|
+
set(value, (get(value) || 0) + 1)
|
25
26
|
end
|
26
27
|
|
27
28
|
def self.dec(value)
|
28
|
-
set(value, get(value
|
29
|
+
set(value, (get(value) || 0) - 1)
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
33
|
+
|
34
|
+
# Change SharedStorage.get if ruby is actually newer
|
35
|
+
require 'sqreen/shared_storage23' if RUBY_VERSION >= '2.3.0'
|
@@ -2,17 +2,9 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
module Sqreen
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@@stats ||= Stats.new
|
9
|
-
end
|
10
|
-
|
11
|
-
class Stats
|
12
|
-
attr_accessor :callbacks_calls
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
@callbacks_calls = 0
|
5
|
+
module SharedStorage
|
6
|
+
def self.get(key)
|
7
|
+
Thread.current[:sqreen_shared_storage]&.[](key)
|
16
8
|
end
|
17
9
|
end
|
18
10
|
end
|