tcell_agent 2.5.1 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/tcell_agent/rails/dlp_handler.rb +2 -3
- data/lib/tcell_agent/rails/js_agent_insert.rb +16 -1
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +4 -15
- data/lib/tcell_agent/rails/responses.rb +0 -12
- data/lib/tcell_agent/rails/tcell_body_proxy.rb +17 -28
- data/lib/tcell_agent/rust/libtcellagent-alpine.so +0 -0
- data/lib/tcell_agent/rust/libtcellagent-x64.dll +0 -0
- data/lib/tcell_agent/rust/libtcellagent.dylib +0 -0
- data/lib/tcell_agent/rust/libtcellagent.so +0 -0
- data/lib/tcell_agent/version.rb +1 -1
- data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +12 -27
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 729643a91b2542ef11a78966c493fadd8a15f6dd7ddc99a5764e9f993904c78e
|
4
|
+
data.tar.gz: 47cb2b434ec142362510f0494c441caa73c34dde4f56afdee470685f92825ac6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a72a5cbe005619fe1932b39798d4d2b63937e2b2a71a2ff80d15186f157c8a11978b61f84bbae6bf9778aa028aba3766addc4c0571a0ec0216d53b29a96adc9e
|
7
|
+
data.tar.gz: 0f40534a487aa4b1f5576795ea2904449b5dc531cdbd56720f8f62a8c0866b32b7d12d0e04e9c9fa40cab4860eceafe02e7047149ec39bdab8c5465831edc77a
|
@@ -33,14 +33,13 @@ module TCellAgent
|
|
33
33
|
response
|
34
34
|
end
|
35
35
|
|
36
|
-
def self.get_handler_and_context(request
|
36
|
+
def self.get_handler_and_context(request)
|
37
37
|
dlp_handler = nil
|
38
38
|
tcell_context = nil
|
39
39
|
|
40
40
|
TCellAgent::Instrumentation.safe_block('DLP Handler get handler and context') do
|
41
41
|
if TCellAgent.configuration.should_instrument? &&
|
42
|
-
TCellAgent.configuration.should_intercept_requests?
|
43
|
-
TCellAgent::Utils::Rails.processable_response?(response_headers)
|
42
|
+
TCellAgent.configuration.should_intercept_requests?
|
44
43
|
|
45
44
|
# do all this work so that dlp doesn't run at all unless it's on and there
|
46
45
|
# are rules to run
|
@@ -5,6 +5,21 @@ module TCellAgent
|
|
5
5
|
module Rails
|
6
6
|
module JSAgent
|
7
7
|
HEAD_SEARCH_REGEX = Regexp.new('(<head>|<head( |\n).*?>)', Regexp::IGNORECASE)
|
8
|
+
def self.insert_js_agent?(response_headers)
|
9
|
+
content_disposition = response_headers['Content-Disposition']
|
10
|
+
is_attachment = content_disposition && content_disposition =~ /^attachment/i
|
11
|
+
|
12
|
+
content_type = response_headers['Content-Type']
|
13
|
+
applicable_content_type = content_type &&
|
14
|
+
content_type.start_with?('text/html')
|
15
|
+
|
16
|
+
content_encoding = response_headers['Content-Encoding']
|
17
|
+
compressed_content_encoding = content_encoding &&
|
18
|
+
(content_encoding =~ /(br|gzip)/i)
|
19
|
+
|
20
|
+
!is_attachment && applicable_content_type && !compressed_content_encoding
|
21
|
+
end
|
22
|
+
|
8
23
|
def self.insert_now(js_agent_handler, script_insert, rack_body, content_length)
|
9
24
|
TCellAgent::Instrumentation.safe_block('Handling JSAgent Insert Now') do
|
10
25
|
if js_agent_handler
|
@@ -43,7 +58,7 @@ module TCellAgent
|
|
43
58
|
script_insert = nil
|
44
59
|
|
45
60
|
TCellAgent::Instrumentation.safe_block('JSAgent get handler and script insert') do
|
46
|
-
return [nil, nil] unless (response_headers
|
61
|
+
return [nil, nil] unless insert_js_agent?(response_headers)
|
47
62
|
|
48
63
|
js_agent_policy = TCellAgent.policy(TCellAgent::PolicyTypes::JSAGENTINJECTION)
|
49
64
|
script_insert = js_agent_policy.get_js_agent_script_tag(
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'tcell_agent/instrumentation'
|
2
2
|
require 'tcell_agent/rails/responses'
|
3
3
|
require 'tcell_agent/rails/js_agent_insert'
|
4
|
-
require 'tcell_agent/rails/dlp_handler'
|
5
4
|
require 'tcell_agent/rails/tcell_body_proxy'
|
6
5
|
|
7
6
|
module TCellAgent
|
@@ -22,7 +21,7 @@ module TCellAgent
|
|
22
21
|
TCellAgent::Instrumentation.safe_block('Handling Request') do
|
23
22
|
tcell_response = response
|
24
23
|
unless request.env[TCellAgent::Instrumentation::TCELL_ID].patches_blocking_triggered
|
25
|
-
tcell_response =
|
24
|
+
tcell_response = _handle_appsensor_js_agent(request, tcell_response)
|
26
25
|
end
|
27
26
|
tcell_response = _handle_redirect(request, tcell_response)
|
28
27
|
tcell_response = _set_headers(request, tcell_response)
|
@@ -77,14 +76,12 @@ module TCellAgent
|
|
77
76
|
response
|
78
77
|
end
|
79
78
|
|
80
|
-
def
|
79
|
+
def _handle_appsensor_js_agent(request, response)
|
81
80
|
TCellAgent::Instrumentation.safe_block('Handling AppSensor, JS Agent, and DLP') do
|
82
81
|
status_code, response_headers, response_body = response
|
83
82
|
|
84
83
|
js_agent_handler, script_insert =
|
85
84
|
TCellAgent::Instrumentation::Rails::JSAgent.get_handler_and_script_insert(request, response_headers)
|
86
|
-
dlp_handler, tcell_context =
|
87
|
-
TCellAgent::Instrumentation::Rails::DLPHandler.get_handler_and_context(request, response_headers)
|
88
85
|
|
89
86
|
content_length = 0
|
90
87
|
defer_appfw_due_to_streaming = false
|
@@ -97,29 +94,21 @@ module TCellAgent
|
|
97
94
|
|
98
95
|
# when content length is present it can be inferred that the
|
99
96
|
# response is not a streaming response, so js agent insertion
|
100
|
-
#
|
97
|
+
# can be done up front
|
101
98
|
response_body, content_length =
|
102
99
|
TCellAgent::Instrumentation::Rails::JSAgent.insert_now(js_agent_handler,
|
103
100
|
script_insert,
|
104
101
|
response_body,
|
105
102
|
content_length)
|
106
103
|
|
107
|
-
response_body, content_length =
|
108
|
-
TCellAgent::Instrumentation::Rails::DLPHandler.report_and_redact_now(dlp_handler,
|
109
|
-
tcell_context,
|
110
|
-
response_body,
|
111
|
-
content_length)
|
112
|
-
|
113
104
|
response_headers['Content-Length'] = content_length.to_s
|
114
105
|
|
115
106
|
elsif response_body.is_a?(Rack::BodyProxy)
|
116
107
|
response_body = TCellAgent::Instrumentation::Rails::TCellBodyProxy.new(
|
117
108
|
response_body,
|
118
|
-
TCellAgent::Utils::Rails.processable_response?(response_headers),
|
119
109
|
js_agent_handler,
|
120
110
|
script_insert,
|
121
|
-
|
122
|
-
tcell_context
|
111
|
+
response_headers
|
123
112
|
)
|
124
113
|
defer_appfw_due_to_streaming = true
|
125
114
|
end
|
@@ -7,18 +7,6 @@ module TCellAgent
|
|
7
7
|
STATUSES_MISSING_CONTENT_LENGTH.include?(status_code.to_i) ||
|
8
8
|
(headers['Content-Length'] && headers['Content-Length'].to_i.zero?)
|
9
9
|
end
|
10
|
-
|
11
|
-
def self.processable_response?(response_headers)
|
12
|
-
content_disposition = response_headers['Content-Disposition']
|
13
|
-
is_attachment = content_disposition && content_disposition =~ /^attachment/i
|
14
|
-
|
15
|
-
content_type = response_headers['Content-Type']
|
16
|
-
applicable_content_type = content_type &&
|
17
|
-
(content_type =~ %r{application/json}i ||
|
18
|
-
content_type =~ %r{application/xml}i ||
|
19
|
-
content_type =~ /^text/i)
|
20
|
-
!is_attachment && applicable_content_type
|
21
|
-
end
|
22
10
|
end
|
23
11
|
end
|
24
12
|
end
|
@@ -4,27 +4,17 @@ module TCellAgent
|
|
4
4
|
module Instrumentation
|
5
5
|
module Rails
|
6
6
|
class TCellBodyProxy
|
7
|
-
attr_accessor :meta_data
|
8
|
-
|
9
|
-
# for specs
|
10
|
-
attr_accessor :content_length
|
7
|
+
attr_accessor :content_length, :meta_data
|
11
8
|
|
12
9
|
def initialize(body,
|
13
|
-
process_js_and_dlp,
|
14
10
|
js_agent_insertion_proc,
|
15
11
|
script_insert,
|
16
|
-
|
17
|
-
tcell_context)
|
12
|
+
response_headers)
|
18
13
|
@content_length = 0
|
19
14
|
@body = body
|
20
|
-
|
21
|
-
@process_js_and_dlp = process_js_and_dlp
|
22
|
-
|
23
15
|
@js_agent_insertion_proc = js_agent_insertion_proc
|
24
16
|
@script_insert = script_insert
|
25
|
-
|
26
|
-
@dlp_cleaner_proc = dlp_cleaner_proc
|
27
|
-
@tcell_context = tcell_context
|
17
|
+
@response_headers = response_headers
|
28
18
|
end
|
29
19
|
|
30
20
|
def close
|
@@ -58,35 +48,34 @@ module TCellAgent
|
|
58
48
|
end
|
59
49
|
|
60
50
|
def process_body(body)
|
51
|
+
new_body = body
|
61
52
|
TCellAgent::Instrumentation.safe_block('Processing tcell body proxy body') do
|
62
53
|
chunked_response_match = nil
|
63
|
-
|
54
|
+
|
55
|
+
if @response_headers['Transfer-Encoding'] == 'chunked' &&
|
56
|
+
body.class.name == 'String' &&
|
57
|
+
body =~ /^([[:xdigit:]]+)(;.+)?\r\n/
|
64
58
|
chunked_response_match = Regexp.last_match(1)
|
65
59
|
@content_length += chunked_response_match.to_i(16)
|
66
60
|
end
|
67
61
|
|
68
|
-
new_body = body
|
69
62
|
if body.class.name == 'ActionView::OutputBuffer' ||
|
70
63
|
(body.class.name == 'String' && !chunked_response_match)
|
71
|
-
if @
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
80
|
-
if @dlp_cleaner_proc
|
81
|
-
@dlp_cleaner_proc.call(@tcell_context, new_body)
|
64
|
+
if @js_agent_insertion_proc
|
65
|
+
new_body = @js_agent_insertion_proc.call(@script_insert, body)
|
66
|
+
|
67
|
+
if new_body != body
|
68
|
+
# js agent was successfully inserted so no need to keep
|
69
|
+
# calling this proc
|
70
|
+
@js_agent_insertion_proc = nil
|
82
71
|
end
|
83
72
|
end
|
84
73
|
|
85
74
|
@content_length += new_body.bytesize
|
86
75
|
end
|
87
|
-
|
88
|
-
new_body
|
89
76
|
end
|
77
|
+
|
78
|
+
new_body
|
90
79
|
end
|
91
80
|
end
|
92
81
|
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/tcell_agent/version.rb
CHANGED
@@ -22,8 +22,7 @@ module TCellAgent
|
|
22
22
|
it 'appfirewall injections should be checked' do
|
23
23
|
tcell_body_proxy = TCellBodyProxy.new(
|
24
24
|
Rack::BodyProxy.new(['body']) {},
|
25
|
-
|
26
|
-
nil, nil, nil, nil
|
25
|
+
nil, nil, {}
|
27
26
|
)
|
28
27
|
tcell_body_proxy.meta_data = @meta_data
|
29
28
|
|
@@ -48,8 +47,7 @@ module TCellAgent
|
|
48
47
|
it 'should check for appfirewall injections' do
|
49
48
|
tcell_body_proxy = TCellBodyProxy.new(
|
50
49
|
Rack::BodyProxy.new(['body']) {},
|
51
|
-
|
52
|
-
nil, nil, nil, nil
|
50
|
+
nil, nil, {}
|
53
51
|
)
|
54
52
|
tcell_body_proxy.meta_data = @meta_data
|
55
53
|
|
@@ -78,8 +76,7 @@ module TCellAgent
|
|
78
76
|
it 'should return an enumerator' do
|
79
77
|
tcell_body_proxy = TCellBodyProxy.new(
|
80
78
|
Rack::BodyProxy.new(['body']) {},
|
81
|
-
|
82
|
-
nil, nil, nil, nil
|
79
|
+
nil, nil, {}
|
83
80
|
)
|
84
81
|
expect(tcell_body_proxy.each.class.name).to eq('Enumerator')
|
85
82
|
end
|
@@ -89,15 +86,16 @@ module TCellAgent
|
|
89
86
|
context 'with a chunked response' do
|
90
87
|
it 'should only calculate content length' do
|
91
88
|
tcell_body_proxy = TCellBodyProxy.new(
|
92
|
-
Rack::BodyProxy.new(["2d\r\nsome content\r\n"]) {},
|
93
|
-
|
94
|
-
nil, nil, nil, nil
|
89
|
+
Rack::BodyProxy.new(["2d\r\nsome content\r\n", "0\r\n"]) {},
|
90
|
+
nil, nil, { 'Transfer-Encoding' => 'chunked' }
|
95
91
|
)
|
96
92
|
|
97
93
|
expect(TCellAgent::Instrumentation).to receive(:safe_block).with(
|
98
94
|
'Processing tcell body proxy body'
|
99
95
|
).and_call_original
|
100
|
-
|
96
|
+
expect(TCellAgent::Instrumentation).to receive(:safe_block).with(
|
97
|
+
'Processing tcell body proxy body'
|
98
|
+
).and_call_original
|
101
99
|
tcell_body_proxy.each { |b| }
|
102
100
|
|
103
101
|
expect(tcell_body_proxy.content_length).to eq(45)
|
@@ -109,8 +107,7 @@ module TCellAgent
|
|
109
107
|
it 'should only calculate content length' do
|
110
108
|
tcell_body_proxy = TCellBodyProxy.new(
|
111
109
|
Rack::BodyProxy.new(['some content']) {},
|
112
|
-
|
113
|
-
nil, nil, nil, nil
|
110
|
+
nil, nil, {}
|
114
111
|
)
|
115
112
|
|
116
113
|
expect(TCellAgent::Instrumentation).to receive(:safe_block).with(
|
@@ -126,11 +123,9 @@ module TCellAgent
|
|
126
123
|
context 'that should be processed' do
|
127
124
|
it 'should call js and dlp procs as well as calculate content length' do
|
128
125
|
js_agent_insertion_proc = double('js_agent_insertion_proc')
|
129
|
-
dlp_cleaner_proc = double('dlp_cleaner_proc')
|
130
126
|
tcell_body_proxy = TCellBodyProxy.new(
|
131
127
|
Rack::BodyProxy.new(['some content']) {},
|
132
|
-
|
133
|
-
js_agent_insertion_proc, 'script_insert', dlp_cleaner_proc, nil
|
128
|
+
js_agent_insertion_proc, 'script_insert', {}
|
134
129
|
)
|
135
130
|
|
136
131
|
expect(TCellAgent::Instrumentation).to receive(:safe_block).with(
|
@@ -139,7 +134,6 @@ module TCellAgent
|
|
139
134
|
expect(js_agent_insertion_proc).to receive(:call).with(
|
140
135
|
'script_insert', 'some content'
|
141
136
|
).and_return('some content')
|
142
|
-
expect(dlp_cleaner_proc).to receive(:call).with(nil, 'some content')
|
143
137
|
|
144
138
|
tcell_body_proxy.each { |b| }
|
145
139
|
|
@@ -154,11 +148,9 @@ module TCellAgent
|
|
154
148
|
it 'should only calculate content length' do
|
155
149
|
body_chunk = 'some content'
|
156
150
|
js_agent_insertion_proc = double('js_agent_insertion_proc')
|
157
|
-
dlp_cleaner_proc = double('dlp_cleaner_proc')
|
158
151
|
tcell_body_proxy = TCellBodyProxy.new(
|
159
152
|
Rack::BodyProxy.new([body_chunk]) {},
|
160
|
-
|
161
|
-
nil, nil, nil, nil
|
153
|
+
nil, nil, {}
|
162
154
|
)
|
163
155
|
|
164
156
|
expect(TCellAgent::Instrumentation).to receive(:safe_block).with(
|
@@ -167,11 +159,7 @@ module TCellAgent
|
|
167
159
|
expect(body_chunk).to receive(:class).and_return(
|
168
160
|
double('body_class', :name => 'ActionView::OutputBuffer')
|
169
161
|
)
|
170
|
-
expect(body_chunk).to receive(:class).and_return(
|
171
|
-
double('body_class', :name => 'ActionView::OutputBuffer')
|
172
|
-
)
|
173
162
|
expect(js_agent_insertion_proc).to_not receive(:call)
|
174
|
-
expect(dlp_cleaner_proc).to_not receive(:call)
|
175
163
|
|
176
164
|
tcell_body_proxy.each { |b| }
|
177
165
|
|
@@ -183,11 +171,9 @@ module TCellAgent
|
|
183
171
|
it 'should call js and dlp procs as well as calculate content length' do
|
184
172
|
body_chunk = 'some content'
|
185
173
|
js_agent_insertion_proc = double('js_agent_insertion_proc')
|
186
|
-
dlp_cleaner_proc = double('dlp_cleaner_proc')
|
187
174
|
tcell_body_proxy = TCellBodyProxy.new(
|
188
175
|
Rack::BodyProxy.new([body_chunk]) {},
|
189
|
-
|
190
|
-
js_agent_insertion_proc, 'script_insert', dlp_cleaner_proc, nil
|
176
|
+
js_agent_insertion_proc, 'script_insert', {}
|
191
177
|
)
|
192
178
|
|
193
179
|
expect(TCellAgent::Instrumentation).to receive(:safe_block).with(
|
@@ -196,7 +182,6 @@ module TCellAgent
|
|
196
182
|
expect(js_agent_insertion_proc).to receive(:call).with(
|
197
183
|
'script_insert', body_chunk
|
198
184
|
).and_return(body_chunk)
|
199
|
-
expect(dlp_cleaner_proc).to receive(:call).with(nil, body_chunk)
|
200
185
|
|
201
186
|
tcell_body_proxy.each { |b| }
|
202
187
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tcell_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rapid7, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -272,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
272
|
- !ruby/object:Gem::Version
|
273
273
|
version: '0'
|
274
274
|
requirements: []
|
275
|
-
rubygems_version: 3.2.
|
275
|
+
rubygems_version: 3.2.32
|
276
276
|
signing_key:
|
277
277
|
specification_version: 4
|
278
278
|
summary: tCell Agent for Rails
|