sqreen 1.8.5-java → 1.9.0-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/attack_detected.html +1 -1
- data/lib/sqreen/callbacks.rb +1 -27
- data/lib/sqreen/context.rb +4 -0
- data/lib/sqreen/deliveries/batch.rb +14 -10
- data/lib/sqreen/deliveries/simple.rb +3 -0
- data/lib/sqreen/events/request_record.rb +54 -0
- data/lib/sqreen/frameworks.rb +1 -1
- data/lib/sqreen/frameworks/generic.rb +32 -12
- data/lib/sqreen/frameworks/request_recorder.rb +68 -0
- data/lib/sqreen/payload_creator.rb +15 -37
- data/lib/sqreen/rule_callback.rb +31 -40
- data/lib/sqreen/rules.rb +1 -0
- data/lib/sqreen/rules_callbacks/execjs.rb +6 -4
- data/lib/sqreen/sdk.rb +11 -3
- data/lib/sqreen/session.rb +8 -2
- data/lib/sqreen/shared_storage.rb +32 -0
- data/lib/sqreen/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c748ad9e30a231437548b0b1b4b51262e6bb0fee
|
4
|
+
data.tar.gz: 020cb5707e74f39af595716a22a21714191a7c13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51aca80eec0d387bec06f9e43d24bcd6f2d7b9195bd94df3f92d38bc66f2a76213509ac969d7a9e8fe28957edbdc2b3298399cf5f5267701ffaa15f769ce1ce1
|
7
|
+
data.tar.gz: 950a8bc12d01a28cdaa6a3d0533d116a3573ce6cec4ce778943a9b65cb5868ff2772fe57fdfc7bcf37e24b14c67a6a927e0f7ade57b7b445d8fe6c77f3fae58f
|
@@ -1,2 +1,2 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Sqreen has detected an attack.</title> <style>html,body,div,span,h1,a{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}body{background
|
1
|
+
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Sqreen has detected an attack.</title> <style>html, body, div, span, h1, a{margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline}body{background: -webkit-radial-gradient(26% 19%, circle, #fff, #f4f7f9); background: radial-gradient(circle at 26% 19%, #fff, #f4f7f9); display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; -ms-flex-line-pack: center; align-content: center; width: 100%; min-height: 100vh; line-height: 1}svg, h1, p{display: block}svg{margin: 0 auto 4vh}h1{font-family: sans-serif; font-weight: 300; font-size: 34px; color: #384886; line-height: normal}p{font-size: 18px; line-height: normal; color: #b8bccc; font-family: sans-serif; font-weight: 300}a{color: #b8bccc}.flex{text-align: center}</style></head><body> <div class="flex"> <svg xmlns="http://www.w3.org/2000/svg" width="230" height="250" viewBox="0 0 230 250" enable-background="new 0 0 230 250"> <style>.st0{opacity: 0.4; filter: url(#a);}.st1{fill: #FFFFFF;}.st2{fill: #B0ACFF;}.st3{fill: #4842B7;}.st4{fill: #1E0936;}</style> <filter id="a" width="151.7%" height="146%" x="-25.8%" y="-16%" filterUnits="objectBoundingBox"> <feOffset dy="14" in="SourceAlpha" result="shadowOffsetOuter1"/> <feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="13"/> <feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/> </filter> <g class="st0"> <path id="b_2_" d="M202.6 34.9c-.2-1.2-.8-2.1-1.9-2.8-3.8-2-37.9-20.1-85.7-20.1-48.8 0-84.2 19.3-85.7 20.1-1 .6-1.6 1.6-1.8 2.7-14.8 123.2 84.7 176.3 85.7 176.8.6.3 1.2.4 1.8.4.6 0 1.2-.1 1.7-.4 1-.5 100.4-55 85.9-176.7z"/> </g> <path id="b_1_" d="M202.6 34.9c-.2-1.2-.8-2.1-1.9-2.8-3.8-2-37.9-20.1-85.7-20.1-48.8 0-84.2 19.3-85.7 20.1-1 .6-1.6 1.6-1.8 2.7-14.8 123.2 84.7 176.3 85.7 176.8.6.3 1.2.4 1.8.4.6 0 1.2-.1 1.7-.4 1-.5 100.4-55 85.9-176.7z" class="st1"/> <g id="nest-cmyk-indigo"> <ellipse id="sqreen" cx="115.5" cy="69.9" class="st2" rx="12.7" ry="12.7"/> <path id="app" d="M113.6 91.9V71.5L95.5 61.1v18l6.4-3.7c.5 1.1 1 2.2 1.7 3.2L97 82.3l16.6 9.6zm3.7 0l16.6-9.6-6.7-3.9c.7-1 1.3-2 1.7-3.2l6.4 3.7v-18l-18.1 10.5v20.5zM96.9 57.6l18.6 10.7L134 57.6 117.3 48v7.6c-.6-.1-1.2-.1-1.8-.1-.6 0-1.2 0-1.8.1V48l-16.8 9.6zm20.2-13.9l20.3 11.7c1 .6 1.6 1.7 1.6 2.8v23.5c0 1.2-.6 2.2-1.6 2.8l-20.3 11.7c-1 .6-2.3.6-3.3 0L93.5 84.5c-1-.6-1.6-1.7-1.6-2.8V58.2c0-1.2.6-2.2 1.6-2.8l20.3-11.7c1-.6 2.3-.6 3.3 0z" class="st3"/> </g> <path id="s" d="M74.6 113c-1.8-1-3.5-1.5-5.2-1.5-1.4 0-2.3.6-2.3 1.5 0 2.7 10.1.4 10.1 7.7 0 3.3-2.9 6-7.6 6-2.1 0-4.7-.5-6.4-1.4l-.1-.1c-.3-.2-.3-.5-.2-.8l1.2-2.7c.1-.3.5-.5.9-.3.1 0 .1.1.2.1 1.5.6 3.1 1 4.6 1 2.2 0 2.9-.6 2.9-1.7 0-3-10.1-.8-10.1-7.7 0-3.1 2.7-5.8 7-5.8 2.1 0 5 .7 6.9 1.8.1 0 .1.1.2.1.3.2.4.5.3.8l-1.2 2.7c-.1.3-.5.5-.9.3h-.3z" class="st4"/> <path id="q" d="M93.6 107.8h3.2c.4 0 .7.3.7.7v25.9c0 .4-.3.7-.7.7h-3.2c-.4 0-.7-.3-.7-.7v-9.1c-1.2.8-2.9 1.4-4.7 1.4-5.4 0-9.6-4.3-9.6-9.7 0-5.4 4.1-9.7 9.6-9.7 1.8 0 3.5.6 4.7 1.4v-.1c0-.5.3-.8.7-.8zm-.7 12.4v-6.5c-1.3-1.3-2.8-2.1-4.5-2.1-2.9 0-5.1 2.3-5.1 5.4s2.2 5.4 5.1 5.4c1.7-.1 3.2-.7 4.5-2.2z" class="st4"/> <path id="r" d="M112.5 107.8c-1-.4-2-.6-3-.6-1.8 0-3.5.6-4.9 1.4v-.2c0-.3-.2-.5-.5-.5h-3.4c-.3 0-.5.2-.5.5v17.8c0 .3.2.5.5.5h3.4c.3 0 .5-.2.5-.5v-12.6c1.1-1.2 2.8-1.9 4.6-1.9.4 0 .9 0 1.5.2.3.1.6-.1.7-.4l1.3-2.9c.1-.4 0-.7-.2-.8z" class="st4"/> <path id="e" d="M129 124.7c-1.7 1-4.2 2-6.7 2-6 0-10.3-4.4-10.3-9.9 0-5.3 3.7-9.6 9.4-9.6 5.2 0 8.4 4.4 8.4 9 0 .4 0 .9-.1 1.2 0 .3-.3.6-.7.6h-12.5c.5 2.8 2.8 4.5 5.8 4.5 1.7 0 3.4-.5 5.1-1.4.3-.2.6-.1.8.2l1.2 2.6c.1.2 0 .4-.2.6-.2.1-.2.2-.2.2zm-12.4-10h8.5c-.2-1.8-1.9-3.3-3.9-3.3-2.5-.1-4 1.4-4.6 3.3z" class="st4"/> <path id="e_1_" d="M148.7 124.7c-1.7 1-4.2 2-6.7 2-6 0-10.3-4.4-10.3-9.9 0-5.3 3.7-9.6 9.4-9.6 5.2 0 8.4 4.4 8.4 9 0 .4 0 .9-.1 1.2 0 .3-.3.6-.7.6h-12.5c.5 2.8 2.8 4.5 5.8 4.5 1.7 0 3.4-.5 5.1-1.4.3-.2.6-.1.8.2l1.2 2.6c.1.2 0 .4-.2.6-.2.1-.2.2-.2.2zm-12.4-10h8.5c-.2-1.8-1.9-3.3-3.9-3.3-2.5-.1-4 1.4-4.6 3.3z" class="st4"/> <path id="n" d="M151.5 108.5V126c0 .4.3.7.7.7h3.2c.4 0 .7-.3.7-.7v-12.5c1.1-1.2 2.8-1.9 4.6-1.9 2.9 0 4.5 1.6 4.5 4.7v9.7c0 .4.3.7.7.7h3.2c.4 0 .7-.3.7-.7v-10.2c0-5.2-2.9-8.5-8.8-8.5-1.8 0-3.5.6-4.9 1.4v-.1c0-.4-.3-.7-.7-.7h-3.2c-.4-.1-.7.2-.7.6z" class="st4"/> </svg> <h1>Uh Oh! Sqreen has detected an attack.</h1> <p>If you are the application owner, check the Sqreen <a href="https://my.sqreen.io/">dashboard</a> for more information.</p></div></body></html>
|
2
2
|
|
data/lib/sqreen/callbacks.rb
CHANGED
@@ -2,35 +2,9 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
require 'set'
|
5
|
+
require 'sqreen/shared_storage'
|
5
6
|
|
6
7
|
module Sqreen
|
7
|
-
module SharedStorage
|
8
|
-
@@shared = {}
|
9
|
-
|
10
|
-
def self::get(key, default = nil)
|
11
|
-
h = @@shared[Thread.current]
|
12
|
-
return h.fetch(key, default) if h
|
13
|
-
default
|
14
|
-
end
|
15
|
-
|
16
|
-
def self::set(key, obj)
|
17
|
-
main_key = Thread.current
|
18
|
-
@@shared[main_key] = {} unless @@shared.key? main_key
|
19
|
-
@@shared[main_key][key] = obj
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.clear
|
23
|
-
@@shared.delete(Thread.current)
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.inc(value)
|
27
|
-
set(value, get(value, 0) + 1)
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.dec(value)
|
31
|
-
set(value, get(value, 0) - 1)
|
32
|
-
end
|
33
|
-
end
|
34
8
|
|
35
9
|
class CB
|
36
10
|
# Callback class.
|
data/lib/sqreen/context.rb
CHANGED
@@ -8,7 +8,7 @@ module Sqreen
|
|
8
8
|
# Simple delivery method that batch event already seen in a batch
|
9
9
|
class Batch < Simple
|
10
10
|
attr_accessor :max_batch, :max_staleness
|
11
|
-
attr_accessor :current_batch
|
11
|
+
attr_accessor :current_batch, :first_seen
|
12
12
|
|
13
13
|
def initialize(session,
|
14
14
|
max_batch,
|
@@ -40,18 +40,17 @@ module Sqreen
|
|
40
40
|
|
41
41
|
def stale?
|
42
42
|
min = @first_seen.values.min
|
43
|
+
return false if min.nil?
|
43
44
|
(min + max_staleness) < Time.now
|
44
45
|
end
|
45
46
|
|
46
47
|
def post_batch_needed?(event)
|
47
|
-
key = event_key(event)
|
48
|
-
was = @first_seen[key]
|
49
48
|
now = Time.now
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
event_keys(event).map do |key|
|
50
|
+
was = @first_seen[key]
|
51
|
+
@first_seen[key] ||= now
|
52
|
+
was.nil? || current_batch.size > max_batch || (was + max_staleness) < now
|
53
|
+
end.any?
|
55
54
|
end
|
56
55
|
|
57
56
|
def post_batch
|
@@ -67,12 +66,17 @@ module Sqreen
|
|
67
66
|
self.max_staleness += rand(@original_max_staleness / 10)
|
68
67
|
end
|
69
68
|
|
69
|
+
def event_keys(event)
|
70
|
+
return [event_key(event)] unless event.is_a?(Sqreen::RequestRecord)
|
71
|
+
event.observed.fetch(:attacks, []).map { |e| "att-#{e[:rule_name]}" } + event.observed.fetch(:sqreen_exceptions, []).map { |e| "rex-#{e[:exception].class}" }
|
72
|
+
end
|
73
|
+
|
70
74
|
def event_key(event)
|
71
75
|
case event
|
72
76
|
when Sqreen::Attack
|
73
|
-
|
77
|
+
"att-#{event.type}"
|
74
78
|
when Sqreen::RemoteException
|
75
|
-
|
79
|
+
"rex-#{event.klass}"
|
76
80
|
end
|
77
81
|
end
|
78
82
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
require 'sqreen/events/remote_exception'
|
5
|
+
require 'sqreen/events/request_record'
|
5
6
|
|
6
7
|
module Sqreen
|
7
8
|
module Deliveries
|
@@ -19,6 +20,8 @@ module Sqreen
|
|
19
20
|
session.post_attack(event)
|
20
21
|
when Sqreen::RemoteException
|
21
22
|
session.post_sqreen_exception(event)
|
23
|
+
when Sqreen::RequestRecord
|
24
|
+
session.post_request_record(event)
|
22
25
|
else
|
23
26
|
session.post_event(event)
|
24
27
|
end
|
@@ -0,0 +1,54 @@
|
|
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 'json'
|
5
|
+
require 'sqreen/event'
|
6
|
+
|
7
|
+
module Sqreen
|
8
|
+
# When a request is deeemed worthy of being sent to the backend
|
9
|
+
class RequestRecord < Sqreen::Event
|
10
|
+
def observed
|
11
|
+
(payload && payload[:observed]) || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
res = { :version => '20171208' }
|
16
|
+
if payload[:observed]
|
17
|
+
res[:observed] = payload[:observed]
|
18
|
+
rulespack = nil
|
19
|
+
observed.fetch(:attacks, []).each do |att|
|
20
|
+
rulespack = att.delete(:rulespack_id) || rulespack
|
21
|
+
end
|
22
|
+
observed.fetch(:sqreen_exceptions, []).each do |exc|
|
23
|
+
excp = exc.delete(:exception)
|
24
|
+
if excp
|
25
|
+
exc[:message] = excp.message
|
26
|
+
exc[:klass] = excp.class.name
|
27
|
+
end
|
28
|
+
rulespack = exc.delete(:rulespack_id) || rulespack
|
29
|
+
end
|
30
|
+
res[:rulespack_id] = rulespack unless rulespack.nil?
|
31
|
+
if observed[:observations]
|
32
|
+
res[:observed][:observations] = observed[:observations].map do |cat, key, value, time|
|
33
|
+
{ :category => cat, :key => key, :value => value, :time => time }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
if observed[:sdk]
|
37
|
+
payload[:observed][:sdk] = observed[:sdk].map do |meth, time, *args|
|
38
|
+
{ :name => meth, :time => time, :args => args }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
res[:local] = payload['local'] if payload['local']
|
43
|
+
if payload['request']
|
44
|
+
res[:request] = payload['request']
|
45
|
+
res[:client_ip] = res[:request].delete(:client_ip) if res[:request][:client_ip]
|
46
|
+
else
|
47
|
+
res[:request] = {}
|
48
|
+
end
|
49
|
+
res[:request][:parameters] = payload['params'] if payload['params']
|
50
|
+
res[:request][:headers] = payload['headers'] if payload['headers']
|
51
|
+
res
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/sqreen/frameworks.rb
CHANGED
@@ -6,11 +6,13 @@ require 'sqreen/events/remote_exception'
|
|
6
6
|
require 'sqreen/callbacks'
|
7
7
|
require 'sqreen/exception'
|
8
8
|
require 'sqreen/log'
|
9
|
+
require 'sqreen/frameworks/request_recorder'
|
9
10
|
|
10
11
|
module Sqreen
|
11
12
|
module Frameworks
|
12
13
|
# This is the base class for framework specific code
|
13
14
|
class GenericFramework
|
15
|
+
include RequestRecorder
|
14
16
|
attr_accessor :sqreen_configuration
|
15
17
|
|
16
18
|
def initialize
|
@@ -19,6 +21,7 @@ module Sqreen
|
|
19
21
|
else
|
20
22
|
to_app_done(Process.pid)
|
21
23
|
end
|
24
|
+
clean_request_record
|
22
25
|
end
|
23
26
|
|
24
27
|
# What kind of database is this
|
@@ -40,13 +43,16 @@ module Sqreen
|
|
40
43
|
ENV['RACK_ENV'] == 'development'
|
41
44
|
end
|
42
45
|
|
46
|
+
PREFFERED_IP_HEADERS = %w(HTTP_X_FORWARDED_FOR HTTP_X_REAL_IP
|
47
|
+
HTTP_CLIENT_IP HTTP_X_FORWARDED
|
48
|
+
HTTP_X_CLUSTER_CLIENT_IP HTTP_FORWARDED_FOR
|
49
|
+
HTTP_FORWARDED HTTP_VIA).freeze
|
50
|
+
|
43
51
|
def ip_headers
|
44
52
|
req = request
|
45
53
|
return [] unless req
|
46
54
|
ips = []
|
47
|
-
|
48
|
-
HTTP_X_CLUSTER_CLIENT_IP HTTP_FORWARDED_FOR HTTP_FORWARDED HTTP_VIA
|
49
|
-
REMOTE_ADDR).each do |header|
|
55
|
+
(PREFFERED_IP_HEADERS + ['REMOTE_ADDR']).each do |header|
|
50
56
|
v = req.env[header]
|
51
57
|
ips << [header, v] unless v.nil?
|
52
58
|
end
|
@@ -71,16 +77,22 @@ module Sqreen
|
|
71
77
|
req = request
|
72
78
|
return nil unless req
|
73
79
|
# Look for an external address being forwarded
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
80
|
+
split_ips = []
|
81
|
+
PREFFERED_IP_HEADERS.each do |header_name|
|
82
|
+
forwarded = req.env[header_name]
|
83
|
+
ips = split_ip_addresses(forwarded)
|
84
|
+
lip = ips.find { |ip| (ip !~ TRUSTED_PROXIES) && valid_ip?(ip) }
|
85
|
+
split_ips << ips unless ips.empty?
|
86
|
+
return lip unless lip.nil?
|
87
|
+
end
|
78
88
|
# Else fall back to declared remote addr
|
79
89
|
r = req.env['REMOTE_ADDR']
|
80
90
|
# If this is localhost get the last hop before
|
81
|
-
if
|
82
|
-
|
83
|
-
|
91
|
+
if r.nil? || r =~ LOCALHOST
|
92
|
+
split_ips.each do |ips|
|
93
|
+
lip = ips.find { |ip| (ip !~ LOCALHOST) && valid_ip?(ip) }
|
94
|
+
return lip unless lip.nil?
|
95
|
+
end
|
84
96
|
end
|
85
97
|
r
|
86
98
|
end
|
@@ -124,10 +136,11 @@ module Sqreen
|
|
124
136
|
:verb => req.env['REQUEST_METHOD'],
|
125
137
|
:host => hostname,
|
126
138
|
:port => req.env['SERVER_PORT'],
|
127
|
-
:rport => req.env['REMOTE_PORT'],
|
128
139
|
:referer => req.env['HTTP_REFERER'],
|
129
140
|
:path => request_path,
|
130
|
-
:
|
141
|
+
:remote_port => req.env['REMOTE_PORT'],
|
142
|
+
:remote_ip => remote_addr,
|
143
|
+
:client_ip => client_ip,
|
131
144
|
}
|
132
145
|
end
|
133
146
|
|
@@ -221,6 +234,8 @@ module Sqreen
|
|
221
234
|
# Cleanup request context
|
222
235
|
def clean_request
|
223
236
|
return unless SharedStorage.dec(:stored_requests) <= 0
|
237
|
+
payload_creator = Sqreen::PayloadCreator.new(self)
|
238
|
+
close_request_record(Sqreen.queue, Sqreen.observations_queue, payload_creator)
|
224
239
|
SharedStorage.set(:request, nil)
|
225
240
|
end
|
226
241
|
|
@@ -327,6 +342,11 @@ module Sqreen
|
|
327
342
|
nil
|
328
343
|
end
|
329
344
|
|
345
|
+
def remote_addr
|
346
|
+
return nil unless request
|
347
|
+
request.env['REMOTE_ADDR']
|
348
|
+
end
|
349
|
+
|
330
350
|
protected
|
331
351
|
|
332
352
|
# Is this a whitelisted path?
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
|
+
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
|
+
require 'set'
|
4
|
+
require 'sqreen/shared_storage'
|
5
|
+
require 'sqreen/events/request_record'
|
6
|
+
|
7
|
+
module Sqreen
|
8
|
+
# Store event/observations that happened in this request
|
9
|
+
module RequestRecorder
|
10
|
+
def observed_items
|
11
|
+
SharedStorage.get(:observed_items)
|
12
|
+
end
|
13
|
+
|
14
|
+
def observed_items=(value)
|
15
|
+
SharedStorage.set(:observed_items, value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def payload_requests
|
19
|
+
SharedStorage.get(:payload_requests)
|
20
|
+
end
|
21
|
+
|
22
|
+
def payload_requests=(value)
|
23
|
+
SharedStorage.set(:payload_requests, value)
|
24
|
+
end
|
25
|
+
|
26
|
+
def only_metric_observation
|
27
|
+
SharedStorage.get(:only_metric_observation)
|
28
|
+
end
|
29
|
+
|
30
|
+
def only_metric_observation=(value)
|
31
|
+
SharedStorage.set(:only_metric_observation, value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def clean_request_record
|
35
|
+
self.only_metric_observation = true
|
36
|
+
self.payload_requests = Set.new
|
37
|
+
self.observed_items = Hash.new { |hash, key| hash[key] = [] }
|
38
|
+
end
|
39
|
+
|
40
|
+
def observe(what, data, accessors = [], report = true)
|
41
|
+
clean_request_record if observed_items.nil?
|
42
|
+
self.only_metric_observation = false if report
|
43
|
+
observed_items[what] << data
|
44
|
+
payload_requests.merge(accessors)
|
45
|
+
end
|
46
|
+
|
47
|
+
def close_request_record(queue, observations_queue, payload_creator)
|
48
|
+
if only_metric_observation
|
49
|
+
push_metrics(observations_queue, queue)
|
50
|
+
return clean_request_record
|
51
|
+
end
|
52
|
+
payload = payload_creator.payload(payload_requests)
|
53
|
+
payload[:observed] = observed_items
|
54
|
+
queue.push RequestRecord.new(payload)
|
55
|
+
clean_request_record
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def push_metrics(observations_queue, event_queue)
|
61
|
+
observed_items[:observations].each do |obs|
|
62
|
+
observations_queue.push obs
|
63
|
+
end
|
64
|
+
return unless observations_queue.size > MAX_OBS_QUEUE_LENGTH / 2
|
65
|
+
event_queue.push Sqreen::METRICS_EVENT
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -1,7 +1,6 @@
|
|
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
|
|
4
|
-
require 'sqreen/context'
|
5
4
|
require 'sqreen/runtime_infos'
|
6
5
|
require 'sqreen/events/remote_exception'
|
7
6
|
|
@@ -15,8 +14,9 @@ module Sqreen
|
|
15
14
|
# The payload will always be outputed as a
|
16
15
|
# Hash of section => subsection.
|
17
16
|
class PayloadCreator
|
18
|
-
|
19
|
-
|
17
|
+
attr_reader :framework
|
18
|
+
def initialize(framework)
|
19
|
+
@framework = framework
|
20
20
|
end
|
21
21
|
|
22
22
|
def query=(keys)
|
@@ -30,24 +30,25 @@ module Sqreen
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def payload(
|
33
|
+
def payload(query)
|
34
|
+
self.query = query
|
34
35
|
ret = {}
|
35
36
|
METHODS.each_key do |section|
|
36
|
-
ret = fill(section, ret, framework
|
37
|
+
ret = fill(section, ret, @framework)
|
37
38
|
end
|
38
39
|
ret
|
39
40
|
end
|
40
41
|
|
41
42
|
protected
|
42
43
|
|
43
|
-
def fill(key, base, framework
|
44
|
+
def fill(key, base, framework)
|
44
45
|
subsection = @sections[key]
|
45
46
|
return base if subsection.nil?
|
46
47
|
if subsection == true
|
47
|
-
return base.merge!(key => full_section(key, framework
|
48
|
+
return base.merge!(key => full_section(key, framework))
|
48
49
|
end
|
49
50
|
return base if subsection.empty?
|
50
|
-
base[key] = fields(key, framework
|
51
|
+
base[key] = fields(key, framework)
|
51
52
|
base
|
52
53
|
end
|
53
54
|
|
@@ -72,33 +73,25 @@ module Sqreen
|
|
72
73
|
'cookies' => 'cookies_params',
|
73
74
|
'rails' => 'rails_params',
|
74
75
|
},
|
75
|
-
'rule' => {},
|
76
76
|
'headers' => {},
|
77
|
-
'context' => {
|
78
|
-
'backtrace' => 'get_current_backtrace',
|
79
|
-
},
|
80
77
|
}.freeze
|
81
78
|
|
82
|
-
def section_object(section, framework
|
79
|
+
def section_object(section, framework)
|
83
80
|
return RuntimeInfos if section == 'local'
|
84
|
-
return rule if section == 'rule'
|
85
|
-
return Context.new if section == 'context'
|
86
81
|
return HeaderSection.new(framework) if section == 'headers'
|
87
82
|
framework
|
88
83
|
end
|
89
84
|
|
90
|
-
def full_section(section, framework
|
91
|
-
return section_rule(framework, rule) if section == 'rule'
|
92
|
-
return section_context(framework, rule) if section == 'context'
|
85
|
+
def full_section(section, framework)
|
93
86
|
# fast path prevent initializing a HeaderSection
|
94
87
|
return framework.ip_headers if section == 'headers'
|
95
|
-
so = section_object(section, framework
|
88
|
+
so = section_object(section, framework)
|
96
89
|
so.send(FULL_SECTIONS[section])
|
97
90
|
end
|
98
91
|
|
99
|
-
def fields(section, framework
|
92
|
+
def fields(section, framework)
|
100
93
|
out = {}
|
101
|
-
object = section_object(section, framework
|
94
|
+
object = section_object(section, framework)
|
102
95
|
remove = []
|
103
96
|
@sections[section].each do |key|
|
104
97
|
meth = METHODS[section][key]
|
@@ -119,21 +112,6 @@ module Sqreen
|
|
119
112
|
Sqreen::RemoteException.record(e)
|
120
113
|
end
|
121
114
|
|
122
|
-
def section_context(framework, rule)
|
123
|
-
obj = section_object('context', framework, rule)
|
124
|
-
{
|
125
|
-
'backtrace' => obj.get_current_backtrace,
|
126
|
-
}
|
127
|
-
end
|
128
|
-
|
129
|
-
def section_rule(_framework, rule)
|
130
|
-
{
|
131
|
-
'name' => rule['name'],
|
132
|
-
'rulespack_id' => rule['rulespack_id'],
|
133
|
-
'test' => rule['test'],
|
134
|
-
}
|
135
|
-
end
|
136
|
-
|
137
115
|
# object that default to call on framework header
|
138
116
|
class HeaderSection
|
139
117
|
def initialize(framework)
|
@@ -141,7 +119,7 @@ module Sqreen
|
|
141
119
|
end
|
142
120
|
|
143
121
|
def [](value)
|
144
|
-
if %w
|
122
|
+
if %w[rack_client_ip rails_client_ip ip_headers].include?(value)
|
145
123
|
return @framework.send(value)
|
146
124
|
end
|
147
125
|
@framework.header(value)
|
data/lib/sqreen/rule_callback.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.io/terms.html
|
3
3
|
|
4
4
|
require 'sqreen/callbacks'
|
5
|
+
require 'sqreen/context'
|
5
6
|
require 'sqreen/conditionable'
|
6
7
|
require 'sqreen/call_countable'
|
7
8
|
require 'sqreen/rule_attributes'
|
@@ -18,8 +19,9 @@ module Sqreen
|
|
18
19
|
include CallCountable
|
19
20
|
# If nothing was asked by the rule we will ask for all sections available
|
20
21
|
# These information will be pruned later when exporting in #to_hash
|
21
|
-
DEFAULT_PAYLOAD = PayloadCreator::METHODS.keys.freeze
|
22
|
+
DEFAULT_PAYLOAD = (PayloadCreator::METHODS.keys - ['local'] + ['context']).freeze
|
22
23
|
attr_reader :test
|
24
|
+
attr_reader :payload_tpl
|
23
25
|
attr_reader :block
|
24
26
|
attr_accessor :framework
|
25
27
|
|
@@ -32,8 +34,7 @@ module Sqreen
|
|
32
34
|
@test = rule_hash[Attrs::TEST] == true
|
33
35
|
@data = rule_hash[Attrs::DATA]
|
34
36
|
@rule = rule_hash
|
35
|
-
payload_tpl = @rule[Attrs::PAYLOAD] || DEFAULT_PAYLOAD
|
36
|
-
@payload_generator = PayloadCreator.new(payload_tpl)
|
37
|
+
@payload_tpl = @rule[Attrs::PAYLOAD] || DEFAULT_PAYLOAD
|
37
38
|
condition_callbacks(@rule[Attrs::CONDITIONS])
|
38
39
|
count_callback_calls(@rule[Attrs::CALL_COUNT_INTERVAL])
|
39
40
|
end
|
@@ -61,10 +62,19 @@ module Sqreen
|
|
61
62
|
|
62
63
|
# Record an attack event into Sqreen system
|
63
64
|
# @param infos [Hash] Additional information about request
|
64
|
-
def record_event(infos)
|
65
|
-
|
66
|
-
payload
|
67
|
-
|
65
|
+
def record_event(infos, at = Time.now.utc)
|
66
|
+
return unless framework
|
67
|
+
payload = {
|
68
|
+
:infos => infos,
|
69
|
+
:rulespack_id => rulespack_id,
|
70
|
+
:rule_name => rule_name,
|
71
|
+
:test => test,
|
72
|
+
:time => at,
|
73
|
+
}
|
74
|
+
if payload_tpl.include?('context')
|
75
|
+
payload[:backtrace] = Sqreen::Context.new.bt
|
76
|
+
end
|
77
|
+
framework.observe(:attacks, payload, payload_tpl)
|
68
78
|
end
|
69
79
|
|
70
80
|
# Record a metric observation
|
@@ -73,44 +83,25 @@ module Sqreen
|
|
73
83
|
# @param observation [Object] data observed
|
74
84
|
# @param at [Time] time when observation was made
|
75
85
|
def record_observation(category, key, observation, at = Time.now.utc)
|
76
|
-
|
77
|
-
|
78
|
-
Sqreen.queue.push Sqreen::METRICS_EVENT
|
79
|
-
end
|
86
|
+
return unless framework
|
87
|
+
framework.observe(:observations, [category, key, observation, at], [], false)
|
80
88
|
end
|
81
89
|
|
82
90
|
# Record an exception that just occurred
|
83
91
|
# @param exception [Exception] Exception to send over
|
84
92
|
# @param infos [Hash] Additional contextual information
|
85
|
-
def record_exception(exception, infos = {})
|
86
|
-
|
87
|
-
payload
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
rescue => e
|
98
|
-
Sqreen.log.debug("No framework request params #{e}")
|
99
|
-
end
|
100
|
-
payload['time'] = Time.now.utc
|
101
|
-
payload['infos'] = infos
|
102
|
-
payload['backtrace'] = Sqreen::Context.new.bt
|
103
|
-
begin
|
104
|
-
payload['client_ip'] = framework.client_ip.to_s
|
105
|
-
rescue => e
|
106
|
-
Sqreen.log.debug("No framework client_ip #{e}")
|
107
|
-
end
|
108
|
-
begin
|
109
|
-
payload['headers'] = framework.ip_headers
|
110
|
-
rescue => e
|
111
|
-
Sqreen.log.debug("No framework ip_headers #{e}")
|
112
|
-
end
|
113
|
-
RemoteException.record(payload)
|
93
|
+
def record_exception(exception, infos = {}, at = Time.now.utc)
|
94
|
+
return unless framework
|
95
|
+
payload = {
|
96
|
+
:exception => exception,
|
97
|
+
:infos => infos,
|
98
|
+
:rulespack_id => rulespack_id,
|
99
|
+
:rule_name => rule_name,
|
100
|
+
:test => test,
|
101
|
+
:time => at,
|
102
|
+
:backtrace => exception.backtrace || Sqreen::Context.bt,
|
103
|
+
}
|
104
|
+
framework.observe(:sqreen_exceptions, payload)
|
114
105
|
end
|
115
106
|
end
|
116
107
|
end
|
data/lib/sqreen/rules.rb
CHANGED
@@ -19,6 +19,7 @@ module Sqreen
|
|
19
19
|
module Rules
|
20
20
|
# Exec js callbacks
|
21
21
|
class ExecJSCB < RuleCB
|
22
|
+
attr_accessor :restrict_max_depth
|
22
23
|
def initialize(klass, method, rule_hash)
|
23
24
|
super(klass, method, rule_hash)
|
24
25
|
callbacks = @rule[Attrs::CALLBACKS]
|
@@ -32,6 +33,7 @@ module Sqreen
|
|
32
33
|
|
33
34
|
build_runnable(callbacks)
|
34
35
|
@compiled = ExecJS.compile(@source)
|
36
|
+
@restrict_max_depth = 20
|
35
37
|
end
|
36
38
|
|
37
39
|
def pre?
|
@@ -97,12 +99,11 @@ module Sqreen
|
|
97
99
|
insert.reverse.each do |wh, ikey, ival|
|
98
100
|
case wh
|
99
101
|
when Array
|
100
|
-
wh << ival unless ival.empty?
|
102
|
+
wh << ival unless ival.respond_to?(:empty?) && ival.empty?
|
101
103
|
else
|
102
|
-
wh[ikey] = ival unless ival.empty?
|
104
|
+
wh[ikey] = ival unless ival.respond_to?(:empty?) && ival.empty?
|
103
105
|
end
|
104
106
|
end
|
105
|
-
|
106
107
|
new_obj
|
107
108
|
end
|
108
109
|
|
@@ -184,7 +185,8 @@ module Sqreen
|
|
184
185
|
arguments[haystack_idx] = ExecJSCB.hash_val_included(
|
185
186
|
arguments[needed_idx],
|
186
187
|
arguments[haystack_idx],
|
187
|
-
min_length.to_i
|
188
|
+
min_length.to_i,
|
189
|
+
@restrict_max_depth
|
188
190
|
)
|
189
191
|
end
|
190
192
|
|
data/lib/sqreen/sdk.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
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
|
|
4
|
+
# Sqreen Namespace
|
4
5
|
module Sqreen
|
5
6
|
# Sqreen SDK
|
6
7
|
class << self
|
7
8
|
# Authentication tracking method
|
8
|
-
def auth_track(is_logged_in, authentication_keys)
|
9
|
-
|
9
|
+
def auth_track(is_logged_in, authentication_keys); end
|
10
|
+
|
11
|
+
def signup_track(authentication_keys); end
|
10
12
|
|
11
|
-
def
|
13
|
+
def identify(authentication_keys, traits = {})
|
14
|
+
return unless Sqreen.framework
|
15
|
+
Sqreen.framework.observe(
|
16
|
+
:sdk,
|
17
|
+
[:identify, Time.now, authentication_keys, traits],
|
18
|
+
[], false
|
19
|
+
)
|
12
20
|
end
|
13
21
|
end
|
14
22
|
end
|
data/lib/sqreen/session.rb
CHANGED
@@ -5,6 +5,8 @@ require 'sqreen/log'
|
|
5
5
|
require 'sqreen/serializer'
|
6
6
|
require 'sqreen/runtime_infos'
|
7
7
|
require 'sqreen/events/remote_exception'
|
8
|
+
require 'sqreen/events/attack'
|
9
|
+
require 'sqreen/events/request_record'
|
8
10
|
require 'sqreen/exception'
|
9
11
|
require 'sqreen/safe_json'
|
10
12
|
|
@@ -159,8 +161,7 @@ module Sqreen
|
|
159
161
|
connect unless connected?
|
160
162
|
headers['X-Session-Key'] = @session_id if @session_id
|
161
163
|
headers['X-Sqreen-Time'] = Time.now.utc.to_f.to_s
|
162
|
-
headers['
|
163
|
-
headers['User-Agent'] = "Ruby/#{Sqreen::VERSION}"
|
164
|
+
headers['User-Agent'] = "sqreen-ruby/#{Sqreen::VERSION}"
|
164
165
|
headers['X-Sqreen-Beta'] = format('pid=%d;tid=%s;nb=%d;t=%f',
|
165
166
|
Process.pid,
|
166
167
|
thread_id,
|
@@ -263,6 +264,10 @@ module Sqreen
|
|
263
264
|
'dependencies' => dependencies)
|
264
265
|
end
|
265
266
|
|
267
|
+
def post_request_record(request_record)
|
268
|
+
resilient_post('request_record', request_record.to_hash)
|
269
|
+
end
|
270
|
+
|
266
271
|
# Post an exception to Sqreen for analysis
|
267
272
|
# @param exception [RemoteException] Exception and context to be sent over
|
268
273
|
def post_sqreen_exception(exception)
|
@@ -305,6 +310,7 @@ module Sqreen
|
|
305
310
|
case event
|
306
311
|
when Sqreen::RemoteException then 'sqreen_exception'
|
307
312
|
when Sqreen::Attack then 'attack'
|
313
|
+
when Sqreen::RequestRecord then 'request_record'
|
308
314
|
end
|
309
315
|
end
|
310
316
|
end
|
@@ -0,0 +1,32 @@
|
|
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
|
+
module Sqreen
|
5
|
+
module SharedStorage
|
6
|
+
@@shared = {}
|
7
|
+
|
8
|
+
def self::get(key, default = nil)
|
9
|
+
h = @@shared[Thread.current]
|
10
|
+
return h.fetch(key, default) if h
|
11
|
+
default
|
12
|
+
end
|
13
|
+
|
14
|
+
def self::set(key, obj)
|
15
|
+
main_key = Thread.current
|
16
|
+
@@shared[main_key] = {} unless @@shared.key? main_key
|
17
|
+
@@shared[main_key][key] = obj
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.clear
|
21
|
+
@@shared.delete(Thread.current)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.inc(value)
|
25
|
+
set(value, get(value, 0) + 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.dec(value)
|
29
|
+
set(value, get(value, 0) - 1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
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.9.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Sqreen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -64,11 +64,13 @@ files:
|
|
64
64
|
- lib/sqreen/event.rb
|
65
65
|
- lib/sqreen/events/attack.rb
|
66
66
|
- lib/sqreen/events/remote_exception.rb
|
67
|
+
- lib/sqreen/events/request_record.rb
|
67
68
|
- lib/sqreen/exception.rb
|
68
69
|
- lib/sqreen/frameworks.rb
|
69
70
|
- lib/sqreen/frameworks/generic.rb
|
70
71
|
- lib/sqreen/frameworks/rails.rb
|
71
72
|
- lib/sqreen/frameworks/rails3.rb
|
73
|
+
- lib/sqreen/frameworks/request_recorder.rb
|
72
74
|
- lib/sqreen/frameworks/sinatra.rb
|
73
75
|
- lib/sqreen/frameworks/sqreen_test.rb
|
74
76
|
- lib/sqreen/instrumentation.rb
|
@@ -115,6 +117,7 @@ files:
|
|
115
117
|
- lib/sqreen/sdk.rb
|
116
118
|
- lib/sqreen/serializer.rb
|
117
119
|
- lib/sqreen/session.rb
|
120
|
+
- lib/sqreen/shared_storage.rb
|
118
121
|
- lib/sqreen/stats.rb
|
119
122
|
- lib/sqreen/version.rb
|
120
123
|
homepage: https://www.sqreen.io/
|