tcell_agent 1.0.0 → 1.1.0
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/Readme.txt +7 -0
- data/bin/tcell_agent +6 -2
- data/lib/tcell_agent.rb +0 -3
- data/lib/tcell_agent/agent/event_processor.rb +1 -4
- data/lib/tcell_agent/agent/policy_manager.rb +5 -8
- data/lib/tcell_agent/agent/policy_types.rb +1 -7
- data/lib/tcell_agent/agent/static_agent.rb +2 -2
- data/lib/tcell_agent/api.rb +7 -9
- data/lib/tcell_agent/configuration.rb +42 -6
- data/lib/tcell_agent/policies/rust_policies.rb +33 -8
- data/lib/tcell_agent/rails/js_agent_insert.rb +17 -18
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +18 -59
- data/lib/tcell_agent/rails/tcell_body_proxy.rb +10 -6
- data/lib/tcell_agent/rust/libtcellagent-0.19.5.dylib +0 -0
- data/lib/tcell_agent/rust/{libtcellagent-0.11.1.so → libtcellagent-0.19.5.so} +0 -0
- data/lib/tcell_agent/rust/tcellagent-0.19.5.dll +0 -0
- data/lib/tcell_agent/rust/whisperer.rb +165 -39
- data/lib/tcell_agent/sensor_events/patches.rb +2 -0
- data/lib/tcell_agent/sinatra.rb +17 -14
- data/lib/tcell_agent/version.rb +1 -1
- data/spec/lib/tcell_agent/agent/policy_manager_spec.rb +17 -0
- data/spec/lib/tcell_agent/api/api_spec.rb +10 -7
- data/spec/lib/tcell_agent/cmdi_spec.rb +91 -80
- data/spec/lib/tcell_agent/instrumentation_spec.rb +20 -0
- data/spec/lib/tcell_agent/patches_spec.rb +33 -15
- data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +150 -99
- data/spec/lib/tcell_agent/policies/command_injection_policy_spec.rb +13 -1
- data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +12 -0
- data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +2 -39
- data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +6 -2
- data/spec/lib/tcell_agent/rails_spec.rb +0 -31
- data/spec/lib/tcell_agent/rust/whisperer_spec.rb +234 -120
- data/tcell_agent.gemspec +1 -1
- metadata +21 -40
- data/lib/tcell_agent/policies/clickjacking_policy.rb +0 -114
- data/lib/tcell_agent/policies/content_security_policy.rb +0 -166
- data/lib/tcell_agent/policies/secure_headers_policy.rb +0 -67
- data/lib/tcell_agent/rust/libtcellagent-0.11.1.dylib +0 -0
- data/lib/tcell_agent/rust/tcellagent-0.11.1.dll +0 -0
- data/spec/apps/rails-3.2/config/tcell_agent.config +0 -15
- data/spec/apps/rails-3.2/log/development.log +0 -0
- data/spec/apps/rails-3.2/log/test.log +0 -12
- data/spec/apps/rails-4.1/log/test.log +0 -0
- data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +0 -71
- data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +0 -130
- data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +0 -67
- data/spec/lib/tcell_agent_spec.rb +0 -22
@@ -1,67 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# See the file "LICENSE" for the full license governing this code.
|
3
|
-
require 'tcell_agent/policies/policy'
|
4
|
-
|
5
|
-
|
6
|
-
module TCellAgent
|
7
|
-
module Policies
|
8
|
-
class SecureHeadersPolicy < Policy
|
9
|
-
class SecurityHeader
|
10
|
-
@@approved_headers = [
|
11
|
-
"strict-transport-security",
|
12
|
-
"x-frame-options",
|
13
|
-
"x-xss-protection",
|
14
|
-
"x-content-type-options",
|
15
|
-
"x-permitted-cross-domain-policies",
|
16
|
-
"x-download-options"
|
17
|
-
]
|
18
|
-
attr_accessor :name
|
19
|
-
attr_accessor :value
|
20
|
-
def initialize(name, value)
|
21
|
-
if !(name && value)
|
22
|
-
raise "Name and value were not set"
|
23
|
-
end
|
24
|
-
if !@@approved_headers.include?(name.downcase)
|
25
|
-
raise "Name was not included in approved_headers"
|
26
|
-
end
|
27
|
-
if value != value.gsub(/[^\p{L}\w\d\-_\ :\/,;.'\*"%?@#=$]/,'')
|
28
|
-
raise "Value is not valid"
|
29
|
-
end
|
30
|
-
self.name = name
|
31
|
-
self.value = value
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
attr_accessor :headers
|
36
|
-
attr_accessor :policy_id
|
37
|
-
|
38
|
-
def self.from_json(policy_json)
|
39
|
-
if (!policy_json)
|
40
|
-
return nil
|
41
|
-
end
|
42
|
-
security_headers_policy = SecureHeadersPolicy.new
|
43
|
-
if policy_json.has_key?("policy_id")
|
44
|
-
security_headers_policy.policy_id = policy_json["policy_id"]
|
45
|
-
else
|
46
|
-
raise "Policy ID missing"
|
47
|
-
end
|
48
|
-
security_headers = []
|
49
|
-
if policy_json.has_key?("headers")
|
50
|
-
headers = policy_json["headers"]
|
51
|
-
headers.each do |header|
|
52
|
-
if header.has_key?("name") && header.has_key?("value")
|
53
|
-
begin
|
54
|
-
security_header = SecurityHeader.new(header["name"], header["value"])
|
55
|
-
security_headers.push(security_header)
|
56
|
-
rescue StandardError => secure_header_exception
|
57
|
-
TCellAgent.logger.debug("Could not load secure header:" + secure_header_exception.message)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
security_headers_policy.headers = security_headers
|
63
|
-
return security_headers_policy
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
Binary file
|
Binary file
|
@@ -1,15 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"version":1,
|
3
|
-
"applications":
|
4
|
-
[
|
5
|
-
{
|
6
|
-
"name":"<name>",
|
7
|
-
"api_key":"<apikey>",
|
8
|
-
"fetch_policies_from_tcell":false,
|
9
|
-
"tcell_input_url":"https://localhost/",
|
10
|
-
"preload_policy_filename":"config/tcell_preload.json",
|
11
|
-
"logging_options":{"enabled":true, "level":"DEBUG"}
|
12
|
-
}
|
13
|
-
]
|
14
|
-
}
|
15
|
-
|
File without changes
|
@@ -1,12 +0,0 @@
|
|
1
|
-
Connecting to database specified by DATABASE_URL
|
2
|
-
Connecting to database specified by DATABASE_URL
|
3
|
-
Connecting to database specified by DATABASE_URL
|
4
|
-
Connecting to database specified by DATABASE_URL
|
5
|
-
Connecting to database specified by DATABASE_URL
|
6
|
-
Connecting to database specified by DATABASE_URL
|
7
|
-
Connecting to database specified by DATABASE_URL
|
8
|
-
Connecting to database specified by DATABASE_URL
|
9
|
-
Connecting to database specified by DATABASE_URL
|
10
|
-
Connecting to database specified by DATABASE_URL
|
11
|
-
Connecting to database specified by DATABASE_URL
|
12
|
-
Connecting to database specified by DATABASE_URL
|
File without changes
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module TCellAgent
|
4
|
-
module Policies
|
5
|
-
describe ClickjackingPolicy do
|
6
|
-
content_security_policy_json = {
|
7
|
-
'policy_id' => '00a1',
|
8
|
-
'headers' => [
|
9
|
-
{ 'name' => 'csp', 'value' => 'csp header value' }
|
10
|
-
]
|
11
|
-
}
|
12
|
-
csp_from_json = ClickjackingPolicy.from_json(content_security_policy_json)
|
13
|
-
context 'initialized with 3 items' do
|
14
|
-
it 'returns true' do
|
15
|
-
expect(csp_from_json.policy_id).to eq('00a1')
|
16
|
-
expect(csp_from_json.headers[0].type).to eq('csp')
|
17
|
-
expect(csp_from_json.headers[0].value).to eq('csp header value')
|
18
|
-
end
|
19
|
-
end
|
20
|
-
context 'headers match up appropriately' do
|
21
|
-
it 'returns content-security-policy headers' do
|
22
|
-
expect(ClickjackingPolicy.cspHeadersForType('csp')).to match_array(['Content-Security-Policy']) # ,"X-Content-Security-Policy","X-WebKit-CSP"])
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
describe ContentSecurityPolicy do
|
27
|
-
content_security_policy_json = {
|
28
|
-
'policy_id' => '01a1',
|
29
|
-
'headers' => [
|
30
|
-
{ 'name' => 'csp-header-is-bad', 'value' => 'csp header value' }
|
31
|
-
]
|
32
|
-
}
|
33
|
-
csp_policy = ClickjackingPolicy.from_json(content_security_policy_json)
|
34
|
-
context 'csp header example, invalid header' do
|
35
|
-
it 'returns false' do
|
36
|
-
expect(csp_policy.headers.length).to eq(0)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
describe ClickjackingPolicy do
|
41
|
-
content_security_policy_json = {
|
42
|
-
'policy_id' => '01a1',
|
43
|
-
'headers' => [
|
44
|
-
{ 'name' => 'csp', 'value' => 'value123\\nabc' }
|
45
|
-
]
|
46
|
-
}
|
47
|
-
csp_policy = ClickjackingPolicy.from_json(content_security_policy_json)
|
48
|
-
context 'secure header, value is bad' do
|
49
|
-
it 'returns false' do
|
50
|
-
expect(csp_policy.headers.length).to eq(0)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
describe ClickjackingPolicy do
|
55
|
-
content_security_policy_json = {
|
56
|
-
'policy_id' => '01a1',
|
57
|
-
'headers' => [
|
58
|
-
{ 'name' => 'csp', 'value' => 'value normal', 'report-uri' => 'https://example.com/abcdde' }
|
59
|
-
]
|
60
|
-
}
|
61
|
-
csp_policy = ClickjackingPolicy.from_json(content_security_policy_json)
|
62
|
-
context 'secure header, report-uri seperate' do
|
63
|
-
it 'returns false' do
|
64
|
-
expect(csp_policy.headers.length).to eq(1)
|
65
|
-
expect(csp_policy.headers[0].value).to eq('value normal; report-uri https://example.com/abcdde')
|
66
|
-
expect(csp_policy.headers[0].value('1', '2', '3')).to eq('value normal; report-uri https://example.com/abcdde?tid=1&sid=2&uid=3')
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,130 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module TCellAgent
|
4
|
-
module Policies
|
5
|
-
describe ContentSecurityPolicy do
|
6
|
-
context 'test empty agent' do
|
7
|
-
it 'enabled is false' do
|
8
|
-
policy_json_empty = {
|
9
|
-
'policy_id' => '01a1',
|
10
|
-
'data' => {
|
11
|
-
'options' => {
|
12
|
-
|
13
|
-
}
|
14
|
-
}
|
15
|
-
}
|
16
|
-
|
17
|
-
empty_policy = ContentSecurityPolicy.from_json(policy_json_empty)
|
18
|
-
|
19
|
-
expect(empty_policy.policy_id).to eq('01a1')
|
20
|
-
expect(empty_policy.js_agent_api_key).to eq(nil)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
context 'tests xss is true and enabled true' do
|
25
|
-
it 'returns true' do
|
26
|
-
policy_json_one = {
|
27
|
-
'policy_id' => '01a1',
|
28
|
-
'data' => {
|
29
|
-
'options' => {
|
30
|
-
'js_agent_api_key' => '000-000-1'
|
31
|
-
}
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
from_json = ContentSecurityPolicy.from_json(policy_json_one)
|
36
|
-
|
37
|
-
expect(from_json.policy_id).to eq('01a1')
|
38
|
-
expect(from_json.js_agent_api_key).to eq('000-000-1')
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context 'initialized with 3 items' do
|
43
|
-
it 'returns true' do
|
44
|
-
content_security_policy_json = {
|
45
|
-
'policy_id' => '00a1',
|
46
|
-
'headers' => [
|
47
|
-
{ 'name' => 'csp', 'value' => 'csp header value' }
|
48
|
-
]
|
49
|
-
}
|
50
|
-
|
51
|
-
csp_from_json = ContentSecurityPolicy.from_json(content_security_policy_json)
|
52
|
-
|
53
|
-
expect(csp_from_json.policy_id).to eq('00a1')
|
54
|
-
expect(csp_from_json.headers[0].type).to eq('csp')
|
55
|
-
expect(csp_from_json.headers[0].value).to eq('csp header value')
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'headers match up appropriately' do
|
60
|
-
it 'returns content-security-policy headers' do
|
61
|
-
expect(ContentSecurityPolicy.cspHeadersForType('csp')).to match_array(['Content-Security-Policy'])
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'csp header example, invalid header' do
|
66
|
-
it 'returns false' do
|
67
|
-
content_security_policy_json = {
|
68
|
-
'policy_id' => '01a1',
|
69
|
-
'headers' => [
|
70
|
-
{ 'name' => 'csp-header-is-bad', 'value' => 'csp header value' }
|
71
|
-
]
|
72
|
-
}
|
73
|
-
|
74
|
-
csp_policy = ContentSecurityPolicy.from_json(content_security_policy_json)
|
75
|
-
|
76
|
-
expect(csp_policy.headers.length).to eq(0)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
context 'secure header, value is bad' do
|
81
|
-
it 'returns false' do
|
82
|
-
content_security_policy_json = {
|
83
|
-
'policy_id' => '01a1',
|
84
|
-
'headers' => [
|
85
|
-
{ 'name' => 'csp', 'value' => 'value123\\nabc' }
|
86
|
-
]
|
87
|
-
}
|
88
|
-
csp_policy = ContentSecurityPolicy.from_json(content_security_policy_json)
|
89
|
-
expect(csp_policy.headers.length).to eq(0)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context 'secure header, report-uri seperate' do
|
94
|
-
it 'returns false' do
|
95
|
-
content_security_policy_json = {
|
96
|
-
'policy_id' => '01a1',
|
97
|
-
'headers' => [
|
98
|
-
{ 'name' => 'csp', 'value' => 'value normal', 'report-uri' => 'https://example.com/abcdde' }
|
99
|
-
]
|
100
|
-
}
|
101
|
-
|
102
|
-
csp_policy = ContentSecurityPolicy.from_json(content_security_policy_json)
|
103
|
-
|
104
|
-
expect(csp_policy.headers.length).to eq(1)
|
105
|
-
expect(csp_policy.headers[0].value).to eq('value normal; report-uri https://example.com/abcdde?c=-815891691')
|
106
|
-
expect(csp_policy.headers[0].value('1', '2', '3')).to eq('value normal; report-uri https://example.com/abcdde?tid=1&sid=3&rid=2&c=1777384531')
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
context 'default js_agent_url' do
|
111
|
-
it 'should have the configuration set to the default js_agent_url value' do
|
112
|
-
expect(TCellAgent.configuration.js_agent_url).to eq('https://jsagent.tcell.io/tcellagent.min.js')
|
113
|
-
|
114
|
-
content_security_policy_json = {
|
115
|
-
'policy_id' => '01a1',
|
116
|
-
'headers' => [
|
117
|
-
{ 'name' => 'csp', 'value' => "script-src 'unsafe-inline' 'unsafe-eval' 'self' https://api.tcell.io/" }
|
118
|
-
]
|
119
|
-
}
|
120
|
-
|
121
|
-
csp_policy = ContentSecurityPolicy.from_json(content_security_policy_json)
|
122
|
-
|
123
|
-
expect(csp_policy.headers.length).to eq(1)
|
124
|
-
expect(csp_policy.headers[0].value).to eq("script-src 'unsafe-inline' 'unsafe-eval' 'self' https://api.tcell.io/")
|
125
|
-
expect(TCellAgent.configuration.js_agent_url).to eq('https://jsagent.tcell.io/tcellagent.min.js')
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module TCellAgent
|
4
|
-
module Policies
|
5
|
-
describe SecureHeadersPolicy do
|
6
|
-
secure_headers_policy_json = {
|
7
|
-
'policy_id' => '01a1',
|
8
|
-
'headers' => [
|
9
|
-
{ 'name' => 'x-permitted-cross-domain-policies', 'value' => 'value123' }
|
10
|
-
]
|
11
|
-
}
|
12
|
-
secure_headers_policy = SecureHeadersPolicy.from_json(secure_headers_policy_json)
|
13
|
-
context 'secure header example' do
|
14
|
-
it 'returns true' do
|
15
|
-
expect(secure_headers_policy.headers[0].name).to eq('x-permitted-cross-domain-policies')
|
16
|
-
expect(secure_headers_policy.headers[0].value).to eq('value123')
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
describe SecureHeadersPolicy do
|
21
|
-
secure_headers_policy_json = {
|
22
|
-
'policy_id' => '01a1',
|
23
|
-
'headers' => [
|
24
|
-
{ 'name' => 'x-frame-options', 'value' => 'DENY' },
|
25
|
-
{ 'name' => 'x-xss-protection', 'value' => '1; mode=block' }
|
26
|
-
]
|
27
|
-
}
|
28
|
-
secure_headers_policy = SecureHeadersPolicy.from_json(secure_headers_policy_json)
|
29
|
-
context 'secure headers (2) example' do
|
30
|
-
it 'returns true' do
|
31
|
-
expect(secure_headers_policy.headers[0].name).to eq('x-frame-options')
|
32
|
-
expect(secure_headers_policy.headers[0].value).to eq('DENY')
|
33
|
-
expect(secure_headers_policy.headers[1].name).to eq('x-xss-protection')
|
34
|
-
expect(secure_headers_policy.headers[1].value).to eq('1; mode=block')
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
describe SecureHeadersPolicy do
|
39
|
-
secure_headers_policy_json = {
|
40
|
-
'policy_id' => '01a1',
|
41
|
-
'headers' => [
|
42
|
-
{ 'name' => 'bad-header', 'value' => 'value123' }
|
43
|
-
]
|
44
|
-
}
|
45
|
-
secure_headers_policy = SecureHeadersPolicy.from_json(secure_headers_policy_json)
|
46
|
-
context 'secure header example, invalid header' do
|
47
|
-
it 'returns false' do
|
48
|
-
expect(secure_headers_policy.headers.length).to eq(0)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
describe SecureHeadersPolicy do
|
53
|
-
secure_headers_policy_json = {
|
54
|
-
'policy_id' => '01a1',
|
55
|
-
'headers' => [
|
56
|
-
{ 'name' => 'x-permitted-cross-domain-policies', 'value' => 'value123\\nabc' }
|
57
|
-
]
|
58
|
-
}
|
59
|
-
secure_headers_policy = SecureHeadersPolicy.from_json(secure_headers_policy_json)
|
60
|
-
context 'secure header, value is bad' do
|
61
|
-
it 'returns false' do
|
62
|
-
expect(secure_headers_policy.headers.length).to eq(0)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module TCellAgent
|
4
|
-
describe Agent do
|
5
|
-
context 'Agent Read File' do
|
6
|
-
agent_worker = Agent.new(0)
|
7
|
-
it 'Reads in a policy file' do
|
8
|
-
policy_file_json = {
|
9
|
-
'csp-headers' => {
|
10
|
-
'policy_id' => '00a1',
|
11
|
-
'headers' => [
|
12
|
-
{ 'name' => 'csp', 'value' => 'csp loaded header' }
|
13
|
-
]
|
14
|
-
}
|
15
|
-
}
|
16
|
-
agent_worker.processPolicyJson(policy_file_json)
|
17
|
-
expect(agent_worker.policies[TCellAgent::PolicyTypes::CSP].headers[0].type).to eq('csp')
|
18
|
-
expect(agent_worker.policies[TCellAgent::PolicyTypes::CSP].headers[0].value).to eq('csp loaded header')
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|