sqreen 1.20.0-java → 1.20.1-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
  SHA256:
3
- metadata.gz: f45370a0f5c03f939b0098527398d058cf0df4ad026f7002905bdb31b79e857d
4
- data.tar.gz: 516269e4979639d390e557f5f382522ebd0fdbc68e1731ea75315cb881dded9d
3
+ metadata.gz: e25462ce4a2c45847bd495862994e20b658b8e24f44e6e53819eef2291b2aa53
4
+ data.tar.gz: 39d5dd53d1927a6bcffcdb7cf168a0553aa9baf610de26bb9932de46a1747f9d
5
5
  SHA512:
6
- metadata.gz: dbaec7b5608f60ef43922c970895b0c3aa3b547dcfc27192aff587993ade656ea6e2bdf969f01ce180d389f272b55f8df6c716be73262c251110afb53909bea5
7
- data.tar.gz: a901202c4f7949711b2bb9c6fd940ea830ebf6c41e0f5e20ed17a0fa67957d49a10eb68573c41b0e5e72ccb0d8cae2e2dc5a9fd29c0644da4845a56164898505
6
+ metadata.gz: 9ee353c82025cbbbee61a296143d405915d7e2ba9f7246754582ce63420155db8c957f337bfc654aa6ae66d6eeb6e51688761e2d8d14a18a37ca45785783834c
7
+ data.tar.gz: 9a813f019c69aafe71988439ab2b1c1c02304f02babf990fdd6c153976a6994df6fe169c40fa71710e4e315a563ec7d824517055b38d6ca34ff83d2b5e851c69
@@ -1,3 +1,7 @@
1
+ ## 1.20.1
2
+
3
+ * Add fallback mechanisms when connecting to new Sqreen backend API domains
4
+
1
5
  ## 1.20.0
2
6
 
3
7
  * Enable new instrumentation engine by default
@@ -0,0 +1,20 @@
1
+ require 'digest'
2
+
3
+ module Sqreen
4
+ class AgentMessage
5
+ def initialize(kind, message, id = nil)
6
+ id ||= message + "\x00" + kind
7
+ @hash_hex = Digest::SHA1.hexdigest(id)
8
+ @kind = kind
9
+ @message = message
10
+ end
11
+
12
+ def to_h
13
+ {
14
+ id: @hash_hex,
15
+ kind: @kind,
16
+ message: @message,
17
+ }
18
+ end
19
+ end
20
+ end
@@ -70,3 +70,27 @@ WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
70
70
  4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
71
71
  hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
72
72
  -----END CERTIFICATE-----
73
+ -----BEGIN CERTIFICATE-----
74
+ MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
75
+ EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
76
+ HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
77
+ ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
78
+ MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
79
+ VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
80
+ ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
81
+ dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
82
+ hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
83
+ OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
84
+ 8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
85
+ Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
86
+ hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
87
+ 6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
88
+ DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
89
+ AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
90
+ bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
91
+ ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
92
+ qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
93
+ iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
94
+ 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
95
+ sSi6
96
+ -----END CERTIFICATE-----
@@ -43,9 +43,9 @@ module Sqreen
43
43
  { :env => :SQREEN_WEAVE_STRATEGY, :name => :weave_strategy,
44
44
  :default => :prepend, :convert => :to_sym },
45
45
  { :env => :SQREEN_URL, :name => :url,
46
- :default => 'https://back.sqreen.io' },
46
+ :default => nil },
47
47
  { :env => :SQREEN_INGESTION_URL, :name => :ingestion_url,
48
- :default => 'https://ingestion.sqreen.com/' },
48
+ :default => nil },
49
49
  { :env => :SQREEN_PROXY_URL, :name => :proxy_url,
50
50
  :default => nil },
51
51
  { :env => :SQREEN_TOKEN, :name => :token,
@@ -78,6 +78,8 @@ module Sqreen
78
78
  :default => nil },
79
79
  { :env => :SQREEN_STRIP_SENSITIVE_REGEX, :name => :strip_sensitive_regex,
80
80
  :default => nil },
81
+ { :env => :SQREEN_NO_SNIFF_DOMAINS, :name => :no_sniff_domains,
82
+ :default => false },
81
83
 
82
84
  ].freeze
83
85
 
@@ -0,0 +1,184 @@
1
+ require 'net/https'
2
+ require 'sqreen/agent_message'
3
+ require 'sqreen/log/loggable'
4
+
5
+ module Sqreen
6
+ class EndpointTesting
7
+ Endpoint = Struct.new(:url, :ca_store)
8
+ class ChosenEndpoints
9
+ def initialize
10
+ @messages = []
11
+ end
12
+
13
+ # @return [Sqreen::EndpointTesting::Endpoint]
14
+ attr_accessor :control
15
+
16
+ # @return [Sqreen::EndpointTesting::Endpoint]
17
+ attr_accessor :ingestion
18
+
19
+ # @return [Array<Sqreen::AgentMessage>]
20
+ attr_reader :messages
21
+
22
+ # @param [Sqreen::AgentMessage] message
23
+ def add_message(message)
24
+ @messages << message
25
+ end
26
+ end
27
+
28
+ MAIN_CONTROL_HOST = 'back.sqreen.com'.freeze
29
+ MAIN_INJECTION_HOST = 'ingestion.sqreen.com'.freeze
30
+ FALLBACK_ENDPOINT_URL = 'https://back.sqreen.io/'.freeze
31
+ GLOBAL_TIMEOUT = 30
32
+
33
+ CONTROL_ERROR_KIND = 'back_sqreen_com_unavailable'.freeze
34
+ INGESTION_ERROR_KIND = 'ingestion_sqreen_com_unavailable'.freeze
35
+
36
+ class << self
37
+ include Log::Loggable
38
+
39
+ # reproduces behaviour before endpoint testing was introduced
40
+ def no_test_endpoints(config_url, config_ingestion_url)
41
+ endpoints = ChosenEndpoints.new
42
+
43
+ endpoints.control = Endpoint.new(
44
+ config_url || "https://#{MAIN_CONTROL_HOST}/", cert_store
45
+ )
46
+ endpoints.ingestion = Endpoint.new(
47
+ config_ingestion_url || "https://#{MAIN_INJECTION_HOST}/", nil
48
+ )
49
+
50
+ endpoints
51
+ end
52
+
53
+ def test_endpoints(proxy_url, config_url, config_ingestion_url)
54
+ proxy_params = create_proxy_params(proxy_url)
55
+
56
+ # execute the tests in separate threads and wait for them
57
+ thread_control = Thread.new do
58
+ thread_main(config_url, proxy_params, MAIN_CONTROL_HOST)
59
+ end
60
+ thread_injection = Thread.new do
61
+ thread_main(config_ingestion_url, proxy_params, MAIN_INJECTION_HOST)
62
+ end
63
+
64
+ wait_for_threads(thread_control, thread_injection)
65
+
66
+ # build and return result
67
+ fallback = Endpoint.new(FALLBACK_ENDPOINT_URL, cert_store)
68
+ endpoints = ChosenEndpoints.new
69
+ endpoints.control = thread_control[:endpoint] || fallback
70
+ endpoints.ingestion = thread_injection[:endpoint] || fallback
71
+
72
+ if thread_control[:endpoint_error]
73
+ msg = AgentMessage.new(CONTROL_ERROR_KIND, thread_control[:endpoint_error])
74
+ endpoints.add_message msg
75
+ end
76
+ if thread_injection[:endpoint_error]
77
+ msg = AgentMessage.new(INGESTION_ERROR_KIND, thread_injection[:endpoint_error])
78
+ endpoints.add_message msg
79
+ end
80
+
81
+ endpoints
82
+ end
83
+
84
+ private
85
+
86
+ def thread_main(configured_url, proxy_params, host)
87
+ res = if configured_url
88
+ Endpoint.new(configured_url, nil)
89
+ else
90
+ EndpointTesting.send(:test_with_store_variants, proxy_params, host)
91
+ end
92
+
93
+ Thread.current[:endpoint] = res
94
+ rescue StandardError => e
95
+ Thread.current[:endpoint_error] = e.message
96
+ end
97
+
98
+ def create_proxy_params(proxy_url)
99
+ return [] unless proxy_url
100
+
101
+ proxy = URI.parse(proxy_url)
102
+
103
+ return [] unless proxy.scheme == 'http'
104
+
105
+ [proxy.host, proxy.port, proxy.user, proxy.password]
106
+ end
107
+
108
+ def test_with_store_variants(proxy_params, server_name)
109
+ # first without custom store
110
+ do_test(proxy_params, server_name, false)
111
+ rescue StandardError => _e
112
+ do_test(proxy_params, server_name, true)
113
+ end
114
+
115
+ # @param [Array] proxy_params
116
+ # @param [String] server_name
117
+ # @param [Boolean] custom_store
118
+ def do_test(proxy_params, server_name, custom_store)
119
+ http = Net::HTTP.new(server_name, 443, *proxy_params)
120
+ http.use_ssl = true
121
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SQREEN_SSL_NO_VERIFY']
122
+ http.verify_callback = lambda do |preverify_ok, ctx|
123
+ unless preverify_ok
124
+ logger.warn do
125
+ "Certificate validation failure for certificate issued to " \
126
+ "#{ctx.chain[0].subject}: #{ctx.error_string}"
127
+ end
128
+ end
129
+
130
+ preverify_ok
131
+ end
132
+
133
+ http.open_timeout = 13
134
+ http.ssl_timeout = 7
135
+ http.read_timeout = 7
136
+ http.close_on_empty_response = true
137
+
138
+ http.cert_store = cert_store if custom_store
139
+
140
+ resp = http.get('/ping')
141
+
142
+ logger.info do
143
+ "Got response from #{server_name}'s ping endpoint. " \
144
+ "Status code is #{resp.code} (custom CA store: #{custom_store})"
145
+ end
146
+
147
+ unless resp.code == '200'
148
+ raise "Response code for /ping is #{resp.code}, not 200"
149
+ end
150
+
151
+ Endpoint.new("https://#{server_name}/", http.cert_store)
152
+ rescue StandardError => e
153
+ logger.info do
154
+ "Error in request to #{server_name} " \
155
+ "(custom store: #{custom_store}): #{e.message}"
156
+ end
157
+
158
+ raise "Error in request to #{server_name}: #{e.message}"
159
+ end
160
+
161
+ def wait_for_threads(thread_control, thread_injection)
162
+ deadline = Time.now + GLOBAL_TIMEOUT
163
+ [thread_control, thread_injection].each do |thread|
164
+ rem = deadline - Time.now
165
+ rem = 0.1 if rem < 0.1
166
+ next if thread.join(rem)
167
+ logger.debug { "Timeout for thread #{thread}" }
168
+ thread.kill
169
+ thread[:endpoint_error] = "Timeout doing endpoint testing"
170
+ end
171
+ end
172
+
173
+ def cert_store
174
+ @cert_store ||= begin
175
+ cert_file = File.join(File.dirname(__FILE__), 'ca.crt')
176
+ cert_store = OpenSSL::X509::Store.new
177
+ cert_store.add_file cert_file
178
+
179
+ cert_store
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
@@ -23,6 +23,6 @@ module Sqreen::Log::Loggable
23
23
  end
24
24
 
25
25
  def logger
26
- @logger || self.class.logger
26
+ @logger || singleton_class.logger
27
27
  end
28
28
  end
@@ -11,6 +11,7 @@ require 'sqreen/events/attack'
11
11
 
12
12
  require 'sqreen/log'
13
13
 
14
+ require 'sqreen/agent_message'
14
15
  require 'sqreen/rules'
15
16
  require 'sqreen/session'
16
17
  require 'sqreen/remote_command'
@@ -18,6 +19,7 @@ require 'sqreen/capped_queue'
18
19
  require 'sqreen/metrics_store'
19
20
  require 'sqreen/deliveries/simple'
20
21
  require 'sqreen/deliveries/batch'
22
+ require 'sqreen/endpoint_testing'
21
23
  require 'sqreen/performance_notifications/metrics'
22
24
  require 'sqreen/performance_notifications/binned_metrics'
23
25
  require 'sqreen/legacy/instrumentation'
@@ -113,19 +115,23 @@ module Sqreen
113
115
  @next_metrics = []
114
116
  @running = true
115
117
 
118
+ @proxy_url = @configuration.get(:proxy_url)
119
+ chosen_endpoints = determine_endpoints
120
+
116
121
  @token = @configuration.get(:token)
117
122
  @app_name = @configuration.get(:app_name)
118
- @url = @configuration.get(:url)
119
- @proxy_url = @configuration.get(:proxy_url)
123
+ @url = chosen_endpoints.control.url
124
+ @cert_store = chosen_endpoints.control.ca_store
125
+
120
126
  Sqreen.update_whitelisted_paths([])
121
127
  Sqreen.update_whitelisted_ips({})
122
128
  Sqreen.update_performance_budget(nil)
123
- raise(Sqreen::Exception, 'no url found') unless @url
124
129
  raise(Sqreen::TokenNotFoundException, 'no token found') unless @token
125
130
 
126
131
  Sqreen::Kit::Configuration.logger = Sqreen.log
127
- Sqreen::Kit::Configuration.ingestion_url = @configuration.get(:ingestion_url)
128
- Sqreen::Kit::Configuration.proxy_url = @configuration.get(:proxy_url)
132
+ Sqreen::Kit::Configuration.ingestion_url = chosen_endpoints.ingestion.url
133
+ Sqreen::Kit::Configuration.certificate_store = chosen_endpoints.ingestion.ca_store
134
+ Sqreen::Kit::Configuration.proxy_url = @proxy_url
129
135
 
130
136
  register_exit_cb if set_at_exit
131
137
 
@@ -143,6 +149,7 @@ module Sqreen
143
149
 
144
150
  Sqreen.log.debug "Using token #{@token}"
145
151
  response = create_session(session_class)
152
+ post_endpoint_testing_msgs(chosen_endpoints)
146
153
  wanted_features = response.fetch('features', {})
147
154
  conf_initial_features = configuration.get(:initial_features)
148
155
  unless conf_initial_features.nil?
@@ -155,7 +162,7 @@ module Sqreen
155
162
  wanted_features = wanted_features.merge(conf_features)
156
163
  rescue
157
164
  Sqreen.log.warn do
158
- "NOT using invalid inital features #{conf_initial_features}"
165
+ "NOT using invalid initial features #{conf_initial_features}"
159
166
  end
160
167
  end
161
168
  end
@@ -171,7 +178,7 @@ module Sqreen
171
178
  end
172
179
 
173
180
  def create_session(session_class)
174
- @session = session_class.new(@url, @token, @app_name, @proxy_url)
181
+ @session = session_class.new(@url, @cert_store, @token, @app_name, @proxy_url)
175
182
  session.login(@framework)
176
183
  end
177
184
 
@@ -508,6 +515,28 @@ module Sqreen
508
515
 
509
516
  private
510
517
 
518
+ def post_endpoint_testing_msgs(chosen_endpoints)
519
+ chosen_endpoints.messages.each do |msg|
520
+ session.post_agent_message(@framework, msg)
521
+ end
522
+ rescue => e
523
+ Sqreen.log.warn "Error submitting agent message: #{e}"
524
+ RemoteException.record(e)
525
+ end
526
+
527
+ def determine_endpoints
528
+ # there's no sniffing going on; just a misnamed config setting
529
+ if @configuration.get(:no_sniff_domains)
530
+ # reproduces behaviour before endpoint testing was introduced
531
+ EndpointTesting.no_test_endpoints(@configuration.get(:url),
532
+ @configuration.get(:ingestion_url))
533
+ else
534
+ EndpointTesting.test_endpoints(@proxy_url,
535
+ @configuration.get(:url),
536
+ @configuration.get(:ingestion_url))
537
+ end
538
+ end
539
+
511
540
  def load_actions(hashes)
512
541
  unsupported = Set.new
513
542
 
@@ -50,7 +50,7 @@ module Sqreen
50
50
 
51
51
  attr_accessor :request_compression
52
52
 
53
- def initialize(server_url, token, app_name = nil, proxy_url = nil)
53
+ def initialize(server_url, cert_store, token, app_name = nil, proxy_url = nil)
54
54
  @token = token
55
55
  @app_name = app_name
56
56
  @session_id = nil
@@ -73,12 +73,7 @@ module Sqreen
73
73
  @http = Net::HTTP.new(uri.host, uri.port, *proxy_params)
74
74
  @http.use_ssl = use_ssl
75
75
  @http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SQREEN_SSL_NO_VERIFY'] # for testing
76
- if use_ssl
77
- cert_file = File.join(File.dirname(__FILE__), 'ca.crt')
78
- cert_store = OpenSSL::X509::Store.new
79
- cert_store.add_file cert_file
80
- @http.cert_store = cert_store
81
- end
76
+ @http.cert_store = cert_store if use_ssl
82
77
  self.use_signals = false
83
78
  end
84
79
 
@@ -240,10 +235,7 @@ module Sqreen
240
235
  end
241
236
 
242
237
  def login(framework)
243
- headers = {
244
- 'x-api-key' => @token,
245
- 'x-app-name' => @app_name || framework.application_name,
246
- }.reject { |k, v| v == nil }
238
+ headers = prelogin_auth_headers(framework)
247
239
 
248
240
  Sqreen.log.warn "Using app name: #{headers['x-app-name']}"
249
241
 
@@ -312,6 +304,11 @@ module Sqreen
312
304
  @evt_sub_strategy.post_batch(events)
313
305
  end
314
306
 
307
+ def post_agent_message(framework, agent_message)
308
+ headers = prelogin_auth_headers(framework)
309
+ post('app_agent_message', agent_message.to_h, headers, 0)
310
+ end
311
+
315
312
  # Perform agent logout
316
313
  # @param retrying [Boolean] whether to try again on error
317
314
  def logout(retrying = true)
@@ -325,5 +322,14 @@ module Sqreen
325
322
  Sqreen.logged_in = false
326
323
  disconnect
327
324
  end
325
+
326
+ private
327
+
328
+ def prelogin_auth_headers(framework)
329
+ {
330
+ 'x-api-key' => @token,
331
+ 'x-app-name' => @app_name || framework.application_name,
332
+ }.reject { |_k, v| v == nil }
333
+ end
328
334
  end
329
335
  end
@@ -4,5 +4,5 @@
4
4
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
5
 
6
6
  module Sqreen
7
- VERSION = '1.20.0'.freeze
7
+ VERSION = '1.20.1'.freeze
8
8
  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.20.0
4
+ version: 1.20.1
5
5
  platform: java
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-18 00:00:00.000000000 Z
11
+ date: 2020-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.2.0
32
+ version: 0.2.1
33
33
  name: sqreen-kit
34
34
  prerelease: false
35
35
  type: :runtime
@@ -37,7 +37,7 @@ dependencies:
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.2.0
40
+ version: 0.2.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
@@ -93,6 +93,7 @@ files:
93
93
  - lib/sqreen/actions/user_action_class.rb
94
94
  - lib/sqreen/actions/users_index.rb
95
95
  - lib/sqreen/agent.rb
96
+ - lib/sqreen/agent_message.rb
96
97
  - lib/sqreen/aggregated_metric.rb
97
98
  - lib/sqreen/attack_blocked.rb
98
99
  - lib/sqreen/attack_detected.html
@@ -122,6 +123,7 @@ files:
122
123
  - lib/sqreen/dependency/sentry.rb
123
124
  - lib/sqreen/dependency/sinatra.rb
124
125
  - lib/sqreen/encoding_sanitizer.rb
126
+ - lib/sqreen/endpoint_testing.rb
125
127
  - lib/sqreen/error_handling_middleware.rb
126
128
  - lib/sqreen/event.rb
127
129
  - lib/sqreen/events/attack.rb