dd-trace 2.31.0 → 2.32.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.
Files changed (58) hide show
  1. package/package.json +6 -6
  2. package/packages/datadog-instrumentations/src/body-parser.js +15 -9
  3. package/packages/datadog-instrumentations/src/express.js +32 -0
  4. package/packages/datadog-instrumentations/src/http/server.js +2 -1
  5. package/packages/datadog-instrumentations/src/playwright.js +3 -0
  6. package/packages/datadog-plugin-amqp10/src/consumer.js +1 -3
  7. package/packages/datadog-plugin-amqp10/src/producer.js +1 -3
  8. package/packages/datadog-plugin-amqplib/src/client.js +4 -3
  9. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -3
  10. package/packages/datadog-plugin-amqplib/src/producer.js +1 -3
  11. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -3
  12. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -3
  13. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -3
  14. package/packages/datadog-plugin-http/src/server.js +2 -2
  15. package/packages/datadog-plugin-http2/src/server.js +0 -5
  16. package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -4
  17. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -3
  18. package/packages/datadog-plugin-rhea/src/consumer.js +1 -3
  19. package/packages/datadog-plugin-rhea/src/producer.js +1 -5
  20. package/packages/dd-trace/src/appsec/addresses.js +0 -3
  21. package/packages/dd-trace/src/appsec/blocked_templates.js +2 -9
  22. package/packages/dd-trace/src/appsec/blocking.js +1 -1
  23. package/packages/dd-trace/src/appsec/{gateway/channels.js → channels.js} +4 -4
  24. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  25. package/packages/dd-trace/src/appsec/index.js +87 -79
  26. package/packages/dd-trace/src/appsec/recommended.json +448 -121
  27. package/packages/dd-trace/src/appsec/remote_config/apply_states.js +7 -0
  28. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -0
  29. package/packages/dd-trace/src/appsec/remote_config/index.js +29 -10
  30. package/packages/dd-trace/src/appsec/remote_config/manager.js +33 -12
  31. package/packages/dd-trace/src/appsec/reporter.js +27 -58
  32. package/packages/dd-trace/src/appsec/rule_manager.js +160 -32
  33. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -12
  34. package/packages/dd-trace/src/appsec/waf/index.js +75 -0
  35. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +57 -0
  36. package/packages/dd-trace/src/appsec/waf/waf_manager.js +66 -0
  37. package/packages/dd-trace/src/config.js +17 -1
  38. package/packages/dd-trace/src/encode/0.4.js +12 -4
  39. package/packages/dd-trace/src/plugin_manager.js +2 -0
  40. package/packages/dd-trace/src/plugins/client.js +3 -2
  41. package/packages/dd-trace/src/plugins/consumer.js +17 -2
  42. package/packages/dd-trace/src/plugins/inbound.js +7 -0
  43. package/packages/dd-trace/src/plugins/{outgoing.js → outbound.js} +2 -2
  44. package/packages/dd-trace/src/plugins/producer.js +17 -2
  45. package/packages/dd-trace/src/plugins/server.js +2 -2
  46. package/packages/dd-trace/src/plugins/tracing.js +11 -0
  47. package/packages/dd-trace/src/service-naming/index.js +41 -0
  48. package/packages/dd-trace/src/service-naming/schemas/definition.js +28 -0
  49. package/packages/dd-trace/src/service-naming/schemas/index.js +6 -0
  50. package/packages/dd-trace/src/service-naming/schemas/v0.js +66 -0
  51. package/packages/dd-trace/src/service-naming/schemas/v1.js +58 -0
  52. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +0 -137
  53. package/packages/dd-trace/src/appsec/callbacks/index.js +0 -7
  54. package/packages/dd-trace/src/appsec/gateway/als.js +0 -6
  55. package/packages/dd-trace/src/appsec/gateway/engine/engine.js +0 -140
  56. package/packages/dd-trace/src/appsec/gateway/engine/index.js +0 -51
  57. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -42
  58. package/packages/dd-trace/src/plugins/incoming.js +0 -7
@@ -3,8 +3,13 @@
3
3
  const log = require('../log')
4
4
  const RuleManager = require('./rule_manager')
5
5
  const remoteConfig = require('./remote_config')
6
- const { incomingHttpRequestStart, incomingHttpRequestEnd } = require('./gateway/channels')
7
- const Gateway = require('./gateway/engine')
6
+ const {
7
+ incomingHttpRequestStart,
8
+ incomingHttpRequestEnd,
9
+ bodyParser,
10
+ queryParser
11
+ } = require('./channels')
12
+ const waf = require('./waf')
8
13
  const addresses = require('./addresses')
9
14
  const Reporter = require('./reporter')
10
15
  const web = require('../plugins/util/web')
@@ -21,39 +26,25 @@ function enable (_config) {
21
26
  try {
22
27
  setTemplates(_config)
23
28
 
24
- // TODO: inline this function
25
- enableFromRules(_config, _config.appsec.rules)
26
- } catch (err) {
27
- abortEnable(err)
28
- }
29
- }
29
+ RuleManager.applyRules(_config.appsec.rules, _config.appsec)
30
30
 
31
- function enableFromRules (_config, rules) {
32
- RuleManager.applyRules(rules, _config.appsec)
33
- remoteConfig.enableAsmData(_config.appsec)
31
+ remoteConfig.enableWafUpdate(_config.appsec)
34
32
 
35
- Reporter.setRateLimit(_config.appsec.rateLimit)
33
+ Reporter.setRateLimit(_config.appsec.rateLimit)
36
34
 
37
- incomingHttpRequestStart.subscribe(incomingHttpStartTranslator)
38
- incomingHttpRequestEnd.subscribe(incomingHttpEndTranslator)
39
-
40
- // add fields needed for HTTP context reporting
41
- Gateway.manager.addresses.add(addresses.HTTP_INCOMING_HEADERS)
42
- Gateway.manager.addresses.add(addresses.HTTP_INCOMING_ENDPOINT)
43
- Gateway.manager.addresses.add(addresses.HTTP_INCOMING_RESPONSE_HEADERS)
44
- Gateway.manager.addresses.add(addresses.HTTP_INCOMING_REMOTE_IP)
45
-
46
- isEnabled = true
47
- config = _config
48
- }
35
+ incomingHttpRequestStart.subscribe(incomingHttpStartTranslator)
36
+ incomingHttpRequestEnd.subscribe(incomingHttpEndTranslator)
37
+ bodyParser.subscribe(onRequestBodyParsed)
38
+ queryParser.subscribe(onRequestQueryParsed)
49
39
 
50
- function abortEnable (err) {
51
- log.error('Unable to start AppSec')
52
- log.error(err)
40
+ isEnabled = true
41
+ config = _config
42
+ } catch (err) {
43
+ log.error('Unable to start AppSec')
44
+ log.error(err)
53
45
 
54
- // abort AppSec start
55
- RuleManager.clearAllRules()
56
- remoteConfig.disableAsmData()
46
+ disable()
47
+ }
57
48
  }
58
49
 
59
50
  function incomingHttpStartTranslator ({ req, res, abortController }) {
@@ -68,78 +59,92 @@ function incomingHttpStartTranslator ({ req, res, abortController }) {
68
59
  [HTTP_CLIENT_IP]: clientIp
69
60
  })
70
61
 
71
- const store = Gateway.startContext()
72
-
73
- store.set('req', req)
74
- store.set('res', res)
62
+ const requestHeaders = Object.assign({}, req.headers)
63
+ delete requestHeaders.cookie
75
64
 
76
- const context = store.get('context')
65
+ const payload = {
66
+ [addresses.HTTP_INCOMING_URL]: req.url,
67
+ [addresses.HTTP_INCOMING_HEADERS]: requestHeaders,
68
+ [addresses.HTTP_INCOMING_METHOD]: req.method
69
+ }
77
70
 
78
71
  if (clientIp) {
79
- const results = Gateway.propagate({
80
- [addresses.HTTP_CLIENT_IP]: clientIp
81
- }, context)
82
-
83
- if (!results || !abortController) return
84
-
85
- for (const entry of results) {
86
- if (entry && entry.includes('block')) {
87
- block(req, res, rootSpan, abortController)
88
- break
89
- }
90
- }
72
+ payload[addresses.HTTP_CLIENT_IP] = clientIp
91
73
  }
92
- }
93
74
 
94
- function incomingHttpEndTranslator (data) {
95
- const context = Gateway.getContext()
96
- if (!context) return
75
+ const actions = waf.run(payload, req)
97
76
 
98
- const requestHeaders = Object.assign({}, data.req.headers)
99
- delete requestHeaders.cookie
77
+ handleResults(actions, req, res, rootSpan, abortController)
78
+ }
100
79
 
80
+ function incomingHttpEndTranslator ({ req, res }) {
101
81
  // TODO: this doesn't support headers sent with res.writeHead()
102
- const responseHeaders = Object.assign({}, data.res.getHeaders())
82
+ const responseHeaders = Object.assign({}, res.getHeaders())
103
83
  delete responseHeaders['set-cookie']
104
84
 
105
85
  const payload = {
106
- [addresses.HTTP_INCOMING_URL]: data.req.url,
107
- [addresses.HTTP_INCOMING_HEADERS]: requestHeaders,
108
- [addresses.HTTP_INCOMING_METHOD]: data.req.method,
109
- [addresses.HTTP_INCOMING_REMOTE_IP]: data.req.socket.remoteAddress,
110
- [addresses.HTTP_INCOMING_REMOTE_PORT]: data.req.socket.remotePort,
111
- [addresses.HTTP_INCOMING_RESPONSE_CODE]: data.res.statusCode,
86
+ [addresses.HTTP_INCOMING_RESPONSE_CODE]: res.statusCode,
112
87
  [addresses.HTTP_INCOMING_RESPONSE_HEADERS]: responseHeaders
113
88
  }
114
89
 
115
- // TODO: temporary express instrumentation, will use express plugin later
116
- if (data.req.body !== undefined && data.req.body !== null) {
117
- payload[addresses.HTTP_INCOMING_BODY] = data.req.body
118
- }
119
-
120
- if (data.req.query && typeof data.req.query === 'object') {
121
- payload[addresses.HTTP_INCOMING_QUERY] = data.req.query
90
+ // we need to keep this to support other body parsers
91
+ // TODO: no need to analyze it if it was already done by the body-parser hook
92
+ if (req.body !== undefined && req.body !== null) {
93
+ payload[addresses.HTTP_INCOMING_BODY] = req.body
122
94
  }
123
95
 
124
- if (data.req.route && typeof data.req.route.path === 'string') {
125
- payload[addresses.HTTP_INCOMING_ENDPOINT] = data.req.route.path
126
- }
127
-
128
- if (data.req.params && typeof data.req.params === 'object') {
129
- payload[addresses.HTTP_INCOMING_PARAMS] = data.req.params
96
+ // TODO: temporary express instrumentation, will use express plugin later
97
+ if (req.params && typeof req.params === 'object') {
98
+ payload[addresses.HTTP_INCOMING_PARAMS] = req.params
130
99
  }
131
100
 
132
- if (data.req.cookies && typeof data.req.cookies === 'object') {
101
+ if (req.cookies && typeof req.cookies === 'object') {
133
102
  payload[addresses.HTTP_INCOMING_COOKIES] = {}
134
103
 
135
- for (const k of Object.keys(data.req.cookies)) {
136
- payload[addresses.HTTP_INCOMING_COOKIES][k] = [data.req.cookies[k]]
104
+ for (const k of Object.keys(req.cookies)) {
105
+ payload[addresses.HTTP_INCOMING_COOKIES][k] = [req.cookies[k]]
137
106
  }
138
107
  }
139
108
 
140
- Gateway.propagate(payload, context)
109
+ waf.run(payload, req)
110
+
111
+ waf.disposeContext(req)
112
+
113
+ Reporter.finishRequest(req, res)
114
+ }
115
+
116
+ function onRequestBodyParsed ({ req, res, abortController }) {
117
+ const rootSpan = web.root(req)
118
+ if (!rootSpan) return
119
+
120
+ if (req.body === undefined || req.body === null) return
121
+
122
+ const results = waf.run({
123
+ [addresses.HTTP_INCOMING_BODY]: req.body
124
+ }, req)
141
125
 
142
- Reporter.finishRequest(data.req, context)
126
+ handleResults(results, req, res, rootSpan, abortController)
127
+ }
128
+
129
+ function onRequestQueryParsed ({ req, res, abortController }) {
130
+ const rootSpan = web.root(req)
131
+ if (!rootSpan) return
132
+
133
+ if (!req.query || typeof req.query !== 'object') return
134
+
135
+ const results = waf.run({
136
+ [addresses.HTTP_INCOMING_QUERY]: req.query
137
+ }, req)
138
+
139
+ handleResults(results, req, res, rootSpan, abortController)
140
+ }
141
+
142
+ function handleResults (actions, req, res, rootSpan, abortController) {
143
+ if (!actions || !req || !res || !rootSpan || !abortController) return
144
+
145
+ if (actions.includes('block')) {
146
+ block(req, res, rootSpan, abortController)
147
+ }
143
148
  }
144
149
 
145
150
  function disable () {
@@ -147,11 +152,14 @@ function disable () {
147
152
  config = null
148
153
 
149
154
  RuleManager.clearAllRules()
150
- remoteConfig.disableAsmData()
155
+
156
+ remoteConfig.disableWafUpdate()
151
157
 
152
158
  // Channel#unsubscribe() is undefined for non active channels
153
159
  if (incomingHttpRequestStart.hasSubscribers) incomingHttpRequestStart.unsubscribe(incomingHttpStartTranslator)
154
160
  if (incomingHttpRequestEnd.hasSubscribers) incomingHttpRequestEnd.unsubscribe(incomingHttpEndTranslator)
161
+ if (bodyParser.hasSubscribers) bodyParser.unsubscribe(onRequestBodyParsed)
162
+ if (queryParser.hasSubscribers) queryParser.unsubscribe(onRequestQueryParsed)
155
163
  }
156
164
 
157
165
  module.exports = {