sqreen 1.8.5-java → 1.9.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
  SHA1:
3
- metadata.gz: 5e1e52d6cf9228df5024c1fd53a95b4bf48c6a1e
4
- data.tar.gz: 95f03d519edc6573cd1adbd2fad3062a8dabbf31
3
+ metadata.gz: c748ad9e30a231437548b0b1b4b51262e6bb0fee
4
+ data.tar.gz: 020cb5707e74f39af595716a22a21714191a7c13
5
5
  SHA512:
6
- metadata.gz: 69de15850bc5d6be5e287d924601342691edf1ace680956ec82aed6c1cba6a5d427ae8d703aff4b9a8ab2bb15571b54ea6f722596f29fc9de2200118f25f005c
7
- data.tar.gz: 304174a40d56166d231e4e218f0733949d2e480434e7ef82c0fcb2350123b5b5d0888bcc051f76862f431dd5063012f9c3beaa9db6b8ba93d4fe57a7ee670967
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:-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" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <path id="b" d="M176.55 22.93v-.03c-.17-1.13-.8-2.1-1.9-2.77C170.93 18.07 136.8.03 88.98 0 40.25 0 4.8 19.28 3.28 20.14c-.98.6-1.63 1.6-1.77 2.72-14.8 123.1 84.7 176.2 85.7 176.7.6.3 1.2.44 1.8.44.6 0 1.2-.15 1.7-.42 1-.52 100.4-55.03 85.9-176.65z"/> <filter id="a" width="151.7%" height="146%" x="-25.8%" y="-16%" filterUnits="objectBoundingBox"> <feOffset dy="14" in="SourceAlpha" result="shadowOffsetOuter1"/> <feGaussianBlur stdDeviation="13" in="shadowOffsetOuter1" result="shadowBlurOuter1"/> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowBlurOuter1"/> </filter> </defs> <g fill="none" fill-rule="evenodd"> <g fill-rule="nonzero" transform="translate(26 12)"> <use fill="#000" filter="url(#a)" xlink:href="#b"/> <use fill="#FFF" fill-rule="evenodd" xlink:href="#b"/> </g> <path fill="#374886" d="M153.85 75.8s0 .68-.35 1.13c-.46.57-8.52 10.74-12.32 15.6-3.8 4.98-11.52 2.26-11.52 2.26s2.54-1.5 4.15-3.4c4.3-5.3 12.5-15.7 12.5-15.7s-8.2-10.2-12.4-15.6c-1.5-2-4.1-3.4-4.1-3.4s7.7-2.6 11.5 2.2c3.8 4.9 11.9 15.1 12.2 15.7.5.4.5 1.1.5 1.1m-78 .1s0 .6.4 1.1c.4.4 8.5 10.7 12.2 15.6 3.7 4.8 11.5 2.2 11.5 2.2s-2.5-1.5-4.1-3.4c-4.3-5.2-12.5-15.5-12.5-15.5l12.4-15.7c1.5-2 4.2-3.4 4.2-3.4s-7.7-2.6-11.5 2.2C84.8 63.7 76.9 74 76.5 74.6c-.32.55-.44 1.12-.44 1.12M115 62.82c-7.03 0-12.9 5.78-12.9 12.9s5.75 12.9 12.9 12.9c7.13 0 12.9-5.8 12.9-12.9s-5.9-12.9-12.9-12.9m-33.38 58.6c3.46 0 5.4-1.77 5.4-4.1 0-5.15-7.4-3.56-7.4-5.47 0-.8.78-1.3 1.97-1.3 1.5 0 2.9.6 3.7 1.5l1.3-2.3c-1.3-1-2.9-1.8-5.1-1.8-3.3 0-5.1 1.9-5.1 4 0 5 7.5 3.3 7.5 5.4 0 .8-.6 1.4-2.1 1.4s-3.4-.9-4.3-1.8l-1.4 2.4c1.4 1.2 3.4 2 5.6 2zm13.53-3c-1.8 0-3.1-1.5-3.1-3.7s1.3-3.7 3.2-3.7c1.1 0 2.3.6 2.8 1.44v4.5c-.5.8-1.7 1.46-2.8 1.46zm-1 3c1.5 0 2.9-.64 3.9-1.96v6.5h3.3v-17.63H98v1.6c-.96-1.23-2.33-1.92-3.86-1.92-3.2 0-5.52 2.5-5.52 6.7 0 4.3 2.33 6.7 5.53 6.7zm13.7-.32v-8.42c.6-.8 2-1.4 3.1-1.4.4 0 .7.1.9.1v-3.3c-1.5 0-3.1 1-3.9 2.1v-1.7h-3.3v12.8h3.3zm11.9.33c2 0 3.9-.6 5.2-1.77l-1.4-2.2c-.8.8-2.26 1.2-3.32 1.2-2.1 0-3.4-1.4-3.6-3h9.3v-.7c0-4.2-2.53-7.1-6.25-7.1-3.8 0-6.45 3-6.45 6.7 0 4.05 2.8 6.7 6.6 6.7zm2.9-7.9h-6.1c.2-1.27 1.07-2.83 3.1-2.83 2.18 0 3 1.6 3.08 2.87zm11.4 7.9c2 0 3.9-.6 5.2-1.77l-1.42-2.2c-.8.8-2.3 1.2-3.34 1.2-2.2 0-3.4-1.4-3.6-3h9.2v-.7c0-4.2-2.6-7.1-6.3-7.1-3.8 0-6.4 3-6.4 6.7 0 4.05 2.82 6.7 6.62 6.7zm2.9-7.9h-6.1c.17-1.27 1.05-2.83 3.1-2.83 2.2 0 3 1.6 3.1 2.87zm17.3 7.58v-9c0-2.5-1.3-4-4.03-4-2.08 0-3.6 1-4.4 2v-1.64h-3.3v12.76h3.3v-8.6c.53-.74 1.53-1.5 2.82-1.5 1.4 0 2.3.63 2.3 2.4v7.7h3.2z"/> </g> </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>
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
 
@@ -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.
@@ -6,6 +6,10 @@ module Sqreen
6
6
  class Context
7
7
  attr_accessor :bt
8
8
 
9
+ def self.bt
10
+ Context.new.bt
11
+ end
12
+
9
13
  def initialize
10
14
  @bt = get_current_backtrace
11
15
  end
@@ -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
- @first_seen[key] ||= now
51
- return true if was.nil?
52
- return true if current_batch.size > max_batch
53
- return true if (was + max_staleness) < now
54
- false
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
- return "att-#{event.type}"
77
+ "att-#{event.type}"
74
78
  when Sqreen::RemoteException
75
- return "rex-#{event.klass}"
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
@@ -11,7 +11,7 @@ module Sqreen
11
11
  def self::framework
12
12
  return @@framework if @@framework
13
13
  klass = case
14
- when defined?(::Rails)
14
+ when defined?(::Rails) && defined?(::Rails::VERSION)
15
15
  case Rails::VERSION::MAJOR.to_i
16
16
  when 4, 5
17
17
  require 'sqreen/frameworks/rails'
@@ -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
- %w(HTTP_X_FORWARDED_FOR HTTP_CLIENT_IP HTTP_X_REAL_IP HTTP_X_FORWARDED
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
- forwarded = req.env['HTTP_X_FORWARDED_FOR']
75
- ips = split_ip_addresses(forwarded)
76
- last = ips.find { |ip| (ip !~ TRUSTED_PROXIES) && valid_ip?(ip) }
77
- return last unless last.nil?
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 !ips.empty? && r =~ LOCALHOST
82
- last = ips.find { |ip| (ip !~ LOCALHOST) && valid_ip?(ip) }
83
- return last unless last.nil?
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
- :addr => client_ip,
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
- def initialize(query)
19
- self.query = query
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(framework, rule = {})
33
+ def payload(query)
34
+ self.query = query
34
35
  ret = {}
35
36
  METHODS.each_key do |section|
36
- ret = fill(section, ret, framework, rule)
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, rule)
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, rule))
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, rule)
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, rule)
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, rule)
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, rule)
88
+ so = section_object(section, framework)
96
89
  so.send(FULL_SECTIONS[section])
97
90
  end
98
91
 
99
- def fields(section, framework, rule)
92
+ def fields(section, framework)
100
93
  out = {}
101
- object = section_object(section, framework, rule)
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(rack_client_ip rails_client_ip ip_headers).include?(value)
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)
@@ -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
- payload = @payload_generator.payload(framework, @rule)
66
- payload['infos'] = infos
67
- Attack.record(payload)
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
- Sqreen.observations_queue.push [category, key, observation, at]
77
- if Sqreen.observations_queue.size > MAX_OBS_QUEUE_LENGTH / 2
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
- payload = {}
87
- payload['exception'] = exception
88
- payload['rulespack_id'] = rulespack_id
89
- payload['rule_name'] = rule_name
90
- begin
91
- payload['request_infos'] = framework.request_infos
92
- rescue => e
93
- Sqreen.log.debug("No framework request infos #{e}")
94
- end
95
- begin
96
- payload['request_params'] = framework.request_params
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
@@ -1,6 +1,7 @@
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/log'
4
5
  require 'sqreen/rule_attributes'
5
6
  require 'sqreen/rules_callbacks'
6
7
 
@@ -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
 
@@ -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
- end
9
+ def auth_track(is_logged_in, authentication_keys); end
10
+
11
+ def signup_track(authentication_keys); end
10
12
 
11
- def signup_track(authentication_keys)
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
@@ -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['X-Sqreen-Agent'] = "Ruby/#{Sqreen::VERSION}"
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
@@ -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.8.5'.freeze
4
+ VERSION = '1.9.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.8.5
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: 2017-10-18 00:00:00.000000000 Z
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/