sqreen 1.21.0.beta1 → 1.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/lib/sqreen/actions/block_user.rb +1 -1
  4. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  5. data/lib/sqreen/actions/redirect_user.rb +1 -1
  6. data/lib/sqreen/condition_evaluator.rb +8 -2
  7. data/lib/sqreen/configuration.rb +1 -1
  8. data/lib/sqreen/deferred_logger.rb +50 -14
  9. data/lib/sqreen/dependency/detector.rb +11 -3
  10. data/lib/sqreen/dependency/new_relic.rb +10 -1
  11. data/lib/sqreen/deprecation.rb +38 -0
  12. data/lib/sqreen/ecosystem.rb +55 -12
  13. data/lib/sqreen/ecosystem/databases/database_connection_data.rb +23 -0
  14. data/lib/sqreen/ecosystem/databases/mongo.rb +39 -0
  15. data/lib/sqreen/ecosystem/databases/mysql.rb +54 -0
  16. data/lib/sqreen/ecosystem/databases/postgres.rb +51 -0
  17. data/lib/sqreen/ecosystem/databases/redis.rb +36 -0
  18. data/lib/sqreen/ecosystem/exception_reporting.rb +28 -0
  19. data/lib/sqreen/ecosystem/http/net_http.rb +16 -17
  20. data/lib/sqreen/ecosystem/http/rack_request.rb +13 -12
  21. data/lib/sqreen/ecosystem/messaging/bunny.rb +61 -0
  22. data/lib/sqreen/ecosystem/messaging/kafka.rb +70 -0
  23. data/lib/sqreen/ecosystem/messaging/kinesis.rb +66 -0
  24. data/lib/sqreen/ecosystem/messaging/sqs.rb +68 -0
  25. data/lib/sqreen/ecosystem/module_api/message_producer.rb +57 -0
  26. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +1 -3
  27. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  28. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  29. data/lib/sqreen/ecosystem/module_api/tracing/consumer_data.rb +13 -0
  30. data/lib/sqreen/ecosystem/module_api/tracing/messaging_data.rb +35 -0
  31. data/lib/sqreen/ecosystem/module_api/tracing/producer_data.rb +13 -0
  32. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  33. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  34. data/lib/sqreen/ecosystem/module_registry.rb +9 -0
  35. data/lib/sqreen/ecosystem/tracing/modules/client.rb +35 -0
  36. data/lib/sqreen/ecosystem/tracing/modules/consumer.rb +35 -0
  37. data/lib/sqreen/ecosystem/tracing/modules/determine_ip.rb +28 -0
  38. data/lib/sqreen/ecosystem/tracing/modules/producer.rb +35 -0
  39. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  40. data/lib/sqreen/ecosystem/tracing/signals/tracing_consumer.rb +56 -0
  41. data/lib/sqreen/ecosystem/tracing/signals/tracing_producer.rb +56 -0
  42. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  43. data/lib/sqreen/ecosystem/tracing_id_setup.rb +4 -4
  44. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  45. data/lib/sqreen/ecosystem_integration.rb +11 -0
  46. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +2 -0
  47. data/lib/sqreen/events/request_record.rb +0 -1
  48. data/lib/sqreen/frameworks/generic.rb +21 -0
  49. data/lib/sqreen/frameworks/rails.rb +0 -7
  50. data/lib/sqreen/frameworks/request_recorder.rb +2 -0
  51. data/lib/sqreen/graft/call.rb +78 -20
  52. data/lib/sqreen/graft/callback.rb +1 -1
  53. data/lib/sqreen/graft/hook.rb +192 -88
  54. data/lib/sqreen/graft/hook_point.rb +18 -11
  55. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +2 -0
  56. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  57. data/lib/sqreen/legacy/old_event_submission_strategy.rb +2 -1
  58. data/lib/sqreen/log.rb +3 -2
  59. data/lib/sqreen/log/loggable.rb +1 -0
  60. data/lib/sqreen/logger.rb +24 -0
  61. data/lib/sqreen/metrics_store.rb +11 -0
  62. data/lib/sqreen/null_logger.rb +22 -0
  63. data/lib/sqreen/remote_command.rb +1 -0
  64. data/lib/sqreen/rules.rb +8 -4
  65. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  66. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  67. data/lib/sqreen/rules/rule_cb.rb +2 -0
  68. data/lib/sqreen/rules/waf_cb.rb +3 -3
  69. data/lib/sqreen/runner.rb +28 -2
  70. data/lib/sqreen/version.rb +1 -1
  71. data/lib/sqreen/weave/budget.rb +46 -0
  72. data/lib/sqreen/weave/legacy/instrumentation.rb +252 -109
  73. data/lib/sqreen/worker.rb +6 -2
  74. metadata +38 -14
  75. data/lib/sqreen/ecosystem/module_api/tracing_push_down.rb +0 -34
  76. data/lib/sqreen/ecosystem/redis/redis_connection.rb +0 -35
  77. data/lib/sqreen/encoding_sanitizer.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49a6c95ab34d19ae0f769e475ae67c2c3e4d19b17582ee09d8a6d231ac3d9150
4
- data.tar.gz: ad1ea7a80f3582ba90ffc6aa1cef7040459c56f65ea4712a023923b8bc7801e3
3
+ metadata.gz: 72fc8c4943ce7cb8cd45a80553ae02ae8c28086ca1895a89f2ec5840b2e6a883
4
+ data.tar.gz: ca46dc3483df4a16fca77e0226ca7c9a3d832c5a837155b86f0ee70c5fc12226
5
5
  SHA512:
6
- metadata.gz: 0da6438f20a00a84914db2bb06c24feab53e164feae1cb7d2af0b53afe24c5d5ea54a0cb68a8872a49aadedae4450de57e63da6a4f4a2ec21ac85eaa84c13acf
7
- data.tar.gz: 3e75918e810529674e10d693fd2a62c0eeeeecb18bac06a25fdd686d29c45d55333abb0feea790ec1d89e29ce71097bd1de16c2d31d98a6219e985d806793008
6
+ metadata.gz: 112a455abff8baca0c586f1479351e8e900e73d7f89b31e83fcbdc07ae99dbfa86f7439541a2f1688d56b481ce9094e16cd6bf860cb9959c7edd7be80ed66f92
7
+ data.tar.gz: 3f867ee75cf103c8817007540151e189c10116e0da8fa0bdad324de3bfa611d2bb4f888fdccf1074248f7976f26eb68fc81f987fcae0db5208ee9c00569f9797
@@ -1,3 +1,43 @@
1
+ ## 1.22.0
2
+
3
+ * Update WAF via libsqreen
4
+ * Add support for raw body
5
+ * Improve signature check
6
+ * Improve APM detection
7
+
8
+ ## 1.21.1
9
+
10
+ * Work around NewRelic initialisation (see https://github.com/newrelic/newrelic-ruby-agent/issues/461)
11
+
12
+ ## 1.21.0
13
+
14
+ * Add support for transport and tracing facilities
15
+
16
+ ## 1.20.4
17
+
18
+ * Fix missing budget check
19
+ * Improve performance
20
+ * Align internal setting name for WAF
21
+ * Include response information in all payloads
22
+ * Improve robustness against invalid Unicode
23
+ * Prevent rule execution to pursue in early block cases
24
+
25
+ ## 1.20.4.beta1
26
+
27
+ * Add optional dynamic time budget
28
+ * Add advanced per request metrics
29
+ * Improve robustness against exception in instrumentation
30
+ * Improve metric engine thread safety
31
+ * Restrict deferred logger to final logger severity on agent boot
32
+
33
+ ## 1.20.3
34
+
35
+ * Fix signature check
36
+
37
+ ## 1.20.2
38
+
39
+ * Fix performance regression in instrumentation engine
40
+
1
41
  ## 1.20.1
2
42
 
3
43
  * Add fallback mechanisms when connecting to new Sqreen backend API domains
@@ -22,7 +22,7 @@ module Sqreen
22
22
  end
23
23
 
24
24
  def do_run(identity_params)
25
- Sqreen.log.info(
25
+ Sqreen.log.debug(
26
26
  "Will raise due to user being blocked by action #{id}. " \
27
27
  "Blocked user identity: #{identity_params}"
28
28
  )
@@ -25,7 +25,7 @@ module Sqreen
25
25
  end
26
26
 
27
27
  def do_run(client_ip)
28
- Sqreen.log.info "Will request redirect for client with IP #{client_ip} " \
28
+ Sqreen.log.debug "Will request redirect for client with IP #{client_ip} " \
29
29
  "(action: #{id})."
30
30
  {
31
31
  :status => :skip,
@@ -24,7 +24,7 @@ module Sqreen
24
24
  end
25
25
 
26
26
  def do_run(identity_params)
27
- Sqreen.log.info 'Will request redirect for user with identity ' \
27
+ Sqreen.log.debug 'Will request redirect for user with identity ' \
28
28
  "#{identity_params} (action: #{id})."
29
29
 
30
30
  e = Sqreen::AttackBlocked.new(
@@ -67,7 +67,7 @@ module Sqreen
67
67
  return true if rem <= 0
68
68
  if hash.is_a?(Array)
69
69
  return hash.any? do |v|
70
- ConditionEvaluator.hash_key_include?(values, v, min_value_size, rem - 1)
70
+ hash_key_include?(values, v, min_value_size, rem - 1)
71
71
  end
72
72
  end
73
73
 
@@ -81,7 +81,13 @@ module Sqreen
81
81
  if hkey.respond_to?(:empty?) && hkey.empty?
82
82
  false
83
83
  else
84
- values.include?(hkey.to_s) || ConditionEvaluator.hash_key_include?(values, hval, min_value_size, rem - 1)
84
+ key_incl = if values.is_a?(String)
85
+ str_include?(values, hkey.to_s)
86
+ else
87
+ values.include?(hkey.to_s)
88
+ end
89
+
90
+ key_incl || hash_key_include?(values, hval, min_value_size, rem - 1)
85
91
  end
86
92
  end
87
93
  end
@@ -57,7 +57,7 @@ module Sqreen
57
57
  { :env => :SQREEN_RULES_SIGNATURE, :name => :rules_verify_signature,
58
58
  :default => true },
59
59
  { :env => :SQREEN_LOG_LEVEL, :name => :log_level,
60
- :default => 'WARN', :choice => %w[UNKNOWN FATAL ERROR WARN INFO DEBUG] },
60
+ :default => 'INFO', :choice => %w[UNKNOWN FATAL ERROR WARN INFO DEBUG] },
61
61
  { :env => :SQREEN_LOG_LOCATION, :name => :log_location,
62
62
  :default => 'log/sqreen.log' },
63
63
  { :env => :SQREEN_RUN_IN_TEST, :name => :run_in_test,
@@ -9,35 +9,70 @@ require 'sqreen/logger'
9
9
 
10
10
  module Sqreen
11
11
  class DeferredLogger
12
- include Singleton
12
+ MAX_ENTRIES = 1000
13
+
14
+ Entry = Struct.new(:severity, :message)
13
15
 
14
16
  def initialize
15
17
  @buffer = StringIO.new
16
18
  @logger = ::Logger.new(@buffer)
19
+ @entries = []
20
+ @mutex = Mutex.new
21
+ end
22
+
23
+ def debug?
24
+ true
25
+ end
26
+
27
+ def info?
28
+ true
29
+ end
30
+
31
+ def warn?
32
+ true
33
+ end
34
+
35
+ def error?
36
+ true
37
+ end
38
+
39
+ def fatal?
40
+ true
17
41
  end
18
42
 
19
43
  def debug(msg = nil, &block)
20
- @logger.debug(msg, &block)
44
+ add(::Logger::DEBUG, msg, &block)
21
45
  end
22
46
 
23
47
  def info(msg = nil, &block)
24
- @logger.info(msg, &block)
48
+ add(::Logger::INFO, msg, &block)
25
49
  end
26
50
 
27
51
  def warn(msg = nil, &block)
28
- @logger.warn(msg, &block)
52
+ add(::Logger::WARN, msg, &block)
29
53
  end
30
54
 
31
55
  def error(msg = nil, &block)
32
- @logger.error(msg, &block)
56
+ add(::Logger::ERROR, msg, &block)
33
57
  end
34
58
 
35
59
  def fatal(msg = nil, &block)
36
- @logger.error(msg, &block)
60
+ add(::Logger::FATAL, msg, &block)
61
+ end
62
+
63
+ def unknown(msg = nil, &block)
64
+ add(::Logger::UNKNOWN, msg, &block)
37
65
  end
38
66
 
39
67
  def add(severity, msg = nil, &block)
40
- send(Sqreen::Logger::SEVERITY_TO_METHOD[severity], msg, &block)
68
+ @mutex.synchronize do
69
+ @entries.shift if @entries.count >= MAX_ENTRIES
70
+ mark = @buffer.pos
71
+ @logger.add(severity, msg, &block)
72
+ @buffer.seek(mark)
73
+ @entries << Entry.new(severity, @buffer.read)
74
+ @buffer.truncate(0)
75
+ end
41
76
  end
42
77
 
43
78
  def formatter=(value)
@@ -45,21 +80,22 @@ module Sqreen
45
80
  end
46
81
 
47
82
  def flush_to(logger)
48
- logger.instance_eval { @logdev }.write(read).tap { reset }
83
+ @mutex.synchronize do
84
+ @entries.each do |entry|
85
+ next if entry.severity < logger.level
86
+ logger.instance_eval { @logdev }.write(entry.message)
87
+ end
88
+ reset
89
+ end
49
90
  end
50
91
 
51
92
  private
52
93
 
53
- def read
54
- @buffer.rewind
55
- @buffer.read
56
- end
57
-
58
94
  def reset
59
95
  buffer = StringIO.new
60
96
  logger = ::Logger.new(buffer)
61
97
  logger.formatter = @logger.formatter
62
- @buffer, @logger = buffer, logger
98
+ @buffer, @logger, @entries = buffer, logger, []
63
99
  end
64
100
  end
65
101
  end
@@ -25,6 +25,14 @@ module Sqreen
25
25
  end
26
26
  end
27
27
 
28
+ def to_app_hook_strategy
29
+ if Sqreen::Dependency::NewRelic.bundled? || Sqreen::Dependency::NewRelic.required?
30
+ :chain
31
+ else
32
+ :prepend
33
+ end
34
+ end
35
+
28
36
  def hook(&block)
29
37
  Sqreen.log.debug "[#{Process.pid}] Startup command: #{$0}"
30
38
 
@@ -34,7 +42,7 @@ module Sqreen
34
42
  Sqreen::Dependency::Rails.insert_sqreen_middlewares
35
43
  end if Sqreen::Dependency::Rails.required?
36
44
 
37
- Sqreen::Graft::Hook.add('Rack::Builder#to_app') do
45
+ Sqreen::Graft::Hook.add('Rack::Builder#to_app', to_app_hook_strategy) do
38
46
  after do
39
47
  Sqreen::Dependency::Rails.inspect_middlewares
40
48
  end
@@ -48,7 +56,7 @@ module Sqreen
48
56
  end
49
57
  end.install if Sqreen::Dependency::Sinatra.required?
50
58
 
51
- Sqreen::Graft::Hook.add('Rack::Builder#to_app') do
59
+ Sqreen::Graft::Hook.add('Rack::Builder#to_app', to_app_hook_strategy) do
52
60
  after do |call|
53
61
  builder = call.instance
54
62
 
@@ -58,7 +66,7 @@ module Sqreen
58
66
 
59
67
  # ensure startup of thread in request handling processes
60
68
 
61
- Sqreen::Graft::Hook.add('Rack::Builder#to_app') do
69
+ Sqreen::Graft::Hook.add('Rack::Builder#to_app', to_app_hook_strategy) do
62
70
  after do |call|
63
71
  callback = call.callback
64
72
 
@@ -8,8 +8,17 @@ module Sqreen
8
8
  module NewRelic
9
9
  module_function
10
10
 
11
+ def bundled?
12
+ defined?(Gem) && Gem.respond_to?(:loaded_specs) && !Gem.loaded_specs['newrelic_rpm'].nil?
13
+ end
14
+
15
+ def required?
16
+ Sqreen::Dependency.const_exist?('NewRelic::Agent::Agent')
17
+ end
18
+
11
19
  def ignore_sqreen_exceptions
12
- return unless defined?(NewRelic::Agent::Agent)
20
+ return unless required?
21
+
13
22
  NewRelic::Agent::Agent.instance.error_collector.ignore(['Sqreen::AttackBlocked'])
14
23
  rescue ::Exception => e # rubocop:disable Lint/RescueException
15
24
  Sqreen.log.warn "Failed ignoring AttackBlocked on NewRelic: #{e.inspect}"
@@ -0,0 +1,38 @@
1
+ # typed: strong
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/log/loggable'
7
+
8
+ module Sqreen
9
+ module Deprecation
10
+ include Sqreen::Log::Loggable
11
+
12
+ module_function
13
+
14
+ def deprecate(method)
15
+ return unless ENV['SQREEN_DEBUG_DEPRECATION']
16
+
17
+ owner = method.owner
18
+ deprecated = :"_deprecated_#{method.name}"
19
+ klass = owner.is_a?(Module)
20
+ target = klass ? owner.to_s : owner.class.to_s
21
+
22
+ method.owner.instance_eval do
23
+ alias_method deprecated, method.name
24
+
25
+ define_method(method.name) do |*args, &block|
26
+ msg = [
27
+ "deprecation",
28
+ "target:#{target}",
29
+ "method:#{method.name}",
30
+ "caller:#{Kernel.caller_locations[0]}",
31
+ ].join(' ')
32
+ Sqreen::Deprecation.logger.info(msg)
33
+ send(deprecated, *args, &block)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,8 +2,11 @@ require 'securerandom'
2
2
  require 'sqreen/ecosystem/module_registry'
3
3
  require 'sqreen/ecosystem/tracing/sampling_configuration'
4
4
  require 'sqreen/ecosystem/transaction_storage'
5
+ require 'sqreen/ecosystem/tracing_broker'
5
6
  require 'sqreen/ecosystem/tracing_id_setup'
6
- require 'sqreen/ecosystem/module_api/tracing_push_down'
7
+ require 'sqreen/ecosystem/module_api/message_producer'
8
+ require 'sqreen/ecosystem/module_api/tracing_id_generation'
9
+ require 'sqreen/ecosystem/module_api/tracing'
7
10
 
8
11
  module Sqreen
9
12
  # The API for the ecosystem client (together with the dispatch table)
@@ -14,8 +17,22 @@ module Sqreen
14
17
  register_modules(opts[:modules])
15
18
  @registry.init_all
16
19
 
17
- @tracing_id_setup = TracingIdSetup.new(@registry)
20
+ # setup tracing generation
21
+ tracing_id_mods = @registry.module_subset(ModuleApi::TracingIdGeneration)
22
+ @tracing_id_setup = TracingIdSetup.new(tracing_id_mods)
18
23
  @tracing_id_setup.setup_modules
24
+
25
+ # configure tracing broker with the consumers (tracing modules)
26
+ tracing_modules = @registry.module_subset(ModuleApi::Tracing)
27
+ @tracing_broker = TracingBroker.new(tracing_modules)
28
+
29
+ # inject tracing broker in message producers
30
+ @registry.each_module(ModuleApi::MessageProducer) do |mod|
31
+ mod.tracing_broker = @tracing_broker
32
+ end
33
+ rescue ::Exception # rubocop:disable Lint/RescueException
34
+ # TODO: modules must be disabled at this point
35
+ raise
19
36
  end
20
37
 
21
38
  def reset
@@ -42,7 +59,7 @@ module Sqreen
42
59
  def configure_sampling(tracing_id_prefix, sampling_config)
43
60
  @tracing_id_setup.tracing_id_prefix = tracing_id_prefix
44
61
  built_samp_cfg = Tracing::SamplingConfiguration.new(sampling_config)
45
- inject_sampling_config(built_samp_cfg)
62
+ @tracing_broker.sampling_configuration = built_samp_cfg
46
63
  end
47
64
 
48
65
  private
@@ -61,20 +78,46 @@ module Sqreen
61
78
  require_relative 'ecosystem/http/net_http'
62
79
  register Http::NetHttp.new
63
80
 
64
- require_relative 'ecosystem/redis/redis_connection'
65
- register Redis::RedisConnection.new
81
+ require_relative 'ecosystem/databases/postgres'
82
+ register Databases::Postgres.new
83
+
84
+ require_relative 'ecosystem/databases/mysql'
85
+ register Databases::Mysql.new
86
+
87
+ require_relative 'ecosystem/databases/mongo'
88
+ register Databases::Mongo.new
89
+
90
+ require_relative 'ecosystem/databases/redis'
91
+ register Databases::Redis.new
92
+
93
+ require_relative 'ecosystem/messaging/sqs'
94
+ register Messaging::Sqs.new
95
+
96
+ require_relative 'ecosystem/messaging/kinesis'
97
+ register Messaging::Kinesis.new
98
+
99
+ require_relative 'ecosystem/messaging/bunny'
100
+ register Messaging::Bunny.new
101
+
102
+ require_relative 'ecosystem/messaging/kafka'
103
+ register Messaging::Kafka.new
104
+
105
+ require_relative 'ecosystem/tracing/modules/client'
106
+ register Tracing::Modules::Client.new
107
+
108
+ require_relative 'ecosystem/tracing/modules/server'
109
+ register Tracing::Modules::Server.new
110
+
111
+ require_relative 'ecosystem/tracing/modules/producer'
112
+ register Tracing::Modules::Producer.new
113
+
114
+ require_relative 'ecosystem/tracing/modules/consumer'
115
+ register Tracing::Modules::Consumer.new
66
116
  end
67
117
 
68
118
  def register(mod)
69
119
  @registry.register mod
70
120
  end
71
-
72
- # @param [Sqreen::Ecosystem::SamplingConfiguration] config
73
- def inject_sampling_config(config)
74
- @registry.each_module(Sqreen::Ecosystem::ModuleApi::TracingPushDown) do |mod|
75
- mod.sampling_config = config
76
- end
77
- end
78
121
  end
79
122
  end
80
123
  end
@@ -0,0 +1,23 @@
1
+ require 'sqreen/ecosystem/module_api/tracing/client_data'
2
+
3
+ module Sqreen
4
+ module Ecosystem
5
+ module Databases
6
+ class DatabaseConnectionData
7
+ include ModuleApi::Tracing::ClientData
8
+
9
+ # @return [Integer]
10
+ attr_accessor :port
11
+
12
+ # @return [String]
13
+ attr_accessor :unix_socket
14
+
15
+ # @return [String]
16
+ attr_accessor :username
17
+
18
+ # @return [String]
19
+ attr_accessor :db
20
+ end
21
+ end
22
+ end
23
+ end