sqreen 1.5.0-java → 1.6.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 +4 -4
- data/lib/sqreen/attack_detected.html +2 -0
- data/lib/sqreen/binding_accessor.rb +247 -157
- data/lib/sqreen/condition_evaluator.rb +191 -189
- data/lib/sqreen/frameworks/generic.rb +6 -0
- data/lib/sqreen/frameworks/rails.rb +1 -0
- data/lib/sqreen/frameworks/sinatra.rb +18 -0
- data/lib/sqreen/middleware.rb +10 -0
- data/lib/sqreen/rules_callbacks.rb +3 -0
- data/lib/sqreen/rules_callbacks/binding_accessor_matcher.rb +75 -0
- data/lib/sqreen/rules_callbacks/custom_error.rb +57 -0
- data/lib/sqreen/rules_callbacks/execjs.rb +4 -7
- data/lib/sqreen/rules_callbacks/matcher_rule.rb +26 -20
- data/lib/sqreen/version.rb +1 -1
- metadata +6 -3
data/lib/sqreen/middleware.rb
CHANGED
@@ -21,5 +21,8 @@ require 'sqreen/rules_callbacks/reflected_xss'
|
|
21
21
|
require 'sqreen/rules_callbacks/execjs'
|
22
22
|
|
23
23
|
require 'sqreen/rules_callbacks/binding_accessor_metrics'
|
24
|
+
require 'sqreen/rules_callbacks/binding_accessor_matcher'
|
24
25
|
require 'sqreen/rules_callbacks/count_http_codes'
|
25
26
|
require 'sqreen/rules_callbacks/crawler_user_agent_matches_metrics'
|
27
|
+
|
28
|
+
require 'sqreen/rules_callbacks/custom_error'
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/rule_callback'
|
5
|
+
require 'sqreen/binding_accessor'
|
6
|
+
require 'sqreen/rules_callbacks/matcher_rule'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Rules
|
10
|
+
# Callback that match on a list or matcher+binding accessor
|
11
|
+
class BindingAccessorMatcherCB < RuleCB
|
12
|
+
attr_reader :rules
|
13
|
+
|
14
|
+
# matcher on one elem
|
15
|
+
class MatcherElem
|
16
|
+
def initialize(expr)
|
17
|
+
prepare([expr])
|
18
|
+
end
|
19
|
+
include Matcher
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(klass, method, rule_hash)
|
23
|
+
super(klass, method, rule_hash)
|
24
|
+
@rules = []
|
25
|
+
if @data.empty? || @data['values'].nil? || @data['values'].empty?
|
26
|
+
msg = "no rules in data (had #{@data.keys})"
|
27
|
+
raise Sqreen::Exception, msg
|
28
|
+
end
|
29
|
+
prepare_rules(@data['values'])
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare_rules(rules)
|
33
|
+
accessors = Hash.new do |hash, key|
|
34
|
+
hash[key] = BindingAccessor.new(key, true)
|
35
|
+
end
|
36
|
+
@rules = rules.map do |r|
|
37
|
+
if r['binding_accessor'].empty?
|
38
|
+
raise Sqreen::Exception, "no accessors #{r['id']}"
|
39
|
+
end
|
40
|
+
[
|
41
|
+
r['id'],
|
42
|
+
r['binding_accessor'].map { |expression| accessors[expression] },
|
43
|
+
MatcherElem.new(r['matcher']),
|
44
|
+
r['matcher']['value'],
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def pre(inst, *args, &_block)
|
50
|
+
resol_cache = Hash.new do |hash, accessor|
|
51
|
+
hash[accessor] = accessor.resolve(binding, framework, inst, args)
|
52
|
+
end
|
53
|
+
@rules.each do |id, accessors, matcher, matcher_ref|
|
54
|
+
accessors.each do |accessor|
|
55
|
+
val = resol_cache[accessor]
|
56
|
+
val = [val] if val.is_a?(String)
|
57
|
+
next unless val.respond_to?(:each)
|
58
|
+
val.each do |v|
|
59
|
+
next if matcher.match(v).nil?
|
60
|
+
infos = {
|
61
|
+
'id' => id,
|
62
|
+
'binding_accessor' => accessor.expression,
|
63
|
+
'matcher' => matcher_ref,
|
64
|
+
'found' => v,
|
65
|
+
}
|
66
|
+
record_event(infos)
|
67
|
+
return advise_action(:raise, :infos => infos)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
|
4
|
+
require 'sqreen/rule_callback'
|
5
|
+
require 'sqreen/exception'
|
6
|
+
|
7
|
+
module Sqreen
|
8
|
+
module Rules
|
9
|
+
# Display sqreen presence
|
10
|
+
class CustomErrorCB < RuleCB
|
11
|
+
attr_reader :status_code, :redirect_url
|
12
|
+
def initialize(klass, method, rule_hash)
|
13
|
+
@redirect_url = nil
|
14
|
+
@status_code = nil
|
15
|
+
super(klass, method, rule_hash)
|
16
|
+
if @data.nil? || @data['values'].empty?
|
17
|
+
raise Sqreen::Exception, 'No data'
|
18
|
+
end
|
19
|
+
configure_custom_error(@data['values'][0])
|
20
|
+
end
|
21
|
+
|
22
|
+
def configure_custom_error(custom_error)
|
23
|
+
case custom_error['type']
|
24
|
+
when 'custom_error_page' then
|
25
|
+
@status_code = custom_error['status_code'].to_i
|
26
|
+
when 'redirection' then
|
27
|
+
@redirect_url = custom_error['redirection_url']
|
28
|
+
@status_code = custom_error.fetch('status_code', 303).to_i
|
29
|
+
else
|
30
|
+
raise Sqreen::Exception, "No custom error #{custom_error['type']}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def failing(except, _inst, *_args, &_block)
|
35
|
+
return advise_action(nil) unless except.is_a?(Sqreen::AttackBlocked)
|
36
|
+
if @redirect_url
|
37
|
+
advise_action(:override, :new_return_value => respond_redirect)
|
38
|
+
else
|
39
|
+
advise_action(:override, :new_return_value => respond_page)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def respond_redirect
|
44
|
+
[@status_code, { 'Location' => @redirect_url }, ['']]
|
45
|
+
end
|
46
|
+
|
47
|
+
def respond_page
|
48
|
+
page = open(File.join(File.dirname(__FILE__), '../attack_detected.html'))
|
49
|
+
headers = {
|
50
|
+
'Content-Type' => 'text/html',
|
51
|
+
'Content-Length' => page.size.to_s,
|
52
|
+
}
|
53
|
+
[@status_code, headers, page]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -93,7 +93,7 @@ module Sqreen
|
|
93
93
|
accessor.resolve(binding, framework, inst, args, @data, rv)
|
94
94
|
end
|
95
95
|
Sqreen.log.debug { [name, arguments].inspect }
|
96
|
-
ret = @compiled.call(
|
96
|
+
ret = @compiled.call(name, *arguments)
|
97
97
|
unless record_and_continue?(ret)
|
98
98
|
return nil if ret.nil?
|
99
99
|
return advise_action(ret[:status], ret)
|
@@ -118,13 +118,12 @@ module Sqreen
|
|
118
118
|
|
119
119
|
def build_runnable(callbacks)
|
120
120
|
@argument_requirements = {}
|
121
|
-
@source = '
|
121
|
+
@source = ''
|
122
122
|
@js_pre = !callbacks['pre'].nil?
|
123
123
|
@js_post = !callbacks['post'].nil?
|
124
124
|
@js_failing = !callbacks['failing'].nil?
|
125
125
|
callbacks.each do |name, args_or_func|
|
126
|
-
@source << name
|
127
|
-
@source << ': '
|
126
|
+
@source << "var #{name} = "
|
128
127
|
if args_or_func.is_a?(Array)
|
129
128
|
@source << args_or_func.pop
|
130
129
|
@argument_requirements[name] = build_accessor(args_or_func)
|
@@ -132,10 +131,8 @@ module Sqreen
|
|
132
131
|
@source << args_or_func
|
133
132
|
@argument_requirements[name] = []
|
134
133
|
end
|
135
|
-
@source << "
|
134
|
+
@source << ";\n"
|
136
135
|
end
|
137
|
-
@source << "\n"
|
138
|
-
@source << '}'
|
139
136
|
end
|
140
137
|
end
|
141
138
|
end
|
@@ -5,33 +5,29 @@ require 'sqreen/rule_callback'
|
|
5
5
|
|
6
6
|
module Sqreen
|
7
7
|
module Rules
|
8
|
-
#
|
9
|
-
|
10
|
-
def initialize(*args)
|
11
|
-
super(*args)
|
12
|
-
prepare
|
13
|
-
end
|
14
|
-
|
8
|
+
# matcher behavior
|
9
|
+
module Matcher
|
15
10
|
def self.prepare_re_pattern(value, options, case_sensitive)
|
16
11
|
res = 0
|
17
12
|
res |= Regexp::MULTILINE if options.include?('multiline')
|
18
13
|
res |= Regexp::IGNORECASE unless case_sensitive
|
19
|
-
Regexp.compile(value, res)
|
14
|
+
r = Regexp.compile(value, res)
|
15
|
+
r.match("")
|
16
|
+
r
|
20
17
|
end
|
21
18
|
|
22
19
|
ANYWHERE_OPT = 'anywhere'.freeze
|
23
|
-
def prepare
|
20
|
+
def prepare(patterns)
|
24
21
|
@string = {}
|
25
|
-
@
|
22
|
+
@regexp_patterns = []
|
26
23
|
|
27
|
-
patterns = @data['values']
|
28
24
|
if patterns.nil?
|
29
25
|
msg = "no key 'values' in data (had #{@data.keys})"
|
30
26
|
raise Sqreen::Exception, msg
|
31
27
|
end
|
32
28
|
|
33
29
|
@funs = {
|
34
|
-
ANYWHERE_OPT
|
30
|
+
ANYWHERE_OPT => lambda { |value, str| str.include?(value) },
|
35
31
|
'starts_with'.freeze => lambda { |value, str| str.start_with?(value) },
|
36
32
|
'ends_with'.freeze => lambda { |value, str| str.end_with?(value) },
|
37
33
|
'equals'.freeze => lambda { |value, str| str == value },
|
@@ -61,17 +57,18 @@ module Sqreen
|
|
61
57
|
@string[opt] = { :ci => [], :cs => [] } unless @string.key?(opt)
|
62
58
|
@string[opt][case_type] << val
|
63
59
|
|
64
|
-
when '
|
65
|
-
pattern =
|
60
|
+
when 'regexp'
|
61
|
+
pattern = Matcher.prepare_re_pattern(val, opt, case_sensitive)
|
66
62
|
next unless pattern
|
67
|
-
@
|
63
|
+
@regexp_patterns << pattern
|
64
|
+
else
|
65
|
+
raise Sqreen::Exception, "No such matcher type #{type}"
|
68
66
|
end
|
69
67
|
end
|
70
68
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
69
|
+
return unless [@regexp_patterns, @string].map(&:empty?).all?
|
70
|
+
msg = "no key 'regexp' nor 'match' in data (had #{@data.keys})"
|
71
|
+
raise Sqreen::Exception, msg
|
75
72
|
end
|
76
73
|
|
77
74
|
def match(str)
|
@@ -95,11 +92,20 @@ module Sqreen
|
|
95
92
|
end
|
96
93
|
end
|
97
94
|
|
98
|
-
@
|
95
|
+
@regexp_patterns.each do |p|
|
99
96
|
return p if p.match(str)
|
100
97
|
end
|
101
98
|
nil
|
102
99
|
end
|
103
100
|
end
|
101
|
+
|
102
|
+
# A configurable matcher rule
|
103
|
+
class MatcherRuleCB < RuleCB
|
104
|
+
def initialize(*args)
|
105
|
+
super(*args)
|
106
|
+
prepare(@data['values'])
|
107
|
+
end
|
108
|
+
include Matcher
|
109
|
+
end
|
104
110
|
end
|
105
111
|
end
|
data/lib/sqreen/version.rb
CHANGED
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.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Sqreen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- README.md
|
49
49
|
- Rakefile
|
50
50
|
- lib/sqreen.rb
|
51
|
+
- lib/sqreen/attack_detected.html
|
51
52
|
- lib/sqreen/binding_accessor.rb
|
52
53
|
- lib/sqreen/ca.crt
|
53
54
|
- lib/sqreen/call_countable.rb
|
@@ -89,10 +90,12 @@ files:
|
|
89
90
|
- lib/sqreen/rule_callback.rb
|
90
91
|
- lib/sqreen/rules.rb
|
91
92
|
- lib/sqreen/rules_callbacks.rb
|
93
|
+
- lib/sqreen/rules_callbacks/binding_accessor_matcher.rb
|
92
94
|
- lib/sqreen/rules_callbacks/binding_accessor_metrics.rb
|
93
95
|
- lib/sqreen/rules_callbacks/count_http_codes.rb
|
94
96
|
- lib/sqreen/rules_callbacks/crawler_user_agent_matches.rb
|
95
97
|
- lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb
|
98
|
+
- lib/sqreen/rules_callbacks/custom_error.rb
|
96
99
|
- lib/sqreen/rules_callbacks/execjs.rb
|
97
100
|
- lib/sqreen/rules_callbacks/headers_insert.rb
|
98
101
|
- lib/sqreen/rules_callbacks/inspect_rule.rb
|
@@ -131,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
134
|
version: '0'
|
132
135
|
requirements: []
|
133
136
|
rubyforge_project:
|
134
|
-
rubygems_version: 2.6.
|
137
|
+
rubygems_version: 2.6.11
|
135
138
|
signing_key:
|
136
139
|
specification_version: 4
|
137
140
|
summary: Sqreen Ruby agent
|