tcell_agent 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +4 -0
  3. data/README.md +43 -0
  4. data/Rakefile +7 -0
  5. data/bin/tcell_agent +171 -0
  6. data/config/initializers/authlogic_auth.rb +51 -0
  7. data/config/initializers/devise_auth.rb +167 -0
  8. data/config/initializers/init.rb +8 -0
  9. data/lib/tcell_agent.rb +33 -0
  10. data/lib/tcell_agent/agent.rb +79 -0
  11. data/lib/tcell_agent/agent/event_processor.rb +133 -0
  12. data/lib/tcell_agent/agent/policy_manager.rb +138 -0
  13. data/lib/tcell_agent/agent/policy_types.rb +42 -0
  14. data/lib/tcell_agent/agent/static_agent.rb +22 -0
  15. data/lib/tcell_agent/api.rb +101 -0
  16. data/lib/tcell_agent/appsensor.rb +42 -0
  17. data/lib/tcell_agent/appsensor/cmdi.rb +32 -0
  18. data/lib/tcell_agent/appsensor/path_traversal.rb +33 -0
  19. data/lib/tcell_agent/appsensor/sqli.rb +55 -0
  20. data/lib/tcell_agent/appsensor/xss.rb +40 -0
  21. data/lib/tcell_agent/authlogic.rb +26 -0
  22. data/lib/tcell_agent/configuration.rb +148 -0
  23. data/lib/tcell_agent/dataloss.rb +0 -0
  24. data/lib/tcell_agent/devise.rb +83 -0
  25. data/lib/tcell_agent/instrumentation.rb +44 -0
  26. data/lib/tcell_agent/logger.rb +46 -0
  27. data/lib/tcell_agent/policies/add_script_tag_policy.rb +47 -0
  28. data/lib/tcell_agent/policies/appsensor_policy.rb +76 -0
  29. data/lib/tcell_agent/policies/clickjacking_policy.rb +113 -0
  30. data/lib/tcell_agent/policies/content_security_policy.rb +119 -0
  31. data/lib/tcell_agent/policies/dataloss_policy.rb +175 -0
  32. data/lib/tcell_agent/policies/honeytokens_policy.rb +67 -0
  33. data/lib/tcell_agent/policies/http_redirect_policy.rb +84 -0
  34. data/lib/tcell_agent/policies/http_tx_policy.rb +60 -0
  35. data/lib/tcell_agent/policies/login_fraud_policy.rb +42 -0
  36. data/lib/tcell_agent/policies/secure_headers_policy.rb +64 -0
  37. data/lib/tcell_agent/rails.rb +146 -0
  38. data/lib/tcell_agent/rails/devise.rb +0 -0
  39. data/lib/tcell_agent/rails/dlp.rb +204 -0
  40. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +69 -0
  41. data/lib/tcell_agent/rails/middleware/context_middleware.rb +50 -0
  42. data/lib/tcell_agent/rails/middleware/global_middleware.rb +53 -0
  43. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +176 -0
  44. data/lib/tcell_agent/rails/routes.rb +130 -0
  45. data/lib/tcell_agent/rails/settings_reporter.rb +40 -0
  46. data/lib/tcell_agent/sensor_events/app_config.rb +16 -0
  47. data/lib/tcell_agent/sensor_events/app_sensor.rb +240 -0
  48. data/lib/tcell_agent/sensor_events/dlp.rb +58 -0
  49. data/lib/tcell_agent/sensor_events/honeytokens.rb +16 -0
  50. data/lib/tcell_agent/sensor_events/login_fraud.rb +43 -0
  51. data/lib/tcell_agent/sensor_events/metrics.rb +24 -0
  52. data/lib/tcell_agent/sensor_events/sensor.rb +85 -0
  53. data/lib/tcell_agent/sensor_events/server_agent.rb +101 -0
  54. data/lib/tcell_agent/sensor_events/util/redirect_utils.rb +22 -0
  55. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +153 -0
  56. data/lib/tcell_agent/sensor_events/util/utils.rb +21 -0
  57. data/lib/tcell_agent/sinatra.rb +41 -0
  58. data/lib/tcell_agent/start_background_thread.rb +63 -0
  59. data/lib/tcell_agent/userinfo.rb +8 -0
  60. data/lib/tcell_agent/utils/queue_with_timeout.rb +60 -0
  61. data/lib/tcell_agent/version.rb +5 -0
  62. data/spec/controllers/application_controller.rb +12 -0
  63. data/spec/lib/tcell_agent/api/api_spec.rb +36 -0
  64. data/spec/lib/tcell_agent/appsensor_spec.rb +66 -0
  65. data/spec/lib/tcell_agent/policies/add_script_tag_policy_spec.rb +37 -0
  66. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +40 -0
  67. data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +71 -0
  68. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +71 -0
  69. data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +88 -0
  70. data/spec/lib/tcell_agent/policies/honeytokens_policy_spec.rb +22 -0
  71. data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +62 -0
  72. data/spec/lib/tcell_agent/policies/http_tx_policy_spec.rb +22 -0
  73. data/spec/lib/tcell_agent/policies/login_policy_spec.rb +42 -0
  74. data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +67 -0
  75. data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +187 -0
  76. data/spec/lib/tcell_agent/rails_spec.rb +57 -0
  77. data/spec/lib/tcell_agent/sensor_events/dlp_spec.rb +14 -0
  78. data/spec/lib/tcell_agent/sensor_events/util/redirect_utils_spec.rb +25 -0
  79. data/spec/lib/tcell_agent/sensor_events/util/sanitizer_utilities_spec.rb +57 -0
  80. data/spec/lib/tcell_agent_spec.rb +22 -0
  81. data/spec/resources/normal_config.json +13 -0
  82. data/spec/spec_helper.rb +4 -0
  83. data/tcell_agent.gemspec +29 -0
  84. metadata +249 -0
@@ -0,0 +1,175 @@
1
+ require 'set'
2
+
3
+ module TCellAgent
4
+ module Policies
5
+ class DataLossPolicy
6
+ class FilterActions
7
+ attr_accessor :body_event
8
+ attr_accessor :body_redact
9
+ attr_accessor :body_hash
10
+
11
+ attr_accessor :log_event
12
+ attr_accessor :log_redact
13
+ attr_accessor :log_hash
14
+ end
15
+
16
+ attr_accessor :session_id_filter_actions
17
+ attr_accessor :request_filter_actions
18
+ attr_accessor :database_filter_actions
19
+
20
+ # {
21
+ # {"context":[]}
22
+ # }
23
+
24
+ attr_accessor :policy_id
25
+
26
+ attr_accessor :table_field_actions
27
+ attr_accessor :session_id_actions
28
+
29
+ attr_accessor :field_redact_body
30
+ attr_accessor :field_alerts
31
+
32
+ def initialize
33
+ self.init_options
34
+ end
35
+ def init_options
36
+ @policy_id = nil
37
+
38
+ @table_field_actions = {}
39
+ @session_id_actions = []
40
+
41
+ @field_redact_body = Set.new #["work_infos.SSN"].to_set #
42
+ @field_alerts = Set.new
43
+
44
+ @session_id_filter_actions = nil
45
+ @request_filter_actions = {
46
+ "form"=>Hash.new{|h,k| h[k] = FilterActions.new},
47
+ "cookie"=>Hash.new{|h,k| h[k] = FilterActions.new},
48
+ "header"=>Hash.new{|h,k| h[k] = FilterActions.new}
49
+ }
50
+ @log_actions = nil
51
+ end
52
+ def get_actions_for_session_id(route_id=nil)
53
+ return @session_id_filter_actions
54
+ end
55
+ def get_actions_for_request(context, route_id=nil)
56
+ return @request_filter_actions.fetch(context)
57
+ end
58
+ def get_actions_for(table, field)
59
+ actions = Set.new
60
+ key = "#{table}.#{field}"
61
+ actions.merge(@table_field_actions.fetch(key,[].to_set))
62
+ #if (@field_redact_body.include?(key))
63
+ # actions += ["body_redact"]
64
+ #end
65
+ #if (@field_redact_log.include?(key))
66
+ # actions += ["log_redact"]
67
+ #end
68
+ return actions
69
+ end
70
+ def self.fromJson(policy_json)
71
+ if (!policy_json)
72
+ return nil
73
+ end
74
+ policy = DataLossPolicy.new
75
+ if policy_json.has_key?("policy_id")
76
+ policy.policy_id = policy_json["policy_id"]
77
+ else
78
+ raise "Policy ID missing"
79
+ end
80
+ if policy_json.has_key?("data")
81
+ data_json = policy_json["data"]
82
+ if data_json.has_key?("session_id_protection")
83
+ session_id_protection = data_json["session_id_protection"]
84
+ if session_id_protection.fetch("body",nil)
85
+ if (session_id_protection["body"].include? "redact")
86
+ policy.session_id_filter_actions ||= FilterActions.new
87
+ policy.session_id_filter_actions.body_redact = true
88
+ end
89
+ if (session_id_protection["body"].include? "event")
90
+ policy.session_id_filter_actions ||= FilterActions.new
91
+ policy.session_id_filter_actions.body_event = true
92
+ end
93
+ if (session_id_protection["body"].include? "hash")
94
+ policy.session_id_filter_actions ||= FilterActions.new
95
+ policy.session_id_filter_actions.body_hash = true
96
+ end
97
+ end
98
+ if session_id_protection.fetch("log",nil)
99
+ if (session_id_protection["log"].include? "redact")
100
+ policy.session_id_filter_actions ||= FilterActions.new
101
+ policy.session_id_filter_actions.log_redact = true
102
+ end
103
+ if (session_id_protection["log"].include? "event")
104
+ policy.session_id_filter_actions ||= FilterActions.new
105
+ policy.session_id_filter_actions.log_event = true
106
+ end
107
+ if (session_id_protection["log"].include? "hash")
108
+ policy.session_id_filter_actions ||= FilterActions.new
109
+ policy.session_id_filter_actions.log_hash = true
110
+ end
111
+ end
112
+ end
113
+ if data_json.has_key?("request_protections")
114
+ data_json["request_protections"].each do |protection|
115
+ context = protection.fetch('context', nil)
116
+ variable = protection.fetch('variable', nil)
117
+ scope = protection.fetch('scope', "global")
118
+ options = protection.fetch('options', nil)
119
+ if scope != "global"
120
+ next
121
+ end
122
+ if context && policy.request_filter_actions.has_key?(context) && variable && options
123
+ if options.has_key?("log")
124
+ if (options["log"].include? "redact")
125
+ policy.request_filter_actions[context][variable].log_redact = true
126
+ end
127
+ if (options["log"].include? "event")
128
+ policy.request_filter_actions[context][variable].log_event = true
129
+ end
130
+ if (options["log"].include? "hash")
131
+ policy.request_filter_actions[context][variable].log_hash = true
132
+ end
133
+ end
134
+ if options.has_key?("body")
135
+ if (options["body"].include? "redact")
136
+ policy.request_filter_actions[context][variable].body_redact = true
137
+ end
138
+ if (options["body"].include? "event")
139
+ policy.request_filter_actions[context][variable].body_event = true
140
+ end
141
+ if (options["body"].include? "hash")
142
+ policy.request_filter_actions[context][variable].body_hash = true
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ if data_json.has_key?("protections")
149
+ protections_json = data_json["protections"]
150
+ protections_json.each do |protection|
151
+ _table = protection.fetch("table", nil)
152
+ _field = protection.fetch("field", nil)
153
+ actions = protection.fetch("actions", {})
154
+ if actions.fetch("body",nil)
155
+ if (actions["body"].include? "redact")
156
+ if (_table && _field)
157
+ (policy.table_field_actions["#{_table}.#{_field}"] ||= []) << "body_redact"
158
+ end
159
+ end
160
+ end
161
+ if actions.fetch("log",nil)
162
+ if (actions["log"].include? "redact")
163
+ if (_table && _field)
164
+ (policy.table_field_actions["#{_table}.#{_field}"] ||= []) << "log_redact"
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ return policy
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,67 @@
1
+ # See the file "LICENSE" for the full license governing this code.
2
+
3
+ #String sh_policy_string = ""
4
+ #+"{"
5
+ #+"\"policy_id\":\"00a1\","
6
+ #+"\"token_salt\":\"salt123\","
7
+ #+"\"tokens\": ["
8
+ #+" {\"type\":\"cred\", \"id\":\"deny\", \"token\":\"abcdefgh\"}"
9
+ #+" ]"
10
+ #+"}";
11
+ require 'pbkdf2'
12
+ require 'openssl'
13
+
14
+ module TCellAgent
15
+ module Policies
16
+ class HoneytokensPolicy
17
+ attr_accessor :policy_id
18
+ attr_accessor :token_salt
19
+ attr_accessor :cred_tokens
20
+
21
+ def id_for_credentialstring(credential_string)
22
+ if cred_tokens
23
+ credential_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), token_salt, credential_string)
24
+ if cred_tokens.has_key?(credential_hmac)
25
+ return cred_tokens[credential_hmac]
26
+ end
27
+ end
28
+ return nil
29
+ end
30
+
31
+ def self.fromJson(policy_json)
32
+ if (!policy_json)
33
+ return nil
34
+ end
35
+
36
+ honeytokens_policy = HoneytokensPolicy.new
37
+ if policy_json.has_key?("policy_id")
38
+ honeytokens_policy.policy_id = policy_json["policy_id"]
39
+ else
40
+ raise "Policy ID missing"
41
+ end
42
+
43
+ if policy_json.has_key?("token_salt")
44
+ honeytokens_policy.token_salt = policy_json["token_salt"]
45
+ else
46
+ raise "Token Salt missing"
47
+ end
48
+
49
+ if policy_json.has_key?("tokens")
50
+ tokens = policy_json["tokens"]
51
+ tokens.each do |token|
52
+ if (token.has_key?("type") && token.has_key?("id") && token.has_key?("token"))
53
+ if (token["type"] == "cred")
54
+ if honeytokens_policy.cred_tokens == nil
55
+ honeytokens_policy.cred_tokens = {}
56
+ end
57
+ honeytokens_policy.cred_tokens[token["token"]] = token["id"]
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ return honeytokens_policy
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,84 @@
1
+ # See the file "LICENSE" for the full license governing this code.
2
+ require 'uri'
3
+ require 'tcell_agent/logger'
4
+ require 'tcell_agent/sensor_events/util/redirect_utils'
5
+ # See the file "LICENSE" for the full license governing this code.
6
+
7
+ #{}"http-tx": {
8
+ # "policy_id":"afh023",
9
+ # "types": {
10
+ # "firehose": { enabled: true },
11
+ #{}"auth_framework_only": {enabled: true},
12
+ #{}"{}structure": {enabled: true },
13
+ #{}"fingerprint": {enabled: true }
14
+ #}
15
+ #},
16
+
17
+ module TCellAgent
18
+ module Policies
19
+ class HttpRedirectPolicy
20
+ attr_accessor :policy_id
21
+ attr_accessor :enabled
22
+ attr_accessor :whitelist
23
+ attr_accessor :block
24
+ def initialize
25
+ @policy_id = nil
26
+ @enabled = false
27
+ @whitelist = []
28
+ @block = false
29
+ end
30
+ def check(host, current_host)
31
+ if (!(host) || host == "" || host == current_host)
32
+ # local redirect
33
+ return false
34
+ end
35
+ if (whitelist)
36
+ whitelist.each do |domain|
37
+ if (TCellAgent::SensorEvents::Util.wildcardMatch(host, domain))
38
+ return false
39
+ end
40
+ end
41
+ end
42
+ return true
43
+ end
44
+ def enforce(target_url, current_host, current_path, method, status_code, remote_addr)
45
+ if @enabled == false
46
+ return nil
47
+ end
48
+ uri = URI.parse(target_url)
49
+ host = uri.host
50
+ if self.check(host, current_host) == false
51
+ return nil
52
+ end
53
+ begin
54
+ event = TCellAgent::SensorEvents::TCellRedirectSensorEvent.new(host, current_host, current_path, method, status_code, remote_addr)
55
+ TCellAgent.send_event(event)
56
+ rescue Exception => ie
57
+ TCellAgent.logger.error("uncaught exception while creating redirect event: #{ie.message}")
58
+ end
59
+ if @block == true
60
+ return "/"
61
+ end
62
+ return nil
63
+ end
64
+ def self.fromJson(policy_json)
65
+ if (!policy_json)
66
+ return nil
67
+ end
68
+ http_redirect_policy = HttpRedirectPolicy.new
69
+ if policy_json.has_key?("policy_id")
70
+ http_redirect_policy.policy_id = policy_json["policy_id"]
71
+ else
72
+ raise "Policy ID missing"
73
+ end
74
+ if policy_json.has_key?("data")
75
+ policy_data_json = policy_json["data"]
76
+ http_redirect_policy.enabled = policy_data_json.fetch("enabled", false)
77
+ http_redirect_policy.whitelist = policy_data_json.fetch("whitelist", [])
78
+ http_redirect_policy.block = policy_data_json.fetch("block", false)
79
+ end
80
+ return http_redirect_policy
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,60 @@
1
+ #{}"http-tx": {
2
+ # "policy_id":"afh023",
3
+ # "types": {
4
+ # "firehose": { enabled: true },
5
+ #{}"auth_framework_only": {enabled: true},
6
+ #{}"{}structure": {enabled: true },
7
+ #{}"fingerprint": {enabled: true }
8
+ #}
9
+ #},
10
+
11
+ module TCellAgent
12
+ module Policies
13
+ class HttpTxPolicy
14
+ attr_accessor :policy_id
15
+ attr_accessor :firehose
16
+ attr_accessor :auth_framework
17
+ attr_accessor :profile
18
+ attr_accessor :fingerprint
19
+
20
+ def initialize()
21
+ @firehose = {"enabled"=>false, "lite"=>false }
22
+ @auth_framework = {"enabled"=>false, "lite"=>false }
23
+ @profile = {"enabled"=>false }
24
+ @fingerprint = {"enabled"=>false, "hmacUserAgent"=>false, "hmacUserId"=>false, "sampling"=>nil }
25
+ end
26
+ def self.fromJson(policy_json)
27
+ if (!policy_json)
28
+ return nil
29
+ end
30
+ http_tx_policy = HttpTxPolicy.new
31
+ if policy_json.has_key?("policy_id")
32
+ http_tx_policy.policy_id = policy_json["policy_id"]
33
+ else
34
+ raise "Policy ID missing"
35
+ end
36
+ if policy_json.has_key?("types")
37
+ types = policy_json["types"]
38
+ if types.has_key?("firehose")
39
+ http_tx_policy.firehose["enabled"] = types["firehose"].fetch("enabled", false)
40
+ http_tx_policy.firehose["lite"] = types["firehose"].fetch("lite", false)
41
+ end
42
+ if types.has_key?("auth_framework")
43
+ http_tx_policy.auth_framework["enabled"] = types["auth_framework"].fetch("enabled", false)
44
+ http_tx_policy.auth_framework["lite"] = types["auth_framework"].fetch("lite", false)
45
+ end
46
+ if types.has_key?("profile")
47
+ http_tx_policy.profile["enabled"] = types["profile"].fetch("enabled", false)
48
+ end
49
+ if types.has_key?("fingerprint")
50
+ http_tx_policy.fingerprint["enabled"] = types["fingerprint"].fetch("enabled", false)
51
+ http_tx_policy.fingerprint["hmacUserAgent"] = types["fingerprint"].fetch("hmacUserAgent", false)
52
+ http_tx_policy.fingerprint["hmacUserId"] = types["fingerprint"].fetch("hmacUserId", false)
53
+ http_tx_policy.fingerprint["sampling"] = types["fingerprint"].fetch("sampling", 0)
54
+ end
55
+ end
56
+ return http_tx_policy
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,42 @@
1
+ module TCellAgent
2
+ module Policies
3
+ class LoginFraudPolicy
4
+ attr_accessor :policy_id
5
+
6
+ attr_accessor :login_success_enabled
7
+ attr_accessor :login_failed_enabled
8
+
9
+ def initialize
10
+ self.init_options
11
+ end
12
+ def init_options
13
+ @policy_id = nil
14
+ @login_success_enabled = false
15
+ @login_failed_enabled = false
16
+ end
17
+ def enabled
18
+ @login_success_enabled || @login_failed_enabled
19
+ end
20
+ def self.fromJson(policy_json)
21
+ if (!policy_json)
22
+ return nil
23
+ end
24
+ sensor_policy = LoginFraudPolicy.new
25
+ if policy_json.has_key?("policy_id")
26
+ sensor_policy.policy_id = policy_json["policy_id"]
27
+ else
28
+ raise "Policy ID missing"
29
+ end
30
+ if policy_json.has_key?("data")
31
+ data_json = policy_json["data"]
32
+ if data_json.has_key?("options")
33
+ options_json = data_json["options"]
34
+ sensor_policy.login_failed_enabled = options_json.fetch("login_failed_enabled", false)
35
+ sensor_policy.login_success_enabled = options_json.fetch("login_success_enabled", false)
36
+ end
37
+ end
38
+ return sensor_policy
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+ # See the file "LICENSE" for the full license governing this code.
3
+ module TCellAgent
4
+ module Policies
5
+ class SecureHeadersPolicy
6
+ class SecurityHeader
7
+ @@approved_headers = [
8
+ "strict-transport-security",
9
+ "x-frame-options",
10
+ "x-xss-protection",
11
+ "x-content-type-options",
12
+ "x-permitted-cross-domain-policies",
13
+ "x-download-options"
14
+ ]
15
+ attr_accessor :name
16
+ attr_accessor :value
17
+ def initialize(name, value)
18
+ if !(name && value)
19
+ raise "Name and value were not set"
20
+ end
21
+ if not @@approved_headers.include?(name.downcase)
22
+ raise "Name was not included in approved_headers"
23
+ end
24
+ if value != value.gsub(/[^\p{L}\w\d\-_\ :\/,;.'\*"%?@#=$]/,'')
25
+ raise "Value is not valid"
26
+ end
27
+ self.name = name
28
+ self.value = value
29
+ end
30
+ end
31
+
32
+ attr_accessor :headers
33
+ attr_accessor :policy_id
34
+
35
+ def self.fromJson(policy_json)
36
+ if (!policy_json)
37
+ return nil
38
+ end
39
+ security_headers_policy = SecureHeadersPolicy.new
40
+ if policy_json.has_key?("policy_id")
41
+ security_headers_policy.policy_id = policy_json["policy_id"]
42
+ else
43
+ raise "Policy ID missing"
44
+ end
45
+ security_headers = []
46
+ if policy_json.has_key?("headers")
47
+ headers = policy_json["headers"]
48
+ headers.each do |header|
49
+ if header.has_key?("name") && header.has_key?("value")
50
+ begin
51
+ security_header = SecurityHeader.new(header["name"], header["value"])
52
+ security_headers.push(security_header)
53
+ rescue Exception => secure_header_exception
54
+ TCellAgent.logger.debug("Could not load secure header:" + secure_header_exception.message)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ security_headers_policy.headers = security_headers
60
+ return security_headers_policy
61
+ end
62
+ end
63
+ end
64
+ end